toa-net
v1.5.4
Published
JSON-RPC 2.0 client/server over TCP net.
Downloads
24
Maintainers
Readme
Toa-net
JSON-RPC 2.0 client/server over TCP net.
Features
- Use JSON-RPC 2.0 Specification as RPC protocol.
- Use RESP (Redis Serialization Protocol) or MsgP (Byte Message Protocol) as message protocol.
- Use JSON Web Signatures as authentication protocol.
- Implemented ES6 Iterable protocol.
Implementations
- snapper-core Teambition push messaging service, based on redis.
- snapper-producer Snapper producer client for node.js.
Examples
Simple
const net = require('toa-net')
const auth = new net.Auth('secretxxx')
const server = new net.Server(function (socket) {
socket.on('message', (message) => {
console.log(message)
// { payload: { jsonrpc: '2.0', method: 'hello', params: [ 1 ] },
// type: 'notification' }
// ...
if (message.type === 'request') {
// echo request
socket.success(message.payload.id, message.payload.params)
}
})
})
server.listen(8000)
// Enable authentication for server
server.getAuthenticator = function () {
return (signature) => auth.verify(signature)
}
const client = new net.Client()
// Enable authentication for client
client.getSignature = function () {
return auth.sign({id: 'clientIdxxx'})
}
client.connect(8000)
client.notification('hello', [1])
client.notification('hello', [2])
client.notification('hello', [3])
client.request('echo', {a: 4})((err, res) => {
console.log(err, res) // null { a: 4 }
client.destroy()
server.close()
})Iterator
Socket is async iterable object!
const thunk = require('thunks')()
const net = require('toa-net')
// 创建服务器
const server = new net.Server(function (socket) {
thunk(function * () {
// 高能!!!异步迭代 socket 接收的数据,socket 关闭后迭代结束
for (let value of socket) {
let message = yield value
console.log(message)
// { payload: { jsonrpc: '2.0', method: 'hello', params: [ 1 ] },
// type: 'notification' }
// ...
if (message.type === 'request') {
// respond to the request
socket.success(message.payload.id, message.payload.params)
}
}
})((err) => {
console.log(err)
process.exit(0)
})
})
server.listen(8000)
// 创建客户端
const client = new net.Client().connect(8000)
// 向服务器发出 notification
client.notification('hello', [1])
client.notification('hello', [2])
client.notification('hello', [3])
// 向服务器发出 RPC 请求,服务器将 echo 请求数据
client.request('echo', {a: 4})((err, res) => {
console.log(err, res) // null { a: 4 }
client.destroy()
server.close()
})Bench https://github.com/toajs/toa-net/tree/master/bench
gRPC vs axon vs toa-net, 5000000 Ping/Pong messages, 1 TCP connection, Node.js v6
- gRPC, no-delay: 1000 cocurrency, 1240066 ms, 4032.04 ops
- axon, no-delay: 1000 cocurrency, 204176 ms, 148888.89 kb, 24488.68 ops
- toa-net, no-delay: 1000 cocurrency, 73789 ms, 263272.57 kb, 67760.78 ops
100000 Ping/Pong messages
- local -> local, no-delay: 1000 cocurrency, 3180ms, 31446 ops
- local -> local, delay 1000ms: 1000 cocurrency, 100590ms, 994 ops
- local -> local, delay 1000ms: 5000 cocurrency, 20869ms, 4791 ops
- local -> local, delay 1000ms: 10000 cocurrency, 11074ms, 9030 ops
10000 simple messages, 1000 cocurrency
// message
{
name: 'abcdefghijklmnopqrst',
email: '[email protected]',
location: 'zhangjiang, shanghai, china'
}- aliyun -> aws: 264321ms, 37 ops, 4.61 kb/s
- aws -> aliyun: 82129ms, 121 ops, 14.84 kb/s
- aliyun -> proxy_cn -> fiber -> proxy_us -> aws: 8056ms, 1241 ops, 151.30 kb/s
Install
npm install toa-netAPI
const toaNet = require('toa-net')Class toaNet.Server
new toaNet.Server(connectionListener)
Create RPC server.
const server = new net.Server(function (socket) {
socket.on('message', (message) => {
console.log(message)
})
})
server.listen(8000)connectionListener: Required, Type:Function.
Event: 'close'
Event: 'error'
Event: 'listening'
server.getAuthenticator()
Abstract method. Should be overridden to enable authentication.
Default:
server.getAuthenticator = function () {
return null // Disable authentication
}Enable authentication:
const auth = new net.Auth('secretxxx')
server.getAuthenticator = function () {
return (signature) => auth.verify(signature)
}server.address()
Returns the bound address.
server.connections: RingPool
server.connections.length
Returns the number of concurrent connections on the server.
server.connections.next()
Return a socket in turn. Return null if no socket available.
server.close([callback])
Closes the server.
server.listen(...)
Same as node.js server.listen
Class toaNet.Client
Event: 'close'
Event: 'connect'
Event: 'auth'
Event: 'message'
Event: 'drain'
Event: 'end'
Event: 'error'
Event: 'timeout'
new toaNet.Client([options])
Creates RPC client.
const client = new net.Client().connect(8000)options.retryDelay: Optional, Type:Number, Default:500ms. Sets time interval for reconnection.options.maxAttempts: Optional, Type:Number, Default:50. Sets max attempts for reconnection.options.tcpTimeout: Optional, Type:Number, Default:0. Sets the socket to timeout after timeout milliseconds of inactivity on the socket.options.tcpNoDelay: Optional, Type:Boolean, Default:true. Disables the Nagle algorithm.options.tcpKeepAlive: Optional, Type:Boolean, Default:true. Enable/disable keep-alive functionality, and optionally set the initial delay before the first keepalive probe is sent on an idle socket.
client.connect(...)
Same as node.js socket.connect
client.connect('tcp://127.0.0.1:33333')client.getSignature()
Abstract method. Should be overridden to enable authentication.
Default:
client.getSignature = function () {
return '' // Disable authentication
}Enable authentication:
const auth = new net.Auth('secretxxx')
client.getSignature = function () {
return auth.sign({id: 'example'})
}client.request(method[, params])
Creates a JSON-RPC 2.0 request to another side. Returns thunk function.
client.request('echo', {name: 'zensh'})((err, res) => {
console.log(err, res)
})method: Required, Type:String.params: Optional, Type:Object|Array.
client.notification(method[, params])
Creates a JSON-RPC 2.0 notification to another side. No return.
client.notification('hello', {name: 'zensh'})method: Required, Type:String.params: Optional, Type:Object|Array.
client.success(id, result)
Respond success result to the request of id. No return.
client.success(1, 'OK')id: Required, Type:String|Integer, the request'sid.result: Required, Type:Mixed.
client.error(id, error)
Respond error to the request of id. No return.
client.error(1, new Error('some error'))id: Required, Type:String|Integer, the request'sid.error: Required, Type:Error.
client.createError(error[, code, data])
client.createError(message[, code, data])
client.createError(code[, data])
client.throw(error[, code, data])
client.throw(message[, code, data])
client.throw(code[, data])
client.handleJsonRpc(jsonRpc, handleFn)
client.address()
client.destroy()
client[Symbol.iterator]()
Class toaNet.Auth
new toaNet.Auth(options)
Creates auth object for Server and Client.
const auth = new net.Auth({
expiresIn: 3600,
secrets: ['secretxxx1', 'secretxxx2', 'secretxxx3']
})options.secrets: Required, Type:Stringor aArrayof string.options.expiresIn: Optional, Type:Number, Default:3600seconds.options.algorithm: Optional, Type:String, Default:'HS256'.
auth.sign(payload)
Returns a new signature string.
let signature = auth.sign({id: 'xxxxxxId'})auth.verify(signature)
Verify the signature, return payload object if success, or throw a error.
let session = auth.verify(signature)auth.decode(signature)
Try decode the signature, return payload object if success, or null.
let signature = auth.decode(signature)Advance API
Class toaNet.Resp
Class toaNet.Queue
Class toaNet.Socket
Class toaNet.RingPool
Class toaNet.RPCCommand
toaNet.jsonrpc
License
Toa-net is licensed under the MIT license. Copyright © 2016-2018 Toajs.
