nd-json-rpc-protocol
Version:
A protocol encapsulating json-rpc massages with new line delimited json attached data
142 lines (125 loc) • 2.9 kB
JavaScript
import * as jsonRpcProtocol from 'json-rpc-protocol'
const {
format: _format,
InvalidJson,
JsonRpcError,
parse: _parse
} = jsonRpcProtocol
export class NdJsonRpcError extends JsonRpcError {}
const _do = ({_f, method, error, id, data, params = {}}) => {
if (!Array.isArray(data)) {
throw new NdJsonRpcError('data is expected as an Array')
}
if (params.size !== undefined) {
throw new NdJsonRpcError('size is a reserved nd-json-rpc response property')
}
params.size = data.length
let firstChunk
switch (_f) {
case 'notification':
firstChunk = _format.notification(method, params)
break
case 'request':
firstChunk = _format.request(id, method, params)
break
case 'response':
firstChunk = _format.response(id, params)
break
case 'error':
firstChunk = _format.error(id, error)
break
default:
throw new Error('Unknown or unhandled jsonrpc message format')
}
let output = firstChunk
data.forEach(element => {
output = output.concat('\n')
output = output.concat(JSON.stringify(element))
})
return output
}
const notification = (method, params, data = []) => {
return _do({
_f: 'notification',
method,
params,
data
})
}
const request = (id, method, params, data) => {
return _do({
_f: 'request',
id,
method,
params,
data
})
}
const response = (id, params, data = []) => {
return _do({
_f: 'response',
id,
params,
data
})
}
const error = (id, error) => {
return _do({
_f: 'error',
id,
error
})
}
/*
* returns { jsonrpcMessage, data}
*
* where `jsonrpcMessage` is a json-rpc message object, and `data` an array
*
* `jsonrpcMessage` can be a json-rpc error
* `data` can be undefined
*
* If `data` is defined, `jsonrpc.size` will give its number of elements
*/
export const parse = response => {
response = response.split('\n')
let firstChunk
try {
firstChunk = _parse(response.shift())
} catch (error) {
if (error instanceof InvalidJson) {
throw new NdJsonRpcError('First chunk is not a well-formed json-rpc response', error.code)
}
throw error
}
const { error } = firstChunk
if (error !== undefined) {
return { jsonrpcMessage: firstChunk }
}
if (firstChunk.result.size !== response.length) {
throw new NdJsonRpcError('Data does not match its given size')
}
try {
response = response.map(chunk => JSON.parse(chunk))
} catch (error) {
if (error instanceof SyntaxError) {
throw new NdJsonRpcError('Some data items are not well-formed JSON')
}
}
return {
jsonrpcMessage: firstChunk,
data: response
}
}
export const format = {
error,
notification,
request,
response
}
export {
InvalidJson,
InvalidParameters,
InvalidRequest,
JsonRpcError,
MethodNotFound
} from 'json-rpc-protocol'