chunked-request
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -38,3 +38,3 @@ // Karma configuration | ||
var reporters = []; | ||
var reporters = ['dots']; | ||
var browsers = []; | ||
@@ -82,2 +82,3 @@ var singlerun = false; | ||
'/chunked-response': 'http://localhost:2001/chunked-response', | ||
'/split-chunked-response': 'http://localhost:2001/split-chunked-response', | ||
'/error-response': 'http://localhost:2001/error-response', | ||
@@ -84,0 +85,0 @@ '/echo-response': 'http://localhost:2001/echo-response' |
@@ -7,10 +7,34 @@ 'use strict'; | ||
exports.default = defaultChunkParser; | ||
function defaultChunkParser(value) { | ||
var entryDelimiter = '\n'; | ||
var entryDelimiter = '\n'; | ||
return value.split(entryDelimiter).filter(function (v) { | ||
return !!v.trim(); | ||
// The defaultChunkParser expects the response from the server to consist of new-line | ||
// delimited JSON, eg: | ||
// | ||
// { "chunk": "#1", "data": "Hello" } | ||
// { "chunk": "#2", "data": "World" } | ||
// | ||
// It will correctly handle the case where a chunk is emitted by the server across | ||
// delimiter boundaries. | ||
function defaultChunkParser(rawChunk) { | ||
var prevChunkSuffix = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1]; | ||
var chunkSuffix = void 0; | ||
var rawChunks = ('' + prevChunkSuffix + rawChunk).split(entryDelimiter); | ||
if (!hasSuffix(rawChunk, entryDelimiter)) { | ||
chunkSuffix = rawChunks.pop(); | ||
} | ||
var processedChunks = rawChunks.filter(function (v) { | ||
return v.trim() !== ''; | ||
}).map(function (v) { | ||
return JSON.parse(v); | ||
}); | ||
return [processedChunks, chunkSuffix]; | ||
} | ||
function hasSuffix(s, suffix) { | ||
return s.substr(s.length - suffix.length) === suffix; | ||
} |
@@ -6,2 +6,5 @@ 'use strict'; | ||
}); | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
exports.default = chunkedRequest; | ||
@@ -41,10 +44,22 @@ | ||
var prevChunkSuffix = ""; | ||
function processRawChunk(rawChunk) { | ||
var parsedChunks = null; | ||
var parseError = null; | ||
var suffix = ""; | ||
try { | ||
parsedChunks = chunkParser(rawChunk); | ||
var _chunkParser = chunkParser(rawChunk, prevChunkSuffix); | ||
var _chunkParser2 = _slicedToArray(_chunkParser, 2); | ||
parsedChunks = _chunkParser2[0]; | ||
suffix = _chunkParser2[1]; | ||
prevChunkSuffix = suffix || ""; | ||
} catch (e) { | ||
parseError = e; | ||
parseError.rawChunk = rawChunk; | ||
parseError.prevChunkSuffix = prevChunkSuffix; | ||
} finally { | ||
@@ -51,0 +66,0 @@ onChunk(parseError, parsedChunks); |
{ | ||
"name": "chunked-request", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"main": "lib/index.js", | ||
@@ -5,0 +5,0 @@ "jsnext:main": "src/index.js", |
@@ -39,8 +39,30 @@ # chunked-request | ||
#### chunkParser (optional) | ||
A function which takes the raw, textual chunk response returned by the server and converts it into the value passed to the `onChunk` callback (see `options.onChunk`). If this value throws an exception, the chunk will be discarded and the error will be passed to the `onChunk` callback. If no `chunkParser` is supplied the `defaultChunkParser` will be used which expects the chunks returned by the server to consist of one or more lines of JSON object literals which are parsed into an Array or objects. | ||
A function which implements the following interface: | ||
```js | ||
(rawChunk, previousChunkSuffix) => [ parsedChunk, chunkSuffix ] | ||
``` | ||
The `chunkParser` takes the raw, textual chunk response returned by the server and converts it into the value passed to the `onChunk` callback (see `options.onChunk`). The function may also yield an optional chunkSuffix which will be not be passed to the `onChunk` callback but will instead be supplied as the `previousChunkSuffix` value the next time the `chunkParser` is invoked. | ||
If the `chunkParser` throws an exception, the chunk will be discarded and the error that was raised will be passed to the `onChunk` callback augmented with a `rawChunk` property consisting of the textual chunk for logging / recovery. | ||
If no `chunkParser` is supplied the `defaultChunkParser` will be used which expects the chunks returned by the server to consist of one or more `\n` delimited lines of JSON object literals which are parsed into an Array. | ||
#### onChunk (optional) | ||
A function which will be invoked each time a chunk of data it returned by the server. This function will be invoked one or more times depending on the response. The function is invoked with two arguments; the first is an optional error which will be null unless there was a parsing error. The second argument is an optional parsedChunk value which is produced by the supplied `chunkParser` (see: `options.chunkParser`). | ||
A function which implements the following interface: | ||
```js | ||
(err, parsedChunk) => undefined | ||
``` | ||
The `onChunk` handler will be invoked each time a chunk of data it returned by the server. This function will be invoked one or more times depending on the response. The function is invoked with two arguments; the first is an optional error which will be null unless there was a parsing error thrown by the `chunkParser``. The second argument is an optional parsedChunk value which is produced by the supplied `chunkParser` (see: `options.chunkParser`). | ||
#### onComplete (optional) | ||
A function which implements the following interface: | ||
```js | ||
({ statusCode, transport, raw }) => undefined | ||
``` | ||
A function which will be invoked once when the browser has closed the connection to the server. This function is invoked with a single argument which contains the following properties: | ||
@@ -55,2 +77,10 @@ | ||
#### transport (optional) | ||
The underlying function to use to make the request, see the provided implementations if you wish to provide a custom extension. If no value is supplied the `chunkedRequest.transportFactory` function will be invoked to determine which transport method to use. The deafult `transportFactory` will attempt to select the best available method for the current platform; but you can override this method for substituting a test-double or custom implementation. | ||
A function which implements the following interface: | ||
```js | ||
({ url, headers, method, body, onComplete, onRawChunk }) => undefined | ||
``` | ||
The underlying function to use to make the request, see the provided implementations if you wish to provide a custom extension. | ||
If no value is supplied the `chunkedRequest.transportFactory` function will be invoked to determine which transport method to use. The deafult `transportFactory` will attempt to select the best available method for the current platform; but you can override this method for substituting a test-double or custom implementation. |
@@ -1,7 +0,30 @@ | ||
export default function defaultChunkParser(value) { | ||
const entryDelimiter = '\n'; | ||
const entryDelimiter = '\n'; | ||
return value.split(entryDelimiter) | ||
.filter(v => !!v.trim()) | ||
// The defaultChunkParser expects the response from the server to consist of new-line | ||
// delimited JSON, eg: | ||
// | ||
// { "chunk": "#1", "data": "Hello" } | ||
// { "chunk": "#2", "data": "World" } | ||
// | ||
// It will correctly handle the case where a chunk is emitted by the server across | ||
// delimiter boundaries. | ||
export default function defaultChunkParser(rawChunk, prevChunkSuffix = '') { | ||
let chunkSuffix; | ||
const rawChunks = `${prevChunkSuffix}${rawChunk}` | ||
.split(entryDelimiter); | ||
if (!hasSuffix(rawChunk, entryDelimiter)) { | ||
chunkSuffix = rawChunks.pop(); | ||
} | ||
const processedChunks = rawChunks | ||
.filter(v => v.trim() !== '') | ||
.map(v => JSON.parse(v)); | ||
return [ processedChunks, chunkSuffix ]; | ||
} | ||
function hasSuffix(s, suffix) { | ||
return s.substr(s.length - suffix.length) === suffix; | ||
} |
@@ -22,10 +22,16 @@ import { isObject, noop } from './util'; | ||
let prevChunkSuffix = ""; | ||
function processRawChunk(rawChunk) { | ||
let parsedChunks = null; | ||
let parseError = null; | ||
let suffix = ""; | ||
try { | ||
parsedChunks = chunkParser(rawChunk); | ||
[ parsedChunks, suffix ] = chunkParser(rawChunk, prevChunkSuffix); | ||
prevChunkSuffix = suffix || ""; | ||
} catch (e) { | ||
parseError = e; | ||
parseError.rawChunk = rawChunk; | ||
parseError.prevChunkSuffix = prevChunkSuffix; | ||
} finally { | ||
@@ -32,0 +38,0 @@ onChunk(parseError, parsedChunks); |
Sorry, the diff of this file is not supported yet
63813
36
574
84