UNPKG

@aimee-blue/ab-service-kit

Version:
149 lines (112 loc) 3.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildRegistryStateApi = void 0; const detachFromSocketInWatchMode = state => id => { const socketState = state.sockets.get(id); if (!socketState) { return; } const { subscription, waitForCompletion, ...rest } = socketState; if (!subscription) { return; } state.sockets.set(id, rest); // detachFromSocket should only be called in case if we want to unload // previous version of the code from memory subscription.unsubscribe(); if (rest.onDetach === 'disconnect') { closeSocketCore(socketState, 1012); } }; const attachToSocket = state => (id, subscription, waitForCompletion, onDetach) => { const socketState = state.sockets.get(id); if (!socketState) { return; } state.sockets.set(id, { ...socketState, subscription, waitForCompletion, onDetach }); }; const buildTeardown = (state, id) => () => { const socketState = state.sockets.get(id); if (!socketState) { return; } if (socketState.subscription) { socketState.subscription.unsubscribe(); } state.sockets.delete(socketState.id); }; const waitForCompletionThenTeardown = (wait, teardown, logger) => { wait().then(teardown).catch(err => { logger.error('💥 Error while waiting for epic to complete', err); teardown(); }); }; const clientSideCloseHandler = (state, id) => () => { const socketState = state.sockets.get(id); if (!socketState) { return; } if (socketState.ws.closingByKit) { return; } const teardown = buildTeardown(state, id); if (socketState.waitForCompletion) { waitForCompletionThenTeardown(socketState.waitForCompletion, teardown, state.logger); } else { teardown(); } }; const addSocket = state => socketState => { const oldState = state.sockets.get(socketState.id); if (oldState) { state.logger.error('💥 Socket with id already exists', oldState, 'will be replaced with', socketState); } socketState.ws.on('close', clientSideCloseHandler(state, socketState.id)); state.sockets.set(socketState.id, socketState); }; const closeSocketCore = (socketState, code) => { socketState.ws.closingByKit = true; socketState.ws.close(code); }; const closeSocket = state => (id, code) => { const socketState = state.sockets.get(id); if (!socketState) { return; } closeSocketCore(socketState, code); }; const waitForAllToComplete = async (all) => await all.reduce((previous, state) => previous.then(() => state.waitForCompletion ? state.waitForCompletion() : Promise.resolve('completed')), Promise.resolve()); const onServerClose = state => async () => { const all = [...state.sockets.values()]; // close sockets and possibly start teardown/completion process // on the epic handlers: for (const socketState of all) { closeSocketCore(socketState, 1012); } // wait for all the epics to complete: await waitForAllToComplete(all); // cleanup all the data in the state: for (const socketState of all) { if (socketState.subscription) { socketState.subscription.unsubscribe(); } state.sockets.delete(socketState.id); } }; const buildRegistryStateApi = state => { return Object.freeze({ addSocket: addSocket(state), closeSocket: closeSocket(state), detachFromSocketInWatchMode: detachFromSocketInWatchMode(state), attachToSocket: attachToSocket(state), onServerClose: onServerClose(state) }); }; exports.buildRegistryStateApi = buildRegistryStateApi; //# sourceMappingURL=socketRegistryState.js.map