UNPKG

hamok

Version:

Lightweight Distributed Object Storage on RAFT consensus algorithm

186 lines (150 loc) 6.96 kB
import { Hamok, HamokConfig, HamokEmitter, setHamokLogLevel } from 'hamok'; import * as pino from 'pino'; import { HamokMessageHub } from './utils/HamokMessageHub'; const logger = pino.pino({ name: 'emitter-example', level: 'debug', }); type ExampleEventMap = { 'simple-request': [requestId: string, { 'param-1': number, }], 'complex-request': [requestId: string, { 'param-1': number, 'param-2': string, }], 'response': [requestId: string, payload?: unknown, error?: string], } type PendingRequest<T> = { requestId: string, timer: ReturnType<typeof setTimeout>, resolve: (value: T) => void, reject: (reason: string) => void, } function createResponseHandler(hamok: Hamok<{requests: Map<string, PendingRequest<any>>}>) { return (requestId: string, payload?: unknown, error?: string) => { const pendingRequest = hamok.appData.requests.get(requestId); logger.debug('Response received by server (%s). requestId: %s, payload: %o, error: %o. do we have this request?: %s', hamok.localPeerId, requestId, payload, error, Boolean(pendingRequest)); if (pendingRequest) { clearTimeout(pendingRequest.timer); hamok.appData.requests.delete(requestId); if (error) { pendingRequest.reject(error); } else { pendingRequest.resolve(payload); } } } } function createRequest<K extends keyof ExampleEventMap>(requests: Map<string, PendingRequest<any>>, emitter: HamokEmitter<ExampleEventMap>, event: K, payload: ExampleEventMap[K][1]): Promise<number> { const requestId = Math.random().toString(36).substring(7); return new Promise((resolve, reject) => { const timer = setTimeout(() => { reject('Request timeout. event: ' + event + ', payload: ' + JSON.stringify(payload)); }, 5000); requests.set(requestId, { requestId, timer, resolve, reject }); logger.debug('Request sent by server (%s). requestId: %s, event: %s, payload: %o', emitter.connection.localPeerId, requestId, event, payload); emitter.notify(event, requestId as any, payload as any); }); } export async function run() { const server_1 = new Hamok<{ requests: Map<string, PendingRequest<any>> }>({ peerId: 'server_1', appData: { requests: new Map(), }, onlyFollower: true, }); const server_2 = new Hamok<{ requests: Map<string, PendingRequest<any>> }>({ peerId: 'server_2', appData: { requests: new Map(), }, }); const server_3 = new Hamok<{ requests: Map<string, PendingRequest<any>> }>({ peerId: 'server_3', appData: { requests: new Map(), }, onlyFollower: true, }); const messageHub = new HamokMessageHub(); messageHub.add(server_1, server_2, server_3); await Promise.all([ server_1.join(), server_2.join(), server_3.join(), ]); logger.info('Servers are joined'); const emitter_1 = server_1.createEmitter<ExampleEventMap>({ emitterId: 'my-distributed-emitter', }); const emitter_2 = server_2.createEmitter<ExampleEventMap>({ emitterId: 'my-distributed-emitter', }); const emitter_3 = server_3.createEmitter<ExampleEventMap>({ emitterId: 'my-distributed-emitter', }); (emitter_1.subscriptions as any).on('debug', (log: any) => { logger.debug('Log received by server_1: %o', log); }) emitter_1.subscriptions.on('added', (event, peerId, metaData) => { logger.debug('On server_1 (%s) peer %s subscribed to event %s, metaData: %o. peers on event: %o', server_1.localPeerId, peerId, event, metaData, [...(emitter_1.subscriptions.getEventPeersMap(event) ?? [])]); }); emitter_2.subscriptions.on('added', (event, peerId, metaData) => { logger.debug('On server_2 (%s) peer %s subscribed to event %s, metaData: %o. peers on event: %o', server_2.localPeerId, peerId, event, metaData, [...(emitter_2.subscriptions.getEventPeersMap(event) ?? [])]); }); emitter_3.subscriptions.on('added', (event, peerId, metaData) => { logger.debug('On server_3 (%s) peer %s subscribed to event %s, metaData: %o. peers on event: %o', server_3.localPeerId, peerId, event, metaData, [...(emitter_3.subscriptions.getEventPeersMap(event) ?? [])]); }); emitter_1.subscriptions.on('removed', (event, peerId, metaData) => { logger.debug('On server_1 (%s) peer %s unsubscribed from event %s, metaData: %o, peers on event: %o', server_1.localPeerId, peerId, event, metaData, [...(emitter_1.subscriptions.getEventPeersMap(event) ?? [])]); }); emitter_2.subscriptions.on('removed', (event, peerId, metaData) => { logger.debug('On server_2 (%s) peer %s unsubscribed from event %s, metaData: %o, peers on event: %o', server_2.localPeerId, peerId, event, metaData, [...(emitter_2.subscriptions.getEventPeersMap(event) ?? [])]); }); emitter_3.subscriptions.on('removed', (event, peerId, metaData) => { logger.debug('On server_3 (%s) peer %s unsubscribed from event %s, metaData: %o, peers on event: %o', server_3.localPeerId, peerId, event, metaData, [...(emitter_3.subscriptions.getEventPeersMap(event) ?? [])]); }); await emitter_1.subscribe('simple-request', (requestId, { 'param-1': param1 }) => { logger.debug('Simple request received by server_1: %s, %s, %s', requestId, param1); emitter_1.notify('response', requestId, 10); }); await emitter_2.subscribe('complex-request', (requestId, { 'param-1': param1, 'param-2': param2 }) => { logger.debug('Complex request received by server_2: %s, %s, %s', requestId, param1, param2); if (10 < param1) { emitter_2.notify('response', requestId, 20); } }); await emitter_1.subscribe('complex-request', (requestId, { 'param-1': param1, 'param-2': param2 }) => { logger.debug('Complex request received by server_1: %s, %s, %s', requestId, param1, param2); if (param1 < 10) { emitter_1.notify('response', requestId, 10); } }); await emitter_1.subscribe('response', createResponseHandler(server_1)); await emitter_2.subscribe('response', createResponseHandler(server_2)); await emitter_3.subscribe('response', createResponseHandler(server_3)); await emitter_1.ready; await emitter_2.ready; await emitter_3.ready; const request_1 = createRequest(server_1.appData.requests, emitter_1, 'simple-request', { 'param-1': 5 }) const request_2 = createRequest(server_2.appData.requests, emitter_2, 'complex-request', { 'param-1': 9, 'param-2': 'test' }) const request_3 = createRequest(server_2.appData.requests, emitter_2, 'complex-request', { 'param-1': 20, 'param-2': 'test' }) logger.info('Response for server : %d', await request_1); logger.info('Response for server : %d', await request_2); logger.info('Response for server : %d', await request_3); messageHub.remove(server_1); logger.info('We wait 10s') await new Promise(resolve => setTimeout(resolve, 10000)); logger.info('We wait 10s') await new Promise(resolve => setTimeout(resolve, 10000)); logger.info('we also add some listeners to server_2 to trigger the expiration of logs'); server_1.close(); server_2.close(); } if (require.main === module) { logger.info('Running from module file'); setHamokLogLevel('info'); run(); }