Initial commit v0.1.0

development
arkancrow 2017-05-07 16:42:18 +02:00
parent d8e6bcfe32
commit 19d3c5927d
4 changed files with 325 additions and 0 deletions

View File

@ -1,2 +1,63 @@
# node-red-contrib-postgres-listen
A Node-RED node to listen to pg_notify
Install
-------
Run the following command in the root directory of your Node-RED install
npm install node-red-contrib-postgres-listen
Overview
-------
This add-on, allows to listen to PostgreSQL [pg_notify](https://www.postgresql.org/docs/9.0/static/sql-notify.html) mechanism.
The node takes two parameters :
- postgresdb : The PostgreSQL connection configuration
- channel : The channel name specified in the pg_notify command
PostgreSQL sample code
----------------------
1. Create a base table:
CREATE TABLE realtime
(
id INTEGER DEFAULT nextval('realtime_id_seq'::regclass) NOT NULL,
title CHARACTER VARYING(128),
PRIMARY KEY (id)
);
2. Create a trigger on the table:
CREATE TRIGGER "updated_realtime_trigger"
BEFORE INSERT OR DELETE OR UPDATE ON realtime
FOR EACH ROW
EXECUTE PROCEDURE notify_realtime()
3. Create a trigger function:
CREATE FUNCTION public.notify_realtime()
RETURNS trigger
LANGUAGE 'plpgsql'
COST 100.0
VOLATILE NOT LEAKPROOF
AS $BODY$
BEGIN
PERFORM pg_notify('addedrecord', '' || row_to_json(NEW));
RETURN NEW;
END;
$BODY$;
Result
------
The node will produce a message like that :
{"name":"notification","length":47,"processId":16147,"channel":"addedrecord","payload":{"id":2,"title":"plopcsd"}}
All fields are generated by Postgres with *payload* being the content of the table row.

28
package.json 100644
View File

@ -0,0 +1,28 @@
{
"name": "node-red-contrib-postgres-listen",
"version": "0.1.0",
"description": "A Node-RED node to listen to pg_notify",
"dependencies": {
"pg": "6.1.5"
},
"repository": {
"type": "git",
"url": "https://github.com/arkancrow/node-red-contrib-postgres-listen"
},
"license": "Apache-2.0",
"keywords": [
"node-red",
"postgres",
"postgresql",
"pg_notify"
],
"node-red": {
"nodes": {
"PostgreSQLListen": "pglisten.js"
}
},
"author": {
"name": "Vincent Schoonenburg",
"email": "arkancrow@gmail.com"
}
}

113
pglisten.html 100644
View File

@ -0,0 +1,113 @@
<!--
Copyright 2017 Vincent Schoonenburg.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-template-name="postgresdb">
<p>Connection can be set up by either defining a full or partial connection string, or specific connection parameters</p>
<div class="form-row">
<label for="node-config-input-connectionstring"><i class="fa fa-bookmark"></i> Connection String</label>
<input class="input-append-left" type="text" id="node-config-input-connectionstring" >
</div>
<div class="form-row">
<label for="node-config-input-hostname"><i class="fa fa-bookmark"></i> Host</label>
<input class="input-append-left" type="text" id="node-config-input-hostname" placeholder="localhost" style="width: 40%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>
<input type="text" id="node-config-input-port" placeholder="5432" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-db"><i class="fa fa-briefcase"></i> Database</label>
<input type="text" id="node-config-input-db" placeholder="test">
</div>
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> Username</label>
<input type="text" id="node-config-input-user" placeholder="postgres">
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
<input type="password" id="node-config-input-password" placeholder="postgres">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-config-input-ssl" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-ssl" style="width: 70%;">Use SSL</label>
</div>
</script>
<script type="text/javascript">
(function() {
RED.nodes.registerType('postgresdb',{
category: 'config',
color:"rgb(218, 196, 180)",
defaults: {
connectionstring : {value:""},
hostname: { value:"localhost"},
port: { value: 5432},
db: { value:"postgres"},
ssl: { value:false }
},
credentials: {
user: {type: "text"},
password: {type: "password"}
},
label: function() {
return this.name|| this.connectionstring || this.hostname+":"+this.port+"/"+this.db;
}
});
})();
</script>
<script type="text/x-red" data-template-name="PG Listen">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-channel"><i class="fa fa-tag"></i> Channel name</label>
<input type="text" id="node-input-channel" placeholder="Channel name">
</div>
<div class="form-row">
<label for="node-input-postgresdb"><i class="fa fa-tag"></i> Server</label>
<input type="text" id="node-input-postgresdb">
</div>
</script>
<script type="text/x-red" data-help-name="PG Listen">
<p>A PostgreSql pg_notify LISTEN node. </p>
<p></p>
<p></p>
</script>
<script type="text/javascript">
(function() {
RED.nodes.registerType('PG Listen',{
category: 'storage-input',
color:"rgb(148, 226, 252)",
defaults: {
postgresdb: { type:"postgresdb",required:true},
name: {value:""},
channel: { value:"", required : true }
},
inputs: 0,
outputs: 1,
icon: "postgres.png",
align: "right",
label: function() {
return this.name||(this.sqlquery?this.sqlquery:"postgres");
}
});
})();
</script>

123
pglisten.js 100644
View File

@ -0,0 +1,123 @@
/**
* Copyright 2017 Vincent Schoonenburg.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
module.exports = function(RED) {
var pg = require('pg');
function Notify(n) {
RED.nodes.createNode(this,n);
this.postgresdb = n.postgresdb;
this.postgresConfig = RED.nodes.getNode(this.postgresdb);
this.channel = n.channel;
console.log(this.channel);
var node = this;
var clientdb = null;
this.status({fill:"red",shape:"ring",text:"disconnected"});
if(this.postgresConfig) {
try {
var config = {};
if (node.postgresConfig.connectionString) {
config = node.postgresConfig.connectionString
} else {
if (node.postgresConfig.user) { config.user = node.postgresConfig.user; }
if (node.postgresConfig.password) { config.password = node.postgresConfig.password; }
if (node.postgresConfig.hostname) { config.host = node.postgresConfig.hostname; }
if (node.postgresConfig.port) { config.port = node.postgresConfig.port; }
if (node.postgresConfig.db) { config.database = node.postgresConfig.db; }
config.ssl = node.postgresConfig.ssl;
}
clientdb = new pg.Client(config);
clientdb.connect(function(err) {
try {
if(err) {
console.log(err);
node.error(err);
} else {
console.log("Connected");
node.status({fill:"green",shape:"dot",text:"connected"});
clientdb.on('notification', function(msg) {
console.log("Notification received");
msg.payload = JSON.parse(msg.payload);
node.log(JSON.stringify(msg));
node.send(msg);
});
var query = "LISTEN " + node.channel;
clientdb.query(query);
console.log("Listening to :" + node.channel);
}
} catch (error) {
node.error(error);
}
});
} catch (err) {
node.error(err);
}
} else {
this.error("missing postgres configuration");
}
this.on("close", function() {
if(node.clientdb) node.clientdb.end();
});
}
function PostgresDatabaseNode(n) {
RED.nodes.createNode(this,n);
this.hostname = n.hostname;
this.port = n.port;
this.db = n.db;
this.ssl = n.ssl;
this.connectionString = n.connectionstring;
var credentials = this.credentials;
if (credentials) {
this.user = credentials.user;
this.password = credentials.password;
}
}
function PostgresArrayNode(n) {
RED.nodes.createNode(this,n);
try {
this.columns = JSON.parse(n.columns);
} catch (e) {
node.error(e.message);
this.columns = [];
}
}
try {
RED.nodes.registerType("postgresdb",PostgresDatabaseNode,{
credentials: {
user: {type:"text"},
password: {type: "password"}
}
});
RED.nodes.registerType("postgresarray",PostgresArrayNode);
} catch (e) {
}
RED.nodes.registerType("PG Listen",Notify);
};