Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate connection configurations to separate config files #7

Merged
merged 5 commits into from
Aug 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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