Created
June 7, 2010 20:05
-
-
Save rwaldron/429112 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
header("Content-Type: text/event-stream\n\n"); | |
echo 'data: ' . json_encode( | |
array( | |
0 => array( | |
'time' => time(), | |
'message' => 'Some kind of foo' | |
), | |
1 => array( | |
'time' => time(), | |
'message' => 'Some kind of quux' | |
) | |
) | |
) . "\n"; | |
?> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="firefox-event-source.js"></script> | |
<script> | |
console.log(EventSource); | |
var eventSource = new EventSource('event.php'); | |
console.group('eventSource') | |
console.log(eventSource); | |
console.log(eventSource.constructor); | |
console.groupEnd(); | |
eventSource.addEventListener('open', function (event) { | |
console.log('OPEN!'); | |
}, false); | |
eventSource.addEventListener('message', function (event) { | |
var message = JSON.parse(event.data); | |
console.log(message); | |
}, false); | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;(function (w) { | |
if ( !w['EventSource'] ) { | |
// parseUri 1.2.2 | |
// (c) Steven Levithan <stevenlevithan.com> | |
// MIT License | |
var parseUri = function(str) { | |
var o = { | |
key: ['source','protocol','authority','userInfo','user','password','host','port','relative','path','directory','file','query','anchor'], | |
q: { | |
name: 'queryKey', | |
parser: /(?:^|&)([^&=]*)=?([^&]*)/g | |
}, | |
parser: { | |
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ | |
} | |
}, | |
m = o.parser.strict.exec(str), | |
uri = {}, | |
i = 14; | |
while (i--) uri[o.key[i]] = m[i] || ''; | |
uri[o.q.name] = {}; | |
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { | |
if ($1) uri[o.q.name][$1] = $2; | |
}); | |
return uri; | |
}; | |
// EventSource implementation | |
function EventSource( resource ) { | |
var that = (this === window) ? {} : this, | |
retry = 1000, offset = 0, | |
boundary = "\n", queue = [], origin = '', | |
lastEventId = null, xhr = null, source = null, matches = null, resourceLocation = null; | |
that.toString = function () { return '[object EventSource]' }; | |
// EventSource listener | |
that.addEventListener = function (type, listener, useCapture) { | |
document.addEventListener(type, listener, useCapture); | |
}; | |
// EventSource dispatcher | |
that.dispatchEvent = function (event) { | |
document.dispatchEvent(event); | |
}; | |
resourceLocation = parseUri(resource); | |
// same origin policy | |
if ( resource.match(/http/) && resource.match(/http/).length ) { | |
if ( resourceLocation.host !== location.host ) { | |
throw DOMException;//"SECURITY_ERR: DOM Exception"; | |
} | |
} | |
that.URL = resourceLocation.source; | |
var openConnectionXHR = function() { | |
xhr = new XMLHttpRequest(); | |
xhr.open('GET', that.URL, true); | |
// FIRE OPEN EVENT | |
var openEvent = document.createEvent('UIEvents'); | |
openEvent.initEvent('open', true, true); | |
openEvent.origin = document.domain; | |
openEvent.source = null; | |
that.dispatchEvent(openEvent); | |
if ( lastEventId ) { | |
xhr.setRequestHeader('Last-Event-ID', lastEventId); | |
} | |
xhr.onreadystatechange = function() { | |
switch (xhr.readyState) { | |
case 4: // disconnect case | |
pseudoDispatchEvent(); | |
reOpenConnectionXHR(); | |
break; | |
case 3: // new data | |
processMessageFromXHR(); | |
break; | |
} | |
} | |
xhr.send(null); | |
} | |
var reOpenConnectionXHR = function() { | |
xhr = null; | |
offset = 0; | |
setTimeout(openConnectionXHR, 1000); | |
} | |
var processMessageFromXHR = function() { | |
var stream = xhr.responseText.split(boundary); | |
// Abandon if empty | |
if ( stream.length < offset ) { | |
return; | |
} | |
for ( var i = 0; i < stream.length; i++ ) { | |
queue.push(stream[i]); | |
} | |
pseudoDispatchEvent(); | |
} | |
var pseudoDispatchEvent = function() { | |
var data = '', name = 'message'; | |
queue.reverse(); | |
while (queue.length > 0) { | |
line = queue.pop(); | |
var dataIndex = line.indexOf(':'), field = null, value = ''; | |
if (dataIndex == -1) { | |
field = line; | |
value = ''; | |
} | |
else if (dataIndex == 0) { | |
// Ignore Comment lines | |
continue; | |
} | |
else { | |
field = line.slice(0, dataIndex) | |
value = line.slice(dataIndex+1) | |
} | |
if (field == 'event') { | |
name = value; | |
} | |
if (field == 'id') { | |
lastEventId = value; | |
} | |
if (field == 'retry') { | |
value = parseInt(value); | |
if (!isNaN(value)) { | |
retry = value; | |
} | |
} | |
if (field == 'data') { | |
if (data.length > 0) { | |
data += "\n"; | |
} | |
data += value; | |
} | |
} | |
var fireEvent = document.createEvent('UIEvents'); | |
// MessageEvent causes "setting a property that has only a getter" Errors | |
if ( data.length > 0 ) { | |
fireEvent.initEvent(name, true, true); | |
fireEvent.lastEventId = lastEventId; | |
fireEvent.data = data.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); | |
fireEvent.origin = document.domain; | |
fireEvent.source = null; | |
that.dispatchEvent(fireEvent); | |
} | |
} | |
// INIT EVENT SOURCE CONNECTION | |
openConnectionXHR(); | |
}; | |
window['EventSource'] = EventSource; | |
} | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment