derteberse
Version:
Postgres connection pooler (promise-based)
63 lines (52 loc) • 1.53 kB
JavaScript
const _ = require('lodash');
const escape = require('pg-escape');
module.exports = Listener;
const default_opts = {
poll_interval: 10,
json: true
};
function Listener(derteberse, opts) {
const { poll_interval, json } = _.defaults({}, opts, default_opts);
const con = derteberse.steal();
/* Callback table */
const subs = new Map();
/* Dispatch notifications */
con.then(client => {
client.on('notification', ({ channel, payload }) => {
const cb = subs.get(channel);
if (!cb) {
return;
}
if (json) {
try {
payload = JSON.parse(payload);
} catch (err) {
console.error(`Failed to process notification payload on channel "${channel}": Invalid JSON`);
return;
}
}
cb.forEach(func => process.nextTick(() => func({ channel, payload })));
});
/* Ping for notifications */
const resetTimer = () => setTimeout(() => client.query('select true;', resetTimer), poll_interval);
resetTimer();
});
this.subscribe = (topic, func) => new Promise((res, rej) => {
const cb = subs.get(topic) || new Set();
if (cb.length === 0) {
subs.set(topic, cb);
con.then(client => client.query(escape('listen %I;', topic), err => err ? rej(err) : res()));
}
cb.add(func);
});
this.function = (topic, func) => new Promise((res, rej) => {
const cb = subs.get(topic);
if (!cb || !cb.delete(func)) {
return;
}
if (cb.size === 0) {
subs.delete(topic);
con.then(client => client.query(escape('unlisten %I;', topic), err => err ? rej(err) : res()));
}
});
}