Comparing version 0.5.0 to 0.6.0
@@ -52,3 +52,3 @@ /* | ||
// this is a completion. | ||
if (payload[0] === '\n\n\n\n') { | ||
if (payload[0] === 'end') { | ||
socket.removeAllListeners(data.streamId); | ||
@@ -68,4 +68,8 @@ events.onEnd(); | ||
// this is a data payload. | ||
} else { | ||
events.onData.apply(null, payload); | ||
} else if (payload[0] === 'data') { | ||
try { | ||
events.onData.call(events, JSON.parse(payload[1])); | ||
} catch (err) { | ||
events.onData.call(events, payload[1]); | ||
} | ||
@@ -72,0 +76,0 @@ } |
@@ -16,4 +16,4 @@ // 1. setup a basic express server | ||
inter = setInterval(function() { | ||
res.write("foobar:", counter, {foo: 'bar'}); | ||
if (counter == 20) { res.error(new Error('send a non-fatal error;')); } | ||
res.write(["foobar:", counter, {foo: 'bar'}], 'json'); | ||
if (counter == 20) { res.error(new Error('send a non-fatal error')); } | ||
if (--counter == 0) { | ||
@@ -20,0 +20,0 @@ clearInterval(inter); |
{ | ||
"name" : "streamable", | ||
"version" : "0.5.0", | ||
"version" : "0.6.0", | ||
"description" : "Super simple streaming responses for Connect/Express.", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -9,2 +9,4 @@ Have you ever wanted to utilize `Content-Encoding: chunked` in XHR, without waiting for the entire request to complete? With Streamable, you can! | ||
Streamable is designed to feel transparent. If you access a streamable REST endpoint without the Streamable client, native chunked encoding will happen in its place. You can also explicitly disable Streamable for a particular request by sending the `x-streamable-bypass` request header. If streamable is bypassed, each message will be delimeted with `\r\n`. This is also configurable by provided the `x-streamable-delimiter` request header, providing the value you'd like to use instead. | ||
## Getting Started | ||
@@ -51,10 +53,10 @@ | ||
```js | ||
res.fatal('this will fire the onError event and close the response stream'); | ||
res.error('this will fire the onError event and keep going'); | ||
res.fatal(new Error('this will fire the onError event and close the response stream')); | ||
res.error(new Error('this will fire the onError event and keep going')); | ||
``` | ||
the write API also supports variable arguments, you can expect them as arguments to the `onData` event handler on the client side. | ||
the write API also supports `json` as a valid encoding, for convenience. | ||
```js | ||
res.write("variable", ["args"], {are: "supported"}); | ||
res.write(["here", "is", {some, "data"}], 'json'); | ||
``` | ||
@@ -69,3 +71,3 @@ | ||
Streamable.get("/myAPI", { | ||
onData : function() { console.log('data:' , arguments); }, | ||
onData : function(data) { console.log('data:' , data); }, | ||
onError : function(e) { console.log('error:', e); }, | ||
@@ -72,0 +74,0 @@ onEnd : function() { console.log('end'); } |
@@ -33,4 +33,4 @@ var randBytes = require('crypto').randomBytes; | ||
write: function() { | ||
_write(Array.prototype.slice.call(arguments, 0)); | ||
write: function(data) { | ||
_write(['data', data]); | ||
}, | ||
@@ -46,7 +46,5 @@ | ||
end: function() { | ||
if (arguments.length != 0) { | ||
_write(Array.prototype.slice.call(arguments, 0)); | ||
} | ||
_write(['\n\n\n\n']); | ||
end: function(data) { | ||
if (data) { _write(['data', data]); } | ||
_write(['end']); | ||
} | ||
@@ -83,2 +81,15 @@ | ||
/* encode a value to a string-oriented representation. | ||
we currently do not support binary streaming. */ | ||
function encodeValue(value, encoding) { | ||
if (encoding === 'json') { | ||
return JSON.stringify(value); | ||
} else if (encoding === 'binary') { | ||
throw new TypeError("Binary encoding not supported. Patches accepted!"); | ||
} else { | ||
return String(value); | ||
} | ||
} | ||
exports.streamable = function(io) { | ||
@@ -106,6 +117,21 @@ | ||
// relies on chunked encoding primitives (write/end, etc.) | ||
if (req.header('x-streamable-bypass')) { | ||
if (req.header('x-streamable-bypass') || !req.query.sid) { | ||
// configurable message delimeter for non-socket streaming. | ||
var reqDelim = (req.header('x-streamable-delimiter') || '\r\n'); | ||
// add fallback support for the Streamable API here. | ||
res.error = function(e) { res.write(e.toString()); } | ||
res.fatal = function(e) { res.end(e.toString()); } | ||
var origWrite = res.write; | ||
// because streamable's API allows you to send variable | ||
// arguments with each write, we must concat the writes | ||
// as string values, delimited by commas, followed by a | ||
// \n to represent the end of that "atomic" write of values. | ||
res.write = function(value, encoding) { | ||
origWrite.call(res, encodeValue(value, encoding)+reqDelim); | ||
}; | ||
res.error = function(err) { res.write.call(res, String(err)); }; | ||
res.fatal = function(err) { res.end.call(res, String(err)); }; | ||
res.header('x-streamable-bypass', '1'); | ||
return next(); | ||
@@ -121,3 +147,2 @@ } | ||
stream.socket.removeAllListeners(ackEvent); | ||
stream.fatal(new Error("stream acknowledgement timed out")); | ||
}, 5000); | ||
@@ -132,12 +157,21 @@ | ||
// writes a buffer to the stream. | ||
res.write = stream.write; | ||
res.write = function(value, encoding) { | ||
stream.write.call(res, encodeValue(value, encoding)); | ||
}; | ||
// writes a non-fatal error to the stream. | ||
res.error = stream.error; | ||
res.error = function(err) { | ||
stream.error.call(res, String(err)); | ||
}; | ||
// writes a fatal error to the stream, with intent to close the stream. | ||
res.fatal = stream.fatal; | ||
res.fatal = function(err) { | ||
stream.fatal.call(res, String(err)); | ||
}; | ||
// closes the stream. | ||
res.end = stream.end; | ||
res.end = function() { | ||
if (arguments.length != 0) { res.write.apply(res, arguments); } | ||
stream.end.call(res); | ||
}; | ||
@@ -144,0 +178,0 @@ next(); |
Sorry, the diff of this file is not supported yet
16129
273
91