@ch1/rpc-web-socket
Advanced tools
Comparing version 1.1.0 to 1.2.0
# CHANGE LOG | ||
## 1.2.0 | ||
- Rejects function back log on error (server) | ||
- Rejects function back log on error (client) | ||
- Rejects function back log on disconnect (server) | ||
- Rejects function back log on disconnect (client) | ||
- Destroys on error (client) | ||
- Destroys on disconnect (client) | ||
- ping/pong keep alive (server) | ||
- adds code coverage | ||
## 1.1.0 | ||
- commonJS exports now supported |
@@ -17,2 +17,20 @@ 'use strict'; | ||
*/ | ||
function configureNativeSocketOnMethod(config) { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureWsSocketOnMethod(config) { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureOnEmit(config) { | ||
@@ -26,18 +44,6 @@ if (!config.socket) { | ||
} | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureNativeSocketOnMethod(config); | ||
} | ||
else { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureWsSocketOnMethod(config); | ||
} | ||
@@ -51,28 +57,95 @@ if (typeof config.socket.send !== 'function') { | ||
} | ||
function create(config = {}, remote, remoteDesc) { | ||
function configureNativeSocket(config, remote, remoteDesc) { | ||
let resolve; | ||
let reject; | ||
let rpc$$1; | ||
const earlyDestroys = []; | ||
const expose = { | ||
onDestroy: (...args) => { | ||
let destroyed = false; | ||
const destroy = (reason) => { | ||
destroyed = true; | ||
desc.onDestroy(reason); | ||
}; | ||
const desc = { | ||
isValid: () => { | ||
if (destroyed) { | ||
return false; | ||
} | ||
else { | ||
return true; | ||
} | ||
}, | ||
args, | ||
onDestroy: reason => { }, | ||
}; | ||
earlyDestroys.push(desc); | ||
return destroy; | ||
}, | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
// @todo awkard... this will need a refactor | ||
config.socket.addEventListener('close', () => { | ||
if (rpc$$1) { | ||
rpc$$1.destroy('rpc: web-socket closed'); | ||
} | ||
else { | ||
console.warn('rpc: web-socket error: rpc still not defined (close)'); | ||
} | ||
}); | ||
// @todo awkard... this will need a refactor | ||
config.socket.addEventListener('error', error => { | ||
if (rpc$$1) { | ||
rpc$$1.destroy('rpc: web-socket error: native: ' + error.message); | ||
} | ||
else { | ||
console.warn('rpc: web-socket error: rpc still not defined (error)'); | ||
} | ||
}); | ||
config.socket.addEventListener('open', () => { | ||
rpc$$1 = rpc.create(config, remote, remoteDesc); | ||
earlyDestroys.forEach(desc => { | ||
if (desc.isValid()) { | ||
desc.onDestroy = rpc$$1.onDestroy(...desc.args); | ||
} | ||
}); | ||
rpc$$1.ready | ||
.then(() => { | ||
Object.keys(rpc$$1).forEach(key => { | ||
expose[key] = rpc$$1[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
} | ||
function configureWsSocket(config, remote, remoteDesc) { | ||
const rpc$$1 = rpc.create(config, remote, remoteDesc); | ||
const interval = setInterval(() => { | ||
if (config.socket.isAlive === false) { | ||
config.socket.terminate(); | ||
} | ||
config.socket.isAlive = false; | ||
config.socket.ping(); | ||
}, config.pingDelay || 10000); | ||
config.socket.isAlive = true; | ||
config.socket.on('pong', () => (config.socket.isAlive = true)); | ||
const destroy = rpc$$1.destroy; | ||
rpc$$1.destroy = () => { | ||
clearInterval(interval); | ||
return destroy(); | ||
}; | ||
return rpc$$1; | ||
} | ||
function create(config, remote, remoteDesc) { | ||
configureOnEmit(config); | ||
if (typeof WebSocket !== 'undefined') { | ||
let resolve; | ||
let reject; | ||
const expose = { | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
config.socket.addEventListener('open', () => { | ||
const rpc$$1 = rpc.create(config, remote, remoteDesc); | ||
rpc$$1.ready | ||
.then(() => { | ||
Object.keys(rpc$$1).forEach(key => { | ||
expose[key] = rpc$$1[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
return configureNativeSocket(config, remote, remoteDesc); | ||
} | ||
else { | ||
return rpc.create(config, remote, remoteDesc); | ||
return configureWsSocket(config, remote, remoteDesc); | ||
} | ||
@@ -79,0 +152,0 @@ } |
@@ -12,6 +12,12 @@ /** | ||
import { Remote, RemoteDesc, RPCAbstractConfig } from '@ch1/rpc'; | ||
export declare type WebSocketType = { | ||
on: (message: string, callback: (data: string) => void) => void; | ||
send: (data: string) => void; | ||
export declare type NativeWebSocket = { | ||
addEventListener: (message: string, handler: (result: { | ||
data: any; | ||
}) => any) => any; | ||
send: (data: string) => any; | ||
}; | ||
export declare type WsWebSocket = { | ||
on: (message: string, callback: (data: any) => any) => any; | ||
send: (data: string) => any; | ||
}; | ||
/** | ||
@@ -21,9 +27,8 @@ * Socket RPC Config | ||
export interface RPCSocketConfig extends RPCAbstractConfig { | ||
socket?: WebSocketType | { | ||
addEventListener: (message: string, callback: (data: any) => void) => void; | ||
send: (data: any) => void; | ||
}; | ||
pingDelay?: number; | ||
socket: NativeWebSocket | WsWebSocket; | ||
} | ||
export declare function create<T>(config?: RPCSocketConfig, remote?: Remote<any>, remoteDesc?: RemoteDesc): { | ||
export declare function create<RemoteType>(config: RPCSocketConfig, remote?: Remote<any>, remoteDesc?: RemoteDesc): { | ||
onDestroy: (...args: any[]) => (reason?: string) => void; | ||
ready: Promise<{}>; | ||
} | import("@ch1/rpc/dist/interfaces").RPC<T>; | ||
} | import("@ch1/rpc/dist/interfaces").RPC<RemoteType>; |
@@ -12,2 +12,20 @@ /** | ||
import { create as createRemote, } from '@ch1/rpc'; | ||
function configureNativeSocketOnMethod(config) { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureWsSocketOnMethod(config) { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureOnEmit(config) { | ||
@@ -21,18 +39,6 @@ if (!config.socket) { | ||
} | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureNativeSocketOnMethod(config); | ||
} | ||
else { | ||
config.on = (callback) => { | ||
const handler = (data) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureWsSocketOnMethod(config); | ||
} | ||
@@ -46,30 +52,97 @@ if (typeof config.socket.send !== 'function') { | ||
} | ||
export function create(config = {}, remote, remoteDesc) { | ||
function configureNativeSocket(config, remote, remoteDesc) { | ||
let resolve; | ||
let reject; | ||
let rpc; | ||
const earlyDestroys = []; | ||
const expose = { | ||
onDestroy: (...args) => { | ||
let destroyed = false; | ||
const destroy = (reason) => { | ||
destroyed = true; | ||
desc.onDestroy(reason); | ||
}; | ||
const desc = { | ||
isValid: () => { | ||
if (destroyed) { | ||
return false; | ||
} | ||
else { | ||
return true; | ||
} | ||
}, | ||
args, | ||
onDestroy: reason => { }, | ||
}; | ||
earlyDestroys.push(desc); | ||
return destroy; | ||
}, | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
// @todo awkard... this will need a refactor | ||
config.socket.addEventListener('close', () => { | ||
if (rpc) { | ||
rpc.destroy('rpc: web-socket closed'); | ||
} | ||
else { | ||
console.warn('rpc: web-socket error: rpc still not defined (close)'); | ||
} | ||
}); | ||
// @todo awkard... this will need a refactor | ||
config.socket.addEventListener('error', error => { | ||
if (rpc) { | ||
rpc.destroy('rpc: web-socket error: native: ' + error.message); | ||
} | ||
else { | ||
console.warn('rpc: web-socket error: rpc still not defined (error)'); | ||
} | ||
}); | ||
config.socket.addEventListener('open', () => { | ||
rpc = createRemote(config, remote, remoteDesc); | ||
earlyDestroys.forEach(desc => { | ||
if (desc.isValid()) { | ||
desc.onDestroy = rpc.onDestroy(...desc.args); | ||
} | ||
}); | ||
rpc.ready | ||
.then(() => { | ||
Object.keys(rpc).forEach(key => { | ||
expose[key] = rpc[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
} | ||
function configureWsSocket(config, remote, remoteDesc) { | ||
const rpc = createRemote(config, remote, remoteDesc); | ||
const interval = setInterval(() => { | ||
if (config.socket.isAlive === false) { | ||
config.socket.terminate(); | ||
} | ||
config.socket.isAlive = false; | ||
config.socket.ping(); | ||
}, config.pingDelay || 10000); | ||
config.socket.isAlive = true; | ||
config.socket.on('pong', () => (config.socket.isAlive = true)); | ||
const destroy = rpc.destroy; | ||
rpc.destroy = () => { | ||
clearInterval(interval); | ||
return destroy(); | ||
}; | ||
return rpc; | ||
} | ||
export function create(config, remote, remoteDesc) { | ||
configureOnEmit(config); | ||
if (typeof WebSocket !== 'undefined') { | ||
let resolve; | ||
let reject; | ||
const expose = { | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
config.socket.addEventListener('open', () => { | ||
const rpc = createRemote(config, remote, remoteDesc); | ||
rpc.ready | ||
.then(() => { | ||
Object.keys(rpc).forEach(key => { | ||
expose[key] = rpc[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
return configureNativeSocket(config, remote, remoteDesc); | ||
} | ||
else { | ||
return createRemote(config, remote, remoteDesc); | ||
return configureWsSocket(config, remote, remoteDesc); | ||
} | ||
} | ||
//# sourceMappingURL=web-socket.js.map |
@@ -21,3 +21,5 @@ // Karma configuration | ||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor | ||
preprocessors: {}, | ||
preprocessors: { | ||
'intermediate/**/*.js': 'coverage', | ||
}, | ||
@@ -27,3 +29,3 @@ // test results reporter to use | ||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter | ||
reporters: ['progress'], | ||
reporters: ['progress', 'coverage'], | ||
@@ -54,3 +56,12 @@ // web server port | ||
concurrency: Infinity, | ||
coverageReporter: { | ||
dir: 'coverage/', | ||
reporters: [ | ||
{ type: 'html', subdir: '.' }, | ||
{ type: 'lcov', subdir: '.' }, | ||
{ type: 'json', subdir: '.', file: 'lcov.json' }, | ||
], | ||
}, | ||
}); | ||
}; |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"author": { | ||
@@ -44,5 +44,5 @@ "name": "Michael J. Bennett", | ||
"postbuild": "rollup --input dist/index.js --format cjs --file dist/index.cjs.js", | ||
"clean": "rimraf ./intermediate && rimraf ./dist", | ||
"clean": "rimraf ./intermediate && rimraf ./dist && rimraf ./coverage", | ||
"precommit": "lint-staged", | ||
"pretest": "rimraf coverage && yarn build && rollup -c", | ||
"pretest": "yarn build && rollup -c", | ||
"test": "./test.js" | ||
@@ -57,2 +57,3 @@ }, | ||
"karma-chrome-launcher": "^2.2.0", | ||
"karma-coverage": "^1.1.2", | ||
"karma-jasmine": "^1.1.2", | ||
@@ -74,56 +75,6 @@ "lint-staged": "^7.2.0", | ||
}, | ||
"jest": { | ||
"collectCoverage": true, | ||
"collectCoverageFrom": [ | ||
"src/**/*.{ts,tsx}", | ||
"!**/node_modules/**", | ||
"!**/coverage/**", | ||
"!**/dist/**", | ||
"!**/*.d.ts", | ||
"!**/interfaces.ts" | ||
], | ||
"coverageDirectory": "coverage/", | ||
"coveragePathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/coverage/", | ||
"/dist/" | ||
], | ||
"coverageReporters": [ | ||
"json", | ||
"lcov", | ||
"text", | ||
"html" | ||
], | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 80, | ||
"functions": 80, | ||
"lines": 80, | ||
"statements": 90 | ||
} | ||
}, | ||
"modulePathIgnorePatterns": [ | ||
"/coverage/", | ||
"/dist/" | ||
], | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
"transformIgnorePatterns": [ | ||
"^node_modules/(?!@ch1).*$" | ||
], | ||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json", | ||
"node" | ||
] | ||
}, | ||
"dependencies": { | ||
"@ch1/rpc": "^1.0.4", | ||
"@ch1/rpc": "^1.3", | ||
"@ch1/utility": "^0.5.1" | ||
} | ||
} |
@@ -11,13 +11,25 @@ # CH1 RPC | ||
`yarn add @ch1/rpc-worker` | ||
`yarn add @ch1/rpc-web-socket` | ||
### Dependencies | ||
This library has an external run time dependency for the server side portion, | ||
which leverages the [excellent ws](https://github.com/websockets/ws 'Node WebSocket Library') library. | ||
This library has an external _optional_ run time dependency for the server | ||
side portion, which leverages the [excellent ws](https://github.com/websockets/ws 'Node WebSocket Library') | ||
library. | ||
The dependency is optional in that this library will work with anything that | ||
satisfies the `ws` interface: | ||
```ts | ||
export type WsWebSocket = { | ||
on: (message: string, callback: (data: any) => any) => any; | ||
send: (data: string) => any; | ||
}; | ||
``` | ||
We _do_ include `ws` as a `devDependency` since we use it for testing the | ||
library end to end. | ||
## Usage | ||
_Warning, no error handling is implemented on the sockets yet, that will come in the next release_ | ||
Slightly easier API than in the raw [`@ch1/rpc`](https://github.com/bennett000/ch1-rpc 'CH1 RPC') | ||
@@ -53,4 +65,79 @@ | ||
### Error Handling | ||
Due to the nature of state that could exist on client/server, this library | ||
takes the approach of terminating itself in the event of catastrophic failure. | ||
- Individual functions that fail are left up to the user to handle | ||
- Connection failures will result in the destruction of the object | ||
- Pending async requests will have their error handlers triggered | ||
best practice is to add an error listener: | ||
```ts | ||
const wrpc = require('@ch1/rpc-web-socket'); | ||
const wss = new WebSocket.Server({ port: 8080 }); | ||
wss.on('connection', ws => { | ||
const rpc = wrpc.create( | ||
{ socket: ws }, | ||
{ | ||
foo: () => new Promise(resolve => resolve(7)), | ||
}, | ||
); | ||
// This is teh relevant bit | ||
rpc.onDestroy((reason?: string) => { | ||
// put your error handling logic here. | ||
}); | ||
}); | ||
``` | ||
#### Web Socket Connection Handling | ||
This library attempts to automatically handle all connection errors and fail | ||
fast where possible. This includes a server side "ping pong" to detect | ||
"unplug" events. | ||
_Reconnection Is Left Up To The User of The Library, `onDestroy` is | ||
your friend_ | ||
Presumably the client will be responsible for the reconnection. | ||
## API | ||
The `create` function will provide an `RPC<RemoteType>` object: | ||
```ts | ||
export function create<RemoteType>( | ||
// required | ||
config: RPCSocketConfig, | ||
// functions (optionally nested) to provide to other side of the connection | ||
remote?: Remote<any>, | ||
// not used for now | ||
remoteDesc?: RemoteDesc, | ||
) { | ||
``` | ||
The `RPCSocketConfig` object looks like: | ||
```ts | ||
export interface RPCSocketConfig { | ||
// optionally configure the ping/pong delay the server uses | ||
// defaults to 10,000ms | ||
pingDelay?: number; | ||
// *mandatory* the socket to use, either WebSocket in the browser | ||
// or something _like_ `ws` on the server | ||
// (we're ws 6.x compatible) | ||
socket: NativeWebSocket | WsWebSocket; | ||
} | ||
``` | ||
The `RPC<RemoteType>` object is described [in the documentation for @ch1/rpc](https://www.npmjs.com/package/@ch1/rpc '@ch1/rpc documentation') | ||
## License | ||
[LGPL](./LICENSE 'Lesser GNU Public License') |
@@ -9,2 +9,3 @@ import nodeResolve from 'rollup-plugin-node-resolve'; | ||
format: 'iife', | ||
sourcemap: true, | ||
}, | ||
@@ -18,2 +19,3 @@ plugins: [nodeResolve({ jsnext: true })], | ||
format: 'cjs', | ||
sourcemap: true, | ||
}, | ||
@@ -20,0 +22,0 @@ plugins: [nodeResolve({ jsnext: true })], |
@@ -22,3 +22,20 @@ const TEST_FILE = '/base/intermediate/test-worker.js'; | ||
}); | ||
it('should destroy if the socket closes', done => { | ||
const ws = new WebSocket('ws://localhost:5151'); | ||
const rpc = wrpc.create({ socket: ws }); | ||
ws.addEventListener('error', done); | ||
rpc.onDestroy(reason => { | ||
expect(reason).toMatch(/^.*close.*$/); | ||
done(); | ||
}); | ||
rpc.ready | ||
.then(() => { | ||
ws.close(); | ||
}) | ||
.catch(done); | ||
}); | ||
}); | ||
}); |
@@ -20,7 +20,15 @@ /** | ||
export type WebSocketType = { | ||
on: (message: string, callback: (data: string) => void) => void; | ||
send: (data: string) => void; | ||
export type NativeWebSocket = { | ||
addEventListener: ( | ||
message: string, | ||
handler: (result: { data: any }) => any, | ||
) => any; | ||
send: (data: string) => any; | ||
}; | ||
export type WsWebSocket = { | ||
on: (message: string, callback: (data: any) => any) => any; | ||
send: (data: string) => any; | ||
}; | ||
/** | ||
@@ -30,13 +38,28 @@ * Socket RPC Config | ||
export interface RPCSocketConfig extends RPCAbstractConfig { | ||
socket?: | ||
| WebSocketType | ||
| { | ||
addEventListener: ( | ||
message: string, | ||
callback: (data: any) => void, | ||
) => void; | ||
send: (data: any) => void; | ||
}; | ||
pingDelay?: number; | ||
socket: NativeWebSocket | WsWebSocket; | ||
} | ||
function configureNativeSocketOnMethod(config: any) { | ||
config.on = (callback: (data: any) => any) => { | ||
const handler = (data: any) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureWsSocketOnMethod(config: any) { | ||
config.on = (callback: (data: any) => any) => { | ||
const handler = (data: any) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
} | ||
function configureOnEmit(config: any) { | ||
@@ -51,19 +74,5 @@ if (!config.socket) { | ||
} | ||
config.on = (callback: (data: any) => any) => { | ||
const handler = (data: any) => { | ||
callback(JSON.parse(data.data)); | ||
}; | ||
config.socket.addEventListener('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureNativeSocketOnMethod(config); | ||
} else { | ||
config.on = (callback: (data: any) => any) => { | ||
const handler = (data: any) => { | ||
callback(JSON.parse(data)); | ||
}; | ||
config.socket.on('message', handler); | ||
return () => config.socket.removeEventListener('message', handler); | ||
}; | ||
configureWsSocketOnMethod(config); | ||
} | ||
@@ -80,4 +89,108 @@ | ||
export function create<T>( | ||
config: RPCSocketConfig = {}, | ||
function configureNativeSocket<RemoteConfig>( | ||
config: any, | ||
remote: Remote<any>, | ||
remoteDesc: RemoteDesc, | ||
) { | ||
let resolve; | ||
let reject; | ||
let rpc; | ||
const earlyDestroys = []; | ||
const expose = { | ||
onDestroy: (...args: any[]) => { | ||
let destroyed = false; | ||
const destroy = (reason?: string) => { | ||
destroyed = true; | ||
desc.onDestroy(reason); | ||
}; | ||
const desc = { | ||
isValid: () => { | ||
if (destroyed) { | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
}, | ||
args, | ||
onDestroy: reason => {}, | ||
}; | ||
earlyDestroys.push(desc); | ||
return destroy; | ||
}, | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
// @todo awkard... this will need a refactor | ||
(config.socket as any).addEventListener('close', () => { | ||
if (rpc) { | ||
rpc.destroy('rpc: web-socket closed'); | ||
} else { | ||
console.warn('rpc: web-socket error: rpc still not defined (close)'); | ||
} | ||
}); | ||
// @todo awkard... this will need a refactor | ||
(config.socket as any).addEventListener('error', error => { | ||
if (rpc) { | ||
rpc.destroy('rpc: web-socket error: native: ' + error.message); | ||
} else { | ||
console.warn('rpc: web-socket error: rpc still not defined (error)'); | ||
} | ||
}); | ||
(config.socket as any).addEventListener('open', () => { | ||
rpc = createRemote<RemoteConfig>(<RPCConfig>config, remote, remoteDesc); | ||
earlyDestroys.forEach(desc => { | ||
if (desc.isValid()) { | ||
desc.onDestroy = rpc.onDestroy(...desc.args); | ||
} | ||
}); | ||
rpc.ready | ||
.then(() => { | ||
Object.keys(rpc).forEach(key => { | ||
expose[key] = rpc[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
} | ||
function configureWsSocket<RemoteConfig>( | ||
config: any, | ||
remote: Remote<any>, | ||
remoteDesc: RemoteDesc, | ||
) { | ||
const rpc = createRemote<RemoteConfig>( | ||
<RPCConfig>config, | ||
remote, | ||
remoteDesc, | ||
); | ||
const interval = setInterval(() => { | ||
if (config.socket.isAlive === false) { | ||
config.socket.terminate(); | ||
} | ||
config.socket.isAlive = false; | ||
config.socket.ping(); | ||
}, config.pingDelay || 10000); | ||
config.socket.isAlive = true; | ||
config.socket.on('pong', () => (config.socket.isAlive = true)); | ||
const destroy = rpc.destroy; | ||
rpc.destroy = () => { | ||
clearInterval(interval); | ||
return destroy(); | ||
}; | ||
return rpc; | ||
} | ||
export function create<RemoteType>( | ||
config: RPCSocketConfig, | ||
remote?: Remote<any>, | ||
@@ -89,25 +202,6 @@ remoteDesc?: RemoteDesc, | ||
if (typeof WebSocket !== 'undefined') { | ||
let resolve; | ||
let reject; | ||
const expose = { | ||
ready: new Promise((res, rej) => { | ||
resolve = res; | ||
reject = rej; | ||
}), | ||
}; | ||
(config.socket as any).addEventListener('open', () => { | ||
const rpc = createRemote<T>(<RPCConfig>config, remote, remoteDesc); | ||
rpc.ready | ||
.then(() => { | ||
Object.keys(rpc).forEach(key => { | ||
expose[key] = rpc[key]; | ||
}); | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
return expose; | ||
return configureNativeSocket<RemoteType>(config, remote, remoteDesc); | ||
} else { | ||
return createRemote<T>(<RPCConfig>config, remote, remoteDesc); | ||
return configureWsSocket<RemoteType>(config, remote, remoteDesc); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
40699
647
142
16
Updated@ch1/rpc@^1.3