From 5743baf4ed2d73bdcd44f87562dfefbca6926369 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 14 Jun 2011 11:37:47 -0400 Subject: [PATCH 1/4] Settable retry time in MS. Fixes #5 --- jquery.eventsource.js | 75 +++++++++++-------- test-event-sources/event-source-2.php | 38 +++++----- test-event-sources/event-source-retry.php | 20 ++++++ test/jquery.eventsource.unit.js | 88 ++++++++++++++++------- 4 files changed, 145 insertions(+), 76 deletions(-) create mode 100644 test-event-sources/event-source-retry.php diff --git a/jquery.eventsource.js b/jquery.eventsource.js index 0a92dd0..fe188f5 100644 --- a/jquery.eventsource.js +++ b/jquery.eventsource.js @@ -26,6 +26,7 @@ stream: {}, lastEventId: 0, isHostApi: false, + retry: 500, history: {}, options: {} }, @@ -71,11 +72,11 @@ var label = options.label; stream.cache[ label ].stream.addEventListener("open", function(event) { - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].options.open.call(this, event); + stream.cache[ label ].options.open.call(this, event); } }, false); @@ -83,40 +84,40 @@ var streamData = []; - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { streamData[ streamData.length ] = jQuery.parseJSON( event.data ); this.label = label; - stream.cache[label].lastEventId = +event.lastEventId; - stream.cache[label].history[stream.cache[label].lastEventId] = streamData; - stream.cache[label].options.message.call(this, streamData[0] ? streamData[0] : null, { + stream.cache[ label ].lastEventId = +event.lastEventId; + stream.cache[ label ].history[stream.cache[ label ].lastEventId] = streamData; + stream.cache[ label ].options.message.call(this, streamData[0] ? streamData[0] : null, { data: streamData, - lastEventId: stream.cache[label].lastEventId + lastEventId: stream.cache[ label ].lastEventId }, event); // TODO: Add custom event triggering } }, false); - return stream.cache[label].stream; + return stream.cache[ label ].stream; }, // open fallback event source openPollingSource: function( options ) { - var label = options.label, + var label = options.label, source; - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { source = jQuery.ajax({ type: "GET", url: options.url, data: options.data, beforeSend: function() { - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].options.open.call( this ); + stream.cache[ label ].options.open.call( this ); } }, success: function( data ) { @@ -124,46 +125,58 @@ var tempdata, label = options.label, parsedData = [], - streamData = jQuery.map( data.split("\n"), function(sdata, i) { + streamData = jQuery.map( data.split("\n\n"), function(sdata, i) { return !!sdata && sdata; - }), - idx = 0, length = streamData.length; + }), + idx = 0, length = streamData.length, + rretryprefix = /retry/, + retries; - if ( jQuery.isArray(streamData) ) { + if ( jQuery.isArray( streamData ) ) { for ( ; idx < length; idx++ ) { - if ( streamData[idx] ) { - tempdata = streamData[idx].split("data: ")[ 1 ]; + if ( streamData[ idx ] ) { - // Convert `dataType` here - if ( options.dataType === "json" ) { - tempdata = jQuery.parseJSON( tempdata ); - } + if ( rretryprefix.test( streamData[ idx ] ) && + (retries = streamData[ idx ].split("retry: ")).length ) { + + if ( retries.length === 2 && !retries[ 0 ] ) { + + stream.cache[ label ].retry = stream.cache[ label ].options.retry = +retries[ 1 ]; + } + + } else { + tempdata = streamData[ idx ].split("data: ")[ 1 ]; - parsedData[ parsedData.length ] = tempdata; + // Convert `dataType` here + if ( options.dataType === "json" ) { + tempdata = jQuery.parseJSON( tempdata ); + } + + parsedData[ parsedData.length ] = tempdata; + } } } } - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].lastEventId++; - stream.cache[label].history[stream.cache[label].lastEventId] = parsedData; - stream.cache[label].options.message.call(this, parsedData[0] ? parsedData[0] : null, { + stream.cache[ label ].lastEventId++; + stream.cache[ label ].history[ stream.cache[ label ].lastEventId ] = parsedData; + stream.cache[ label ].options.message.call(this, parsedData[0] ? parsedData[0] : null, { data: parsedData, - lastEventId: stream.cache[label].lastEventId + lastEventId: stream.cache[ label ].lastEventId }); - setTimeout( function() { pluginFns._private.openPollingSource.call( this, options ); }, - // matches speed of host api EventSource - 500 + // Use server sent retry time if exists or default retry time if not + ( stream.cache[ label ] && stream.cache[ label ].retry ) || 500 ); } }, diff --git a/test-event-sources/event-source-2.php b/test-event-sources/event-source-2.php index 66e7121..0d71cb1 100644 --- a/test-event-sources/event-source-2.php +++ b/test-event-sources/event-source-2.php @@ -1,19 +1,19 @@ - array( - 'time' => time(), - 'message' => 'Some kind of foo' - ), - 1 => array( - 'time' => time(), - 'message' => 'Some kind of quux' - ) - ) - ) . "\n"; - -?> \ No newline at end of file + array( + 'time' => time(), + 'message' => 'Some kind of foo' + ), + 1 => array( + 'time' => time(), + 'message' => 'Some kind of quux' + ) + ) + ) . "\n"; + +?> diff --git a/test-event-sources/event-source-retry.php b/test-event-sources/event-source-retry.php new file mode 100644 index 0000000..5a44f36 --- /dev/null +++ b/test-event-sources/event-source-retry.php @@ -0,0 +1,20 @@ + array( + 'time' => time(), + 'message' => 'Some kind of foo' + ), + 1 => array( + 'time' => time(), + 'message' => 'Some kind of quux' + ) + ) + ) . "\n"; + + +?> diff --git a/test/jquery.eventsource.unit.js b/test/jquery.eventsource.unit.js index a205ad2..5df148a 100644 --- a/test/jquery.eventsource.unit.js +++ b/test/jquery.eventsource.unit.js @@ -13,26 +13,24 @@ $(function() { var params = location.search.slice( 1 ).split( "&" ), pairs = {}; - params.forEach(function(param) { + $.each( params, function(idx, param) { var tmp = param.split("="); pairs[ tmp[0] ] = tmp[1]; }); - //document.querySelectorAll("iframe")[0].style.display = "none"; - if ( pairs.nospecit ) { $("iframe").hide(); } }); -test("jQuery.eventsource is a function", function() { +test("is a function", function() { expect(7); - ok( jQuery.eventsource, "jQuery.eventsource exists" ); + ok( jQuery.eventsource, "exists" ); equal( typeof jQuery.eventsource, "function", "jQuery.eventsource() is a Function" ); ok( jQuery.eventsource.streams, "jQuery.eventsource.streams exists" ); @@ -45,7 +43,7 @@ test("jQuery.eventsource is a function", function() { }); -test("jQuery.eventsource callbacks", function() { +test("callbacks", function() { var expects = 12, count = 0; @@ -64,52 +62,52 @@ test("jQuery.eventsource callbacks", function() { } stop(); - // PLAIN TEXT EXAMPLE - NO CONTENT TYPE GIVEN + // PLAIN TEXT EXAMPLE NO CONTENT TYPE GIVEN jQuery.eventsource({ label: "text-event-source", url: "../test-event-sources/event-source-1.php", open: function() { - okPlus( true, "#1 jQuery.eventsource fires onopen callback" ); + okPlus( true, "#1 fires onopen callback" ); }, message: function(data) { - okPlus( true, "#1 jQuery.eventsource fires onmessage callback" ); + okPlus( true, "#1 fires onmessage callback" ); - okPlus( data, "#1 jQuery.eventsource returns data"); + okPlus( data, "#1 returns data"); okPlus( typeof jQuery.eventsource("close", "text-event-source") === "object", 'jQuery.eventsource("close", "text-event-source") must return an object' ); } }); - // PLAIN TEXT EXAMPLE - HAS CONTENT TYPE + // PLAIN TEXT EXAMPLE HAS CONTENT TYPE jQuery.eventsource({ label: "text-event-source-ct", url: "../test-event-sources/event-source-1.php", dataType: "text", open: function() { - okPlus( true, "#2 jQuery.eventsource fires onopen callback" ); + okPlus( true, "#2 fires onopen callback" ); }, message: function(data) { - okPlus( true, "#2 jQuery.eventsource fires onmessage callback" ); - okPlus( data, "#2 jQuery.eventsource returns data"); + okPlus( true, "#2 fires onmessage callback" ); + okPlus( data, "#2 returns data"); okPlus( typeof jQuery.eventsource("close", "text-event-source-ct") === "object", 'jQuery.eventsource("close", "text-event-source-ct") must return an object' ); } }); - // PLAIN TEXT EXAMPLE - HAS CONTENT TYPE + // PLAIN TEXT EXAMPLE HAS CONTENT TYPE jQuery.eventsource({ label: "json-event-source", url: "../test-event-sources/event-source-2.php", dataType: "json", open: function() { - okPlus( true, "#3 jQuery.eventsource fires onopen callback" ); + okPlus( true, "#3 fires onopen callback" ); }, message: function(data) { - okPlus( true, "#3 jQuery.eventsource fires onmessage callback" ); - okPlus( data, "#3 jQuery.eventsource returns data"); + okPlus( true, "#3 fires onmessage callback" ); + okPlus( data, "#3 returns data"); okPlus( typeof jQuery.eventsource("close", "json-event-source") === "object", 'jQuery.eventsource("close", "json-event-source") must return an object' ); } @@ -117,7 +115,7 @@ test("jQuery.eventsource callbacks", function() { }); -test("jQuery.eventsource open/close", function() { +test("open/close", function() { var expects = 5, count = 0; @@ -136,15 +134,15 @@ test("jQuery.eventsource open/close", function() { url: "../test-event-sources/event-source-2.php", dataType: "json", open: function() { - ok( true, "jQuery.eventsource fires onopen callback" ); + ok( true, "fires onopen callback" ); plus(); }, message: function(data) { - ok( true, "jQuery.eventsource fires onmessage callback" ); + ok( true, "fires onmessage callback" ); plus(); - ok( data, "jQuery.eventsource returns data"); + ok( data, "returns data"); plus(); equal( typeof jQuery.eventsource.close("json-event-source-stream"), "object", 'jQuery.eventsource.close("json-event-source-stream") must return an object' ); @@ -157,7 +155,7 @@ test("jQuery.eventsource open/close", function() { }); -test("jQuery.eventsource - multiple concurrent sources - scope tests", function() { +test("multiple concurrent sources scope tests", function() { var expects = 12, count = 0, down = 3; @@ -200,7 +198,7 @@ test("jQuery.eventsource - multiple concurrent sources - scope tests", function( }); }); -test("jQuery.eventsource - breakage tests", function() { +test("breakage tests", function() { var expects = 7, count = 0; @@ -294,7 +292,7 @@ test("jQuery.eventsource - breakage tests", function() { } }); -test("jQuery.eventsource streams object", function() { +test("streams object", function() { var expects = 13, count = 0; @@ -370,7 +368,45 @@ test("jQuery.eventsource streams object", function() { }); -test("jQuery.eventsource streams Are Closed", function() { +test("settable retry time in ms", function() { + + var expects = 2, + count = 0, + stream; + + expect( expects ); + + function plus() { + if ( ++count === expects ) { + jQuery.eventsource.close(); + start(); + } + } + + stop(); + + // labeled stream + jQuery.eventsource({ + label: "retry-stream", + url: "../test-event-sources/event-source-retry.php", + dataType: "json", + message: function() { + + var stream = jQuery.eventsource.streams("retry-stream"), + streamretry = jQuery.eventsource.streams("retry-stream").retry; + + if ( !stream.isHostApi ) { + equal( streamretry, 1000, "jQuery.eventsource.streams('retry-stream') has a retry time of 1000ms" ); + } else { + ok( true, "retry time is managed by the implementation when provided from a server message" ); + } + plus(); + } + }); +}); + + +test("streams Are Closed", function() { var expects = 2, count = 0; From cf2cd1caca6ea3ad9c1e896fa44e60f129a37239 Mon Sep 17 00:00:00 2001 From: Or Cohen Date: Tue, 29 May 2012 19:36:40 +0300 Subject: [PATCH 2/4] Using close() on the stream when host API is used --- jquery.eventsource.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jquery.eventsource.js b/jquery.eventsource.js index fe188f5..7599b77 100644 --- a/jquery.eventsource.js +++ b/jquery.eventsource.js @@ -41,6 +41,12 @@ var tmp = {}; if ( !label || label === "*" ) { + for ( var prop in stream.cache ) { + if ( stream.cache[ prop ].isHostApi ) { + stream.cache[ prop ].stream.close(); + } + } + stream.cache = {}; return stream.cache; @@ -49,6 +55,10 @@ for ( var prop in stream.cache ) { if ( label !== prop ) { tmp[ prop ] = stream.cache[ prop ]; + } else { + if ( stream.cache[ prop ].isHostApi ) { + stream.cache[ prop ].stream.close(); + } } } From 45f3e8aa99314ccf0405efd51725ff6e0aae8026 Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Tue, 29 May 2012 13:03:13 -0400 Subject: [PATCH 3/4] Update stuff that I didn't commit many months ago Signed-off-by: Rick Waldron --- test/index.html | 13 ++++++------- test/specit.html | 18 +++++++++--------- test/test.php | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 test/test.php diff --git a/test/index.html b/test/index.html index c567c56..7cac823 100644 --- a/test/index.html +++ b/test/index.html @@ -1,12 +1,11 @@ - + jquery.eventsource.unit - + - - + + @@ -17,7 +16,7 @@

    - + - + \ No newline at end of file diff --git a/test/specit.html b/test/specit.html index 5de5621..347ae89 100644 --- a/test/specit.html +++ b/test/specit.html @@ -1,27 +1,27 @@ - jquery.eventsource.specit - + - - - + + + - + diff --git a/test/test.php b/test/test.php new file mode 100644 index 0000000..3512aac --- /dev/null +++ b/test/test.php @@ -0,0 +1,45 @@ + + + + + + jQuery.eventsource.js + + + + + + + Date: Tue, 29 May 2012 13:26:03 -0400 Subject: [PATCH 4/4] Update latest qunit Signed-off-by: Rick Waldron --- jquery.eventsource.js | 26 +++++++------- test/index.html | 12 +++---- test/jquery.eventsource.unit.js | 64 ++++++++++++++++----------------- test/specit.html | 14 ++++---- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/jquery.eventsource.js b/jquery.eventsource.js index 7599b77..848d51f 100644 --- a/jquery.eventsource.js +++ b/jquery.eventsource.js @@ -1,6 +1,6 @@ /*! * jQuery.EventSource (jQuery.eventsource) - * + * * Copyright (c) 2011 Rick Waldron * Dual licensed under the MIT and GPL licenses. */ @@ -12,7 +12,7 @@ }); var stream = { - + defaults: { // Stream identity label: null, @@ -23,7 +23,7 @@ message: jQuery.noop }, setup: { - stream: {}, + stream: {}, lastEventId: 0, isHostApi: false, retry: 500, @@ -65,7 +65,7 @@ stream.cache = tmp; return stream.cache; - }, + }, streams: function( label ) { if ( !label || label === "*" ) { @@ -77,7 +77,7 @@ }, _private: { - // Open a host api event source + // Open a host api event source openEventSource: function( options ) { var label = options.label; @@ -91,7 +91,7 @@ }, false); stream.cache[label].stream.addEventListener("message", function(event) { - + var streamData = []; if ( stream.cache[ label ] ) { @@ -107,12 +107,12 @@ lastEventId: stream.cache[ label ].lastEventId }, event); - // TODO: Add custom event triggering + // TODO: Add custom event triggering } }, false); return stream.cache[ label ].stream; - }, + }, // open fallback event source openPollingSource: function( options ) { var label = options.label, @@ -139,7 +139,7 @@ return !!sdata && sdata; }), idx = 0, length = streamData.length, - rretryprefix = /retry/, + rretryprefix = /retry/, retries; if ( jQuery.isArray( streamData ) ) { @@ -148,7 +148,7 @@ if ( streamData[ idx ] ) { - if ( rretryprefix.test( streamData[ idx ] ) && + if ( rretryprefix.test( streamData[ idx ] ) && (retries = streamData[ idx ].split("retry: ")).length ) { if ( retries.length === 2 && !retries[ 0 ] ) { @@ -207,7 +207,7 @@ // Plugin sub function if ( options && !jQuery.isPlainObject( options ) && pluginFns.public[ options ] ) { // If no label was passed, send message to all streams - return pluginFns.public[ options ]( + return pluginFns.public[ options ]( arguments[1] ? arguments[1] : "*" @@ -215,7 +215,7 @@ } // If params were passed in as an object, normalize to a query string - options.data = options.data && jQuery.isPlainObject( options.data ) ? + options.data = options.data && jQuery.isPlainObject( options.data ) ? jQuery.param( options.data ) : options.data; @@ -240,7 +240,7 @@ }; - // Determine and declare `event stream` source, + // Determine and declare `event stream` source, // whether will be host api or XHR fallback streamType = !isHostApi ? // If not host api, open a polling fallback diff --git a/test/index.html b/test/index.html index 41b7f08..b5ff890 100644 --- a/test/index.html +++ b/test/index.html @@ -3,12 +3,12 @@ jquery.eventsource.unit - - + + - - + + @@ -23,7 +23,7 @@

    - + - + diff --git a/test/jquery.eventsource.unit.js b/test/jquery.eventsource.unit.js index 5df148a..e39eb38 100644 --- a/test/jquery.eventsource.unit.js +++ b/test/jquery.eventsource.unit.js @@ -10,7 +10,7 @@ function sizeOf(obj) { $(function() { - var params = location.search.slice( 1 ).split( "&" ), + var params = location.search.slice( 1 ).split( "&" ), pairs = {}; $.each( params, function(idx, param) { @@ -29,10 +29,10 @@ $(function() { test("is a function", function() { expect(7); - + ok( jQuery.eventsource, "exists" ); equal( typeof jQuery.eventsource, "function", "jQuery.eventsource() is a Function" ); - + ok( jQuery.eventsource.streams, "jQuery.eventsource.streams exists" ); equal( typeof jQuery.eventsource.streams, "function", "jQuery.eventsource.streams() is a Function" ); @@ -42,21 +42,21 @@ test("is a function", function() { equal( sizeOf( jQuery.eventsource.streams() ), 0, "There are no streams"); }); - -test("callbacks", function() { - - var expects = 12, + +test("callbacks", function() { + + var expects = 12, count = 0; expect( expects ); - - function plus() { + + function plus() { if ( ++count === expects ) { - start(); + start(); } } - function okPlus() { + function okPlus() { ok.apply(null, arguments); plus(); } @@ -71,10 +71,10 @@ test("callbacks", function() { }, message: function(data) { okPlus( true, "#1 fires onmessage callback" ); - + okPlus( data, "#1 returns data"); - - okPlus( typeof jQuery.eventsource("close", "text-event-source") === "object", 'jQuery.eventsource("close", "text-event-source") must return an object' ); + + okPlus( typeof jQuery.eventsource("close", "text-event-source") === "object", 'jQuery.eventsource("close", "text-event-source") must return an object' ); } }); @@ -90,11 +90,11 @@ test("callbacks", function() { okPlus( true, "#2 fires onmessage callback" ); okPlus( data, "#2 returns data"); - okPlus( typeof jQuery.eventsource("close", "text-event-source-ct") === "object", 'jQuery.eventsource("close", "text-event-source-ct") must return an object' ); + okPlus( typeof jQuery.eventsource("close", "text-event-source-ct") === "object", 'jQuery.eventsource("close", "text-event-source-ct") must return an object' ); } }); - + // PLAIN TEXT EXAMPLE HAS CONTENT TYPE jQuery.eventsource({ @@ -108,7 +108,7 @@ test("callbacks", function() { okPlus( true, "#3 fires onmessage callback" ); okPlus( data, "#3 returns data"); - okPlus( typeof jQuery.eventsource("close", "json-event-source") === "object", 'jQuery.eventsource("close", "json-event-source") must return an object' ); + okPlus( typeof jQuery.eventsource("close", "json-event-source") === "object", 'jQuery.eventsource("close", "json-event-source") must return an object' ); } }); @@ -156,15 +156,15 @@ test("open/close", function() { test("multiple concurrent sources scope tests", function() { - var expects = 12, - count = 0, + var expects = 12, + count = 0, down = 3; expect( expects ); - function plus() { + function plus() { if ( ++count === expects ) { - start(); + start(); } } @@ -200,18 +200,18 @@ test("multiple concurrent sources scope tests", function() { test("breakage tests", function() { - var expects = 7, + var expects = 7, count = 0; expect( expects ); - - function plus() { + + function plus() { if ( ++count === expects ) { start(); } } - function okPlus() { + function okPlus() { ok.apply(null, arguments); plus(); } @@ -292,7 +292,7 @@ test("breakage tests", function() { } }); -test("streams object", function() { +test("streams object", function() { var expects = 13, count = 0; @@ -408,24 +408,24 @@ test("settable retry time in ms", function() { test("streams Are Closed", function() { - var expects = 2, + var expects = 2, count = 0; expect( expects ); - - function plus() { + + function plus() { if ( ++count === expects ) { - start(); + start(); } } stop(); jQuery.eventsource.close(); - + equal(sizeOf(jQuery.eventsource.streams()), 0, "there are 0 active streams"); plus(); - ok( typeof jQuery.eventsource.streams() === "object", 'jQuery.eventsource.streams() must return an object' ); + ok( typeof jQuery.eventsource.streams() === "object", 'jQuery.eventsource.streams() must return an object' ); plus(); }); diff --git a/test/specit.html b/test/specit.html index 9214060..fef7eec 100644 --- a/test/specit.html +++ b/test/specit.html @@ -3,27 +3,27 @@ jquery.eventsource.specit - - + + - + - +