UNPKG

@coko/server

Version:

Reusable server for use by Coko's projects

119 lines 4.13 kB
"use strict"; /** * Code starting point (though modified for typescript) courtesy of the authors in this repo: * https://github.com/GraphQLCollege/graphql-postgres-subscriptions/blob/master/postgres-pubsub.js * * Repo seems abandoned, so moved here to be able to keep dependencies up to date. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const graphql_subscriptions_1 = require("graphql-subscriptions"); const pg_1 = require("pg"); const pg_ipc_1 = __importDefault(require("pg-ipc")); const defaultCommonMessageHandler = (message) => message; function eventEmitterAsyncIterator(eventEmitter, eventsNames, commonMessageHandler) { const pullQueue = []; const pushQueue = []; const eventsArray = typeof eventsNames === 'string' ? [eventsNames] : eventsNames; let listening = true; const pushValue = ({ payload: event }) => { const value = commonMessageHandler(event); if (pullQueue.length !== 0) { pullQueue.shift()({ value, done: false }); } else { pushQueue.push(value); } }; const pullValue = () => { return new Promise(resolve => { if (pushQueue.length !== 0) { resolve({ value: pushQueue.shift(), done: false }); } else { pullQueue.push(resolve); } }); }; const emptyQueue = () => { if (listening) { listening = false; removeEventListeners(); pullQueue.forEach(resolve => resolve({ value: undefined, done: true })); pullQueue.length = 0; pushQueue.length = 0; } }; const addEventListeners = () => { for (const eventName of eventsArray) { eventEmitter.addListener(eventName, pushValue); } }; const removeEventListeners = () => { for (const eventName of eventsArray) { eventEmitter.removeListener(eventName, pushValue); } }; addEventListeners(); return { next() { return listening ? pullValue() : this.return(); }, return() { emptyQueue(); return Promise.resolve({ value: undefined, done: true }); }, throw(error) { emptyQueue(); return Promise.reject(error); }, /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ [Symbol.asyncIterator]() { return this; }, }; } class PostgresPubSub extends graphql_subscriptions_1.PubSubEngine { client; ee; subscriptions; subIdCounter; commonMessageHandler = defaultCommonMessageHandler; constructor(options = {}) { super(); this.subscriptions = {}; this.subIdCounter = 0; const { client, ...pgOptions } = options; this.client = client || new pg_1.Client(pgOptions); if (!client) this.client.connect(); this.ee = new pg_ipc_1.default(this.client); } publish(triggerName, payload) { this.ee.notify(triggerName, payload); return Promise.resolve(); } subscribe(triggerName, onMessage) { const callback = (message) => { onMessage(message instanceof Error ? message : this.commonMessageHandler(message.payload)); }; this.ee.on(triggerName, callback); this.subIdCounter += 1; this.subscriptions[this.subIdCounter] = [triggerName, callback]; return Promise.resolve(this.subIdCounter); } unsubscribe(subId) { const [triggerName, onMessage] = this.subscriptions[subId]; delete this.subscriptions[subId]; this.ee.removeListener(triggerName, onMessage); } asyncIterator(triggers) { return eventEmitterAsyncIterator(this.ee, triggers, this.commonMessageHandler); } } exports.default = PostgresPubSub; //# sourceMappingURL=PostgresPubSub.js.map