Skip to content

Commit

Permalink
Merge pull request #7 from kabirbaidhya/config-separation
Browse files Browse the repository at this point in the history
Separate connection configurations to separate config files
  • Loading branch information
kabirbaidhya authored Aug 2, 2016
2 parents 3982b73 + 906b16a commit b9198d2
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 76 deletions.
13 changes: 11 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"presets": ["es2015"],
"plugins": []
"presets": [
"es2015"
],
"plugins": [
[
"transform-es2015-for-of",
{
"loose": true
}
]
]
}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dist/
node_modules
.pglistend.yml
.pglistend*.yml
*.log
15 changes: 15 additions & 0 deletions .pglistend-connection.yml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# database connection
connection:
database: DATABASE_NAME
user: YOUR_USERNAME
password: PASSWORD
port: 5432
max: 2

# channels to LISTEN to
channels: [CHANNEL_1, CHANNEL_2]

# list of listener scripts to be included
scripts:
- /path/to/listener/script.js
# - path/to/another/listener-script.js
12 changes: 12 additions & 0 deletions .pglistend.yml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
default:
connection:
host: localhost
port: 5432
max: 2
idleTimeoutMillis: 10000

# Include configuration files database connections you want to use
connections:
- /path/to/.pglistend-connection.yml
- /path/to/another/.pglistend-connection.yml

1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,4 @@ Check [this](https://www.digitalocean.com/community/tutorials/how-to-use-journal
6. From terminal in root directory, run: `npm start`. You can see the logs in terminal as the channels hit the queries when the `notify` operation is called on.

## TODOs
* Multiple database support as right now it supports single database only.
* Delegate CPU-intensive tasks (mostly queries) to separate thread or message queue most likely. [Here's why](http://stackoverflow.com/questions/3491811/node-js-and-cpu-intensive-requests/3536183#answer-3491931)
35 changes: 0 additions & 35 deletions config.yml.sample

This file was deleted.

11 changes: 11 additions & 0 deletions listener.js.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = function(h) {
return {
'channel_1': function(payload) {
// Do something
},

'channel_2': function(payload) {
// Do something
}
};
};
21 changes: 0 additions & 21 deletions listener.js.sample

This file was deleted.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"dependencies": {
"chalk": "^1.1.3",
"commander": "^2.9.0",
"deep-assign": "^2.0.0",
"es6-shim": "^0.35.1",
"lodash.debounce": "^4.0.6",
"lodash.throttle": "^4.0.1",
Expand All @@ -38,6 +39,7 @@
"babel-cli": "^6.10.1",
"babel-eslint": "^5.0.0",
"babel-preset-es2015": "^6.9.0",
"babel-plugin-transform-es2015-for-of": "^6.8.0",
"eslint": "2.2.0",
"nodemon": "^1.9.2"
},
Expand All @@ -48,6 +50,9 @@
"files": [
"bin/",
"dist/",
"setup"
"setup",
".pglistend.yml.dist",
".pglistend-connection.yml.dist",
"listener.js.dist"
]
}
29 changes: 25 additions & 4 deletions setup/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@

# Configuration file template
CONFIG_TEMPLATE = '''
default:
connection:
host: localhost
port: 5432
max: 2
idleTimeoutMillis: 10000
# Include configuration files database connections you want to use
connections:
# - path/to/connection-config.yml
'''

# Connection config file template
CONNECTION_CONFIG_TEMPLATE = '''
# Change the following configuration parameters according to your need.
# postgresql connection
Expand All @@ -57,11 +71,18 @@
DEFAULT_LISTENER_TEMPLATE = '''
// Here you can define handlers for each of the channels
// that are being LISTENed.
module.exports = {
// 'boom': function(payload) {
// console.log('Received notification on channel "boom"', payload);
// }
module.exports = function(h) {
return {
'channel_1': function(payload) {
// Do something
},
'channel_2': function(payload) {
// Do something
}
};
};
'''

# Constants
Expand Down
11 changes: 7 additions & 4 deletions src/Listener.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Client, Pool} from 'pg';
import {format} from 'util';
import {yellow, green, red, dim} from 'chalk';

import {halt} from './program';
import {log, error} from './util';

import * as msg from './messages/common';

class Listener {
Expand Down Expand Up @@ -58,14 +58,15 @@ class Listener {
}

// TODO: Delegate CPU-intensive jobs to a task queue or a separate process.

handlers.forEach(callback => callback(payload));
}

handle(notification) {
const database = this.client.database;
const {channel, payload: str} = notification;

log(msg.RECEIVED_NOTIFICATION, green(channel), dim(str || '(empty)'));
log(msg.RECEIVED_NOTIFICATION, green(database + ':' + channel), dim(str || '(empty)'));

try {
const payload = this.parsePayload(str);
Expand All @@ -78,8 +79,10 @@ class Listener {
}

listenTo(channel) {
const database = this.client.database;

this.client.query(`LISTEN ${channel}`).then(() => {
log(msg.STARTED_LISTENING, green(channel));
log(msg.STARTED_LISTENING, green(database + ':' + channel));

// Warn if handlers are not registered for the channels being listened to
if (!Array.isArray(this.handlers[channel])) {
Expand Down
5 changes: 4 additions & 1 deletion src/messages/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ export const RECEIVED_NOTIFICATION = 'Received notification on channel %s: %s';
export const DATABASE_CONNECTED = 'Connected to database %s';
export const STARTED_LISTENING = 'Started listening to channel %s';
export const SETUP_ERROR = 'Setup could not be completed.';
export const GENERIC_ERROR_MESSAGE = 'An error occurred.';
export const GENERIC_ERROR_MESSAGE = 'An error occurred.';
export const LOADED_CONFIG_FILE = 'Loaded configuration file: %s';
export const ERROR_LOADING_CONFIG_FILE = 'Error loading configuration file: %s';
export const NO_CONNECTIONS_CONFIGURED = 'No database connections are configured. Please do configure properly and start pglistend again.';
11 changes: 7 additions & 4 deletions src/program.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function run() {
.description('pglisten - Postgres LISTEN CLI tool')
.usage('--config=<path>')
.option('-c, --config <path>', 'Configuration file to use');

prog.command('setup-daemon')
.description('Setup pglistend service on this system')
.option('-C, --configure', 'Configure the daemon during setup')
Expand All @@ -43,9 +43,12 @@ export function halt(err) {
function listen(args) {
let config = resolveConfig(args.config);

for (let i = 0; i < config.connections.length; i++) {
let configuration = config.connections[i];
let listener = new Listener(configuration, resolveHandlers(configuration));
if (config.connections.length === 0) {
throw new Error(msg.NO_CONNECTIONS_CONFIGURED);
}

for (let connection of config.connections) {
let listener = new Listener(connection, resolveHandlers(connection));

listener.listen();
}
Expand Down
30 changes: 28 additions & 2 deletions src/resolver.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import {Pool} from 'pg';
import Yaml from 'yamljs';
import {yellow} from 'chalk';
import deepAssign from 'deep-assign';

import query from './query';
import {Pool} from 'pg';
import {log, error} from './util';
import {throttle, debounce} from './util';
import {isObject, isFunction} from './util';
import * as msg from './messages/common';

export function resolveConfig(file) {
return Yaml.load(file);
let config = loadConfig(file);

config.connections = resolveConnections(config.connections, config.default);

return config;
}

function resolveConnections(files, defaults = {}) {
if (!Array.isArray(files)) return [];

return files.map(path => deepAssign({}, loadConfig(path), defaults));
}

function loadConfig(file) {
try {
let config = Yaml.load(file);

log(msg.LOADED_CONFIG_FILE, yellow(file));
return config;
} catch (e) {
error(msg.ERROR_LOADING_CONFIG_FILE, file);
throw e;
}
}

export function resolveHandlers(config) {
Expand Down

0 comments on commit b9198d2

Please sign in to comment.