@aimee-blue/ab-service-kit
Version:
Aimee Blue Service Template
149 lines (112 loc) • 3.6 kB
JavaScript
;
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