ts-event-bus
Advanced tools
Comparing version 3.1.0 to 4.0.0
@@ -5,2 +5,9 @@ import { TransportMessage } from './Message'; | ||
timeout: number; | ||
/** | ||
* Orders the channel to reconnect. | ||
* | ||
* @remarks To implement in order to benefit from the auto-reconnect feature. | ||
* See the {@link ../README.md | README} for more context. | ||
*/ | ||
autoReconnect?: () => void; | ||
send: (message: TransportMessage) => void; | ||
@@ -7,0 +14,0 @@ onData: (cb: OnMessageCallback) => void; |
@@ -5,5 +5,7 @@ import { Transport } from './Transport'; | ||
noBuffer?: boolean; | ||
autoReconnect?: boolean; | ||
} | ||
export declare const defaultSlotConfig: { | ||
noBuffer: boolean; | ||
autoReconnect: boolean; | ||
}; | ||
@@ -10,0 +12,0 @@ export declare type LazyCallback = (param: string) => void; |
@@ -19,3 +19,4 @@ "use strict"; | ||
const defaultSlotConfig = { | ||
noBuffer: false | ||
noBuffer: false, | ||
autoReconnect: true | ||
}; | ||
@@ -145,7 +146,37 @@ exports.defaultSlotConfig = defaultSlotConfig; | ||
const data = paramUsed ? secondArg : firstArg; | ||
const param = paramUsed ? firstArg : _Constants.DEFAULT_PARAM; | ||
const param = paramUsed ? firstArg : _Constants.DEFAULT_PARAM; // Called when all transports are ready: | ||
// 1. When only the LOCAL_TRANSPORT exists | ||
// 2. With noBuffer option and all transport channels are connected | ||
// 3. Without noBuffer option and all transport channels are connected and handler registered | ||
if (config.noBuffer || transports.length === 0) { | ||
const callHandlersWithParameters = () => { | ||
const allParamHandlers = getParamHandlers(param, handlers); | ||
return (0, _Handler.callHandlers)(data, allParamHandlers); | ||
}; // In this case: only the LOCAL_TRANSPORT handler is defined, | ||
// we don't need to check any connection or buffering status | ||
if (transports.length === 0) { | ||
return callHandlersWithParameters(); | ||
} // Autoreconnect disconnected transports | ||
// The transport's handler will be called when the remote one will be registered | ||
// (default connect and registration flow with awaitHandlerRegistration) | ||
const transportConnectionPromises = []; | ||
if (config.autoReconnect) { | ||
transports.forEach(_t => { | ||
// Connection status is handle into autoReconnect method | ||
transportConnectionPromises.push(_t.autoReconnect()); | ||
}); | ||
} // In case of noBuffer config we wait all connections are established before calling the handlers | ||
// NOTE: there is a conceptual issue here, as all resolved response from all transports are expected | ||
// if one transport failed, the trigger initiator won't receive an answer | ||
if (config.noBuffer) { | ||
return Promise.all(transportConnectionPromises).then(() => { | ||
return callHandlersWithParameters(); | ||
}); | ||
} else { | ||
@@ -159,4 +190,3 @@ transports.forEach((_t, transportKey) => { | ||
return Promise.all(transportPromises).then(() => { | ||
const allParamHandlers = getParamHandlers(param, handlers); | ||
return (0, _Handler.callHandlers)(data, allParamHandlers); | ||
return callHandlersWithParameters(); | ||
}); | ||
@@ -163,0 +193,0 @@ } |
@@ -77,3 +77,16 @@ import { Handler } from './Handler'; | ||
unregisterHandler(slotName: string, param: string, handler: Handler<any, any>): void; | ||
/** | ||
* Allows to know the transport status and to perform a reconnection | ||
* | ||
* @returns {boolean} Transport's channel connection status, true if disconnected, otherwise false | ||
*/ | ||
isDisconnected(): boolean; | ||
/** | ||
* Auto-reconnect the channel | ||
* see Slot.trigger function for usage | ||
* | ||
* @returns {Promise} A promise resolving when the connection is established | ||
*/ | ||
autoReconnect(): Promise<void>; | ||
} | ||
//# sourceMappingURL=Transport.d.ts.map |
@@ -354,5 +354,38 @@ "use strict"; | ||
} | ||
/** | ||
* Allows to know the transport status and to perform a reconnection | ||
* | ||
* @returns {boolean} Transport's channel connection status, true if disconnected, otherwise false | ||
*/ | ||
isDisconnected() { | ||
return !this._channelReady; | ||
} | ||
/** | ||
* Auto-reconnect the channel | ||
* see Slot.trigger function for usage | ||
* | ||
* @returns {Promise} A promise resolving when the connection is established | ||
*/ | ||
autoReconnect() { | ||
if (this.isDisconnected() && this._channel.autoReconnect) { | ||
const promise = new Promise(resolve => { | ||
this._channel.onConnect(() => { | ||
return resolve(); | ||
}); | ||
}); | ||
this._channel.autoReconnect(); | ||
return promise; | ||
} | ||
return Promise.resolve(); | ||
} | ||
} | ||
exports.Transport = Transport; |
{ | ||
"name": "ts-event-bus", | ||
"version": "3.1.0", | ||
"version": "4.0.0", | ||
"description": "Distributed messaging in Typescript", | ||
@@ -39,3 +39,2 @@ "main": "build/index.js", | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
@@ -47,2 +46,3 @@ "@babel/cli": "^7.12.10", | ||
"@babel/preset-typescript": "^7.12.7", | ||
"@types/chrome": "^0.0.155", | ||
"@types/jest": "^26.0.20", | ||
@@ -54,3 +54,3 @@ "@types/ws": "^3.2.1", | ||
"tslint": "^5.6.0", | ||
"typescript": "^4.1.3", | ||
"typescript": "~4.1.3", | ||
"typescript-formatter": "^7.2.2", | ||
@@ -57,0 +57,0 @@ "ws": "^3.3.2" |
196
README.md
# ts-event-bus | ||
[![by Dashlane](https://rawgit.com/dashlane/ts-event-bus/master/by_dashlane.svg)](https://www.dashlane.com/) | ||
[![Build Status](https://travis-ci.org/Dashlane/ts-event-bus.svg?branch=master)](https://travis-ci.org/Dashlane/ts-event-bus) | ||
[![Build Status](https://github.com/Dashlane/ts-event-bus/actions/workflows/nodejs.yml/badge.svg)](https://github.com/Dashlane/ts-event-bus/actions/workflows/nodejs.yml) | ||
[![Dependency Status](https://david-dm.org/Dashlane/ts-event-bus.svg)](https://david-dm.org/Dashlane/ts-event-bus) | ||
@@ -19,15 +20,16 @@ | ||
// MyEvents.ts | ||
import { slot, Slot } from 'ts-event-bus' | ||
import { slot, Slot } from "ts-event-bus"; | ||
const MyEvents = { | ||
sayHello: slot<string>(), | ||
getTime: slot<null, string>(), | ||
multiply: slot<{a: number, b: number}, number>(), | ||
ping: slot<void>(), | ||
} | ||
sayHello: slot<string>(), | ||
getTime: slot<null, string>(), | ||
multiply: slot<{ a: number; b: number }, number>(), | ||
ping: slot<void>(), | ||
}; | ||
export default MyEvents | ||
export default MyEvents; | ||
``` | ||
### Create EventBus | ||
Your components will then instantiate an event bus based on this declaration, using whatever channel they may want to communicate on. | ||
@@ -40,12 +42,12 @@ If you specify no `Channel`, it means that you will exchange events in the same memory space. | ||
// firstModule.EventBus.ts | ||
import { createEventBus } from 'ts-event-bus' | ||
import MyEvents from './MyEvents.ts' | ||
import MyBasicWebSocketClientChannel from './MyBasicWebSocketClientChannel.ts' | ||
import { createEventBus } from "ts-event-bus"; | ||
import MyEvents from "./MyEvents.ts"; | ||
import MyBasicWebSocketClientChannel from "./MyBasicWebSocketClientChannel.ts"; | ||
const EventBus = createEventBus({ | ||
events: MyEvents, | ||
channels: [ new MyBasicWebSocketClientChannel('ws://your_host') ] | ||
}) | ||
events: MyEvents, | ||
channels: [new MyBasicWebSocketClientChannel("ws://your_host")], | ||
}); | ||
export default EventBus | ||
export default EventBus; | ||
``` | ||
@@ -55,10 +57,10 @@ | ||
// secondModule.EventBus.ts | ||
import { createEventBus } from 'ts-event-bus' | ||
import MyEvents from './MyEvents.ts' | ||
import MyBasicWebSocketServerChannel from './MyBasicWebSocketServerChannel.ts' | ||
import { createEventBus } from "ts-event-bus"; | ||
import MyEvents from "./MyEvents.ts"; | ||
import MyBasicWebSocketServerChannel from "./MyBasicWebSocketServerChannel.ts"; | ||
const EventBus = createEventBus({ | ||
events: MyEvents, | ||
channels: [ new MyBasicWebSocketServerChannel('ws://your_host') ] | ||
}) | ||
events: MyEvents, | ||
channels: [new MyBasicWebSocketServerChannel("ws://your_host")], | ||
}); | ||
``` | ||
@@ -99,29 +101,33 @@ | ||
// secondModule.ts | ||
import EventBus from './secondModule.EventBus.ts' | ||
import EventBus from "./secondModule.EventBus.ts"; | ||
// Add a listener on the default parameter | ||
EventBus.ping.on(() => { | ||
console.log('pong') | ||
}) | ||
console.log("pong"); | ||
}); | ||
// Or listen to a specific parameter | ||
EventBus.say.on('michel', (words) => { | ||
console.log('michel said', words) | ||
}) | ||
EventBus.say.on("michel", (words) => { | ||
console.log("michel said", words); | ||
}); | ||
// Event subscribers can respond to the event synchronously (by returning a value) | ||
EventBus.getTime.on(() => new Date().toString) | ||
EventBus.getTime.on(() => new Date().toString); | ||
// Or asynchronously (by returning a Promise that resolves with the value). | ||
EventBus.multiply.on(({ a, b }) => new Promise((resolve, reject) => { | ||
AsynchronousMultiplier(a, b, (err, result) => { | ||
EventBus.multiply.on( | ||
({ a, b }) => | ||
new Promise((resolve, reject) => { | ||
AsynchronousMultiplier(a, b, (err, result) => { | ||
if (err) { | ||
return reject(err) | ||
return reject(err); | ||
} | ||
resolve(result) | ||
resolve(result); | ||
}); | ||
}) | ||
})) | ||
); | ||
``` | ||
Calls and subscriptions on slots are typechecked | ||
```typescript | ||
@@ -147,21 +153,23 @@ EventBus.multiply({a: 1, c: 2}) // Compile error: property 'c' does not exist on type {a: number, b: number} | ||
const connect = (param) => { | ||
console.log(`Someone somewhere has begun listening to the slot with .on on ${param}.`) | ||
} | ||
console.log( | ||
`Someone somewhere has begun listening to the slot with .on on ${param}.` | ||
); | ||
}; | ||
const disconnect = (param) => { | ||
console.log(`No one is listening to the slot anymore on ${param}.`) | ||
} | ||
console.log(`No one is listening to the slot anymore on ${param}.`); | ||
}; | ||
const disconnectLazy = EventBus.ping.lazy(connect, disconnect) | ||
const disconnectLazy = EventBus.ping.lazy(connect, disconnect); | ||
const unsubscribe = EventBus.ping().on(() => { }) | ||
const unsubscribe = EventBus.ping().on(() => {}); | ||
// console output: 'Someone somewhere has begun listening to the slot with .on on $_DEFAULT_$.' | ||
unsubscribe() | ||
unsubscribe(); | ||
// console output: 'No one is listening to the slot anymore on $_DEFAULT_$.' | ||
const unsubscribe = EventBus.ping().on('parameter', () => { }) | ||
const unsubscribe = EventBus.ping().on("parameter", () => {}); | ||
// console output: 'Someone somewhere has begun listening to the slot with .on on parameter.' | ||
unsubscribe() | ||
unsubscribe(); | ||
// console output: 'No one is listening to the slot anymore on parameter.' | ||
@@ -171,3 +179,3 @@ | ||
// "disconnect" is called one last time if there were subscribers left on the slot. | ||
disconnectLazy() | ||
disconnectLazy(); | ||
``` | ||
@@ -184,21 +192,33 @@ | ||
const MyEvents = { | ||
willWait: slot<string>(), | ||
wontWait: slot<string>({ noBuffer: true }), | ||
} | ||
willWait: slot<string>(), | ||
wontWait: slot<string>({ noBuffer: true }), | ||
}; | ||
``` | ||
### Auto-reconnection | ||
In order to re-establish a lost connection when triggering an event a `Channel` | ||
needs to implement the `autoReconnect` method. | ||
See example: [RuntimeConnect](./examples/channels/RuntimeConnect.ts) | ||
It's also possible to fine tune and deactivate this feature on a per-slot basis : | ||
```typescript | ||
const MyEvents = { | ||
willAutoReconnect: slot<string>(), | ||
wontNotAutoReconnect: slot<string>({ autoReconnect: false }), | ||
}; | ||
``` | ||
### Syntactic sugar | ||
You can combine events from different sources. | ||
```typescript | ||
import { combineEvents } from 'ts-event-bus' | ||
import MyEvents from './MyEvents.ts' | ||
import MyOtherEvents from './MyOtherEvents.ts' | ||
import { combineEvents } from "ts-event-bus"; | ||
import MyEvents from "./MyEvents.ts"; | ||
import MyOtherEvents from "./MyOtherEvents.ts"; | ||
const MyCombinedEvents = combineEvents( | ||
MyEvents, | ||
MyOtherEvents, | ||
) | ||
const MyCombinedEvents = combineEvents(MyEvents, MyOtherEvents); | ||
export default MyCombinedEvents | ||
export default MyCombinedEvents; | ||
``` | ||
@@ -212,48 +232,48 @@ | ||
Basic WebSocket Channel example: | ||
```typescript | ||
import { GenericChannel } from 'ts-event-bus' | ||
import { GenericChannel } from "ts-event-bus"; | ||
export class MyBasicWebSocketChannel extends GenericChannel { | ||
private _ws: WebSocket | null = null | ||
private _host: string | ||
private _ws: WebSocket | null = null; | ||
private _host: string; | ||
constructor(host: string) { | ||
super() | ||
this._host = host | ||
this._init() | ||
} | ||
constructor(host: string) { | ||
super(); | ||
this._host = host; | ||
this._init(); | ||
} | ||
private _init(): void { | ||
const ws = new WebSocket(this._host) | ||
private _init(): void { | ||
const ws = new WebSocket(this._host); | ||
ws.onopen = (e: Event) => { | ||
this._connected() | ||
this._ws = ws | ||
} | ||
ws.onopen = (e: Event) => { | ||
this._connected(); | ||
this._ws = ws; | ||
}; | ||
ws.onerror = (e: Event) => { | ||
this._ws = null | ||
this._error(e) | ||
this._disconnected() | ||
setTimeout(() => { | ||
this._init() | ||
}, 2000) | ||
} | ||
ws.onerror = (e: Event) => { | ||
this._ws = null; | ||
this._error(e); | ||
this._disconnected(); | ||
setTimeout(() => { | ||
this._init(); | ||
}, 2000); | ||
}; | ||
ws.onclose = (e: CloseEvent) => { | ||
if (ws === this._ws) { | ||
this._ws = null | ||
this._disconnected() | ||
this._init() | ||
} | ||
} | ||
ws.onclose = (e: CloseEvent) => { | ||
if (ws === this._ws) { | ||
this._ws = null; | ||
this._disconnected(); | ||
this._init(); | ||
} | ||
}; | ||
ws.onmessage = (e: MessageEvent) => { | ||
this._messageReceived(e.data) | ||
} | ||
} | ||
ws.onmessage = (e: MessageEvent) => { | ||
this._messageReceived(e.data); | ||
}; | ||
} | ||
} | ||
``` | ||
## Examples | ||
@@ -260,0 +280,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
73974
1214
275
15