@coko/server
Version:
Reusable server for use by Coko's projects
119 lines • 4.13 kB
JavaScript
;
/**
* 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