From 2fe859b1117d8087d55eeba1c2bd124d5db353a1 Mon Sep 17 00:00:00 2001 From: Scott Yoshizawa Date: Sun, 10 May 2015 15:47:22 -0500 Subject: [PATCH] NLS Core nodes NLS exec node NLS function/temple/delay nodes NLS function/template/delay/trigger/comment nodes NLS io nodes (mqtt/httpin/websocket/watch/serial) NLS messages.json for tcpin NLS io nodes (tcpin & udp half) NLS io nodes (udp) NLS logic nodes (switch/change) NLS logic (range) and parsers (csv&html) nodes NLS parser nodes (json/xml) NLS test case update for logic/parsers NLS analysis and hardware nodes NLS storage nodes (file/redisout/mongodb) and test NLS storage node (tail) NLS social nodes (feedparse/email/irc) NLS socal node (twitter half change) NLS social node (twitter) and core node (unknown) --- nodes/core/analysis/72-sentiment.html | 6 +- nodes/core/core/20-inject.html | 6 +- nodes/core/core/25-catch.html | 6 +- nodes/core/core/58-debug.html | 16 +- nodes/core/core/75-exec.html | 16 +- nodes/core/core/75-exec.js | 4 +- nodes/core/core/80-function.html | 10 +- nodes/core/core/80-template.html | 8 +- nodes/core/core/89-delay.html | 60 +- nodes/core/core/89-delay.js | 2 +- nodes/core/core/89-trigger.html | 138 ++--- nodes/core/core/90-comment.html | 12 +- nodes/core/core/98-unknown.html | 7 +- nodes/core/hardware/36-rpi-gpio.html | 90 +-- nodes/core/hardware/36-rpi-gpio.js | 80 +-- nodes/core/io/10-mqtt.html | 44 +- nodes/core/io/10-mqtt.js | 24 +- nodes/core/io/21-httpin.html | 50 +- nodes/core/io/21-httpin.js | 14 +- nodes/core/io/22-websocket.html | 556 +++++++++-------- nodes/core/io/22-websocket.js | 466 +++++++------- nodes/core/io/23-watch.html | 10 +- nodes/core/io/31-tcpin.html | 83 ++- nodes/core/io/31-tcpin.js | 78 ++- nodes/core/io/32-udp.html | 136 ++-- nodes/core/io/32-udp.js | 38 +- nodes/core/locales/en-US/messages.json | 791 +++++++++++++++++++++++- nodes/core/logic/10-switch.html | 12 +- nodes/core/logic/15-change.html | 25 +- nodes/core/logic/15-change.js | 2 +- nodes/core/logic/16-range.html | 30 +- nodes/core/logic/16-range.js | 2 +- nodes/core/parsers/70-CSV.html | 50 +- nodes/core/parsers/70-CSV.js | 2 +- nodes/core/parsers/70-HTML.html | 24 +- nodes/core/parsers/70-JSON.html | 4 +- nodes/core/parsers/70-JSON.js | 4 +- nodes/core/parsers/70-XML.html | 44 +- nodes/core/parsers/70-XML.js | 2 +- nodes/core/storage/28-tail.html | 10 +- nodes/core/storage/28-tail.js | 2 +- nodes/core/storage/50-file.html | 38 +- nodes/core/storage/50-file.js | 24 +- test/nodes/core/io/22-websocket_spec.js | 4 +- test/nodes/core/logic/16-range_spec.js | 2 +- test/nodes/core/parsers/70-CSV_spec.js | 4 +- test/nodes/core/parsers/70-JSON_spec.js | 8 +- test/nodes/core/parsers/70-XML_spec.js | 2 +- test/nodes/core/storage/50-file_spec.js | 16 +- 49 files changed, 1903 insertions(+), 1159 deletions(-) diff --git a/nodes/core/analysis/72-sentiment.html b/nodes/core/analysis/72-sentiment.html index c33b873bb..78a6ee024 100644 --- a/nodes/core/analysis/72-sentiment.html +++ b/nodes/core/analysis/72-sentiment.html @@ -16,8 +16,8 @@ @@ -40,7 +40,7 @@ outputs:1, icon: "arrow-in.png", label: function() { - return this.name||"sentiment"; + return this.name||this._("sentiment.label.sentimentlabel"); }, labelStyle: function() { return this.name?"node_label_italic":""; diff --git a/nodes/core/core/20-inject.html b/nodes/core/core/20-inject.html index c1a1c0dcd..19ff73597 100644 --- a/nodes/core/core/20-inject.html +++ b/nodes/core/core/20-inject.html @@ -19,8 +19,8 @@ @@ -122,7 +122,7 @@
- +
diff --git a/nodes/core/core/25-catch.html b/nodes/core/core/25-catch.html index c6eed933f..ffc28e3db 100644 --- a/nodes/core/core/25-catch.html +++ b/nodes/core/core/25-catch.html @@ -16,8 +16,8 @@ diff --git a/nodes/core/core/75-exec.html b/nodes/core/core/75-exec.html index 731656802..34b499045 100644 --- a/nodes/core/core/75-exec.html +++ b/nodes/core/core/75-exec.html @@ -16,28 +16,28 @@ diff --git a/nodes/core/core/89-delay.html b/nodes/core/core/89-delay.html index 91de21669..44aa08790 100644 --- a/nodes/core/core/89-delay.html +++ b/nodes/core/core/89-delay.html @@ -18,58 +18,58 @@ @@ -109,16 +109,16 @@ if (this.pauseType == "delay") { var units = this.timeoutUnits ? this.timeoutUnits.charAt(0) : "s"; if (this.timeoutUnits == "milliseconds") { units = "ms"; } - return this.name||"delay "+this.timeout+" " + units; + return this.name||this._("delay.delaylabel")+" "+this.timeout+" " + units; } else if (this.pauseType == "rate") { var units = this.rateUnits ? this.rateUnits.charAt(0) : "s"; - return this.name||"limit "+this.rate+" msg/"+ units; + return this.name||this._("delay.limitlabel")+" "+this.rate+" "+this._("delay.msgperlabel")+ units; } else if (this.pauseType == "random") { - return this.name || "random"; + return this.name || this._("delay.randomlabel"); } else { var units = this.rateUnits ? this.rateUnits.charAt(0) : "s"; - return this.name || "queue" +this.rate+" msg/"+ units; + return this.name || this._("delay.queuelabel") +this.rate+" "+this._("delay.msgperlabel")+ units; } }, labelStyle: function() { // sets the class to apply to the label diff --git a/nodes/core/core/89-delay.js b/nodes/core/core/89-delay.js index 4c1710f69..9f7e685dc 100644 --- a/nodes/core/core/89-delay.js +++ b/nodes/core/core/89-delay.js @@ -104,7 +104,7 @@ module.exports = function(RED) { node.status({text:node.buffer.length}); } if (node.buffer.length > 1000) { - node.warn(this.name + " buffer exceeded 1000 messages"); + node.warn(this.name + " " + RED._("delay.buffererr")); } } else { node.send(msg); diff --git a/nodes/core/core/89-trigger.html b/nodes/core/core/89-trigger.html index 0bd4983f8..70f3a85c6 100644 --- a/nodes/core/core/89-trigger.html +++ b/nodes/core/core/89-trigger.html @@ -1,5 +1,5 @@ +
+ diff --git a/nodes/core/core/90-comment.html b/nodes/core/core/90-comment.html index f8c08fdd1..785a34a2a 100644 --- a/nodes/core/core/90-comment.html +++ b/nodes/core/core/90-comment.html @@ -16,17 +16,17 @@ @@ -341,10 +349,10 @@ outputs:1, icon: "rpi.png", label: function() { - var na = "Pi Mouse"; - if (this.butt === "1") { na += " Left"; } - if (this.butt === "2") { na += " Right"; } - if (this.butt === "4") { na += " Middle"; } + var na = this._("rpi-gpio.label.pimouse"); + if (this.butt === "1") { na += " "+this._("rpi-gpio.label.left"); } + if (this.butt === "2") { na += " "+this._("rpi-gpio.label.right"); } + if (this.butt === "4") { na += " "+this._("rpi-gpio.label.middle"); } return this.name||na; }, labelStyle: function() { diff --git a/nodes/core/hardware/36-rpi-gpio.js b/nodes/core/hardware/36-rpi-gpio.js index 5673f015c..ddd477c80 100644 --- a/nodes/core/hardware/36-rpi-gpio.js +++ b/nodes/core/hardware/36-rpi-gpio.js @@ -23,25 +23,25 @@ module.exports = function(RED) { var gpioCommand = __dirname+'/nrgpio'; if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi - //RED.log.info("Ignoring Raspberry Pi specific node."); - throw "Info : Ignoring Raspberry Pi specific node."; + //RED.log.info(RED._("rpi-gpio.errors.ignorenode")); + throw "Info : "+RED._("rpi-gpio.errors.ignorenode"); } if (!fs.existsSync("/usr/share/doc/python-rpi.gpio")) { - RED.log.warn("Can't find Pi RPi.GPIO python library."); - throw "Warning : Can't find Pi RPi.GPIO python library."; + RED.log.warn(RED._("rpi-gpio.errors.libnotfound")); + throw "Warning : "+RED._("rpi-gpio.errors.libnotfound"); } if ( !(1 & parseInt ((fs.statSync(gpioCommand).mode & parseInt ("777", 8)).toString (8)[0]) )) { - RED.log.error(gpioCommand+" needs to be executable."); - throw "Error : nrgpio must to be executable."; + RED.log.error(gpioCommand+" "+RED._("rpi-gpio.errors.needtobeexecutable")); + throw "Error : "+RED._("rpi-gpio.errors.mustbeexecutable"); } // the magic to make python print stuff immediately process.env.PYTHONUNBUFFERED = 1; var pinsInUse = {}; - var pinTypes = {"out":"digital output", "tri":"input", "up":"input with pull up", "down":"input with pull down", "pwm":"PWM output"}; + var pinTypes = {"out":RED._("rpi-gpio.errors.digout"), "tri":RED._("rpi-gpio.errors.input"), "up":RED._("rpi-gpio.errors.pullup"), "down":RED._("rpi-gpio.errors.pulldown"), "pwm":RED._("rpi-gpio.errors.pwmout")}; function GPIOInNode(n) { RED.nodes.createNode(this,n); @@ -56,7 +56,7 @@ module.exports = function(RED) { } else { if ((pinsInUse[this.pin] !== this.intype)||(pinsInUse[this.pin] === "pwm")) { - node.warn("GPIO pin "+this.pin+" already set as "+pinTypes[pinsInUse[this.pin]]); + node.warn(RED._("rpi-gpio.errors.gpiopin")+" "+this.pin+" "+RED._("rpi-gpio.errors.alreadyset")+" "+pinTypes[pinsInUse[this.pin]]); } } @@ -67,7 +67,7 @@ module.exports = function(RED) { node.child = spawn(gpioCommand, ["in",node.pin,node.intype]); } node.running = true; - node.status({fill:"green",shape:"dot",text:"OK"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.ok")}); node.child.stdout.on('data', function (data) { data = data.toString().trim(); @@ -88,27 +88,27 @@ module.exports = function(RED) { node.child.on('close', function (code) { node.child = null; node.running = false; - if (RED.settings.verbose) { node.log("closed"); } + if (RED.settings.verbose) { node.log(RED._("rpi-gpio.errors.closed")); } if (node.done) { - node.status({fill:"grey",shape:"ring",text:"closed"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.closed")}); node.done(); } - else { node.status({fill:"red",shape:"ring",text:"stopped"}); } + else { node.status({fill:"red",shape:"ring",text:RED._("common.status.stopped")}); } }); node.child.on('error', function (err) { - if (err.errno === "ENOENT") { node.error('nrgpio command not found'); } - else if (err.errno === "EACCES") { node.error('nrgpio command not executable'); } - else { node.error('error: ' + err.errno); } + if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); } + else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); } + else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); } }); } else { - node.warn("Invalid GPIO pin: "+node.pin); + node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin); } node.on("close", function(done) { - node.status({fill:"grey",shape:"ring",text:"close"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.close")}); delete pinsInUse[node.pin]; if (node.child != null) { node.done = done; @@ -133,7 +133,7 @@ module.exports = function(RED) { } else { if ((pinsInUse[this.pin] !== this.out)||(pinsInUse[this.pin] === "pwm")) { - node.warn("GPIO pin "+this.pin+" already set as "+pinTypes[pinsInUse[this.pin]]); + node.warn(RED._("rpi-gpio.errors.gpiopin")+" "+this.pin+" "+RED._("rpi-gpio.errors.alreadyset")+" "+pinTypes[pinsInUse[this.pin]]); } } @@ -150,11 +150,11 @@ module.exports = function(RED) { node.status({fill:"green",shape:"dot",text:msg.payload.toString()}); } else { - node.error("nrpgio python command not running",msg); - node.status({fill:"red",shape:"ring",text:"not running"}); + node.error(RED._("rpi-gpio.errors.pythoncommandnotfound"),msg); + node.status({fill:"red",shape:"ring",text:RED._("common.status.not-running")}); } } - else { node.warn("Invalid input: "+out); } + else { node.warn(RED._("rpi-gpio.errors.invalidinput")+": "+out); } } if (node.pin !== undefined) { @@ -164,7 +164,7 @@ module.exports = function(RED) { node.child = spawn(gpioCommand, [node.out,node.pin]); } node.running = true; - node.status({fill:"green",shape:"dot",text:"OK"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.ok")}); node.on("input", inputlistener); @@ -179,27 +179,27 @@ module.exports = function(RED) { node.child.on('close', function (code) { node.child = null; node.running = false; - if (RED.settings.verbose) { node.log("closed"); } + if (RED.settings.verbose) { node.log(RED._("rpi-gpio.errors.closed")); } if (node.done) { - node.status({fill:"grey",shape:"ring",text:"closed"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.closed")}); node.done(); } - else { node.status({fill:"red",shape:"ring",text:"stopped"}); } + else { node.status({fill:"red",shape:"ring",text:RED._("common.status.stopped")}); } }); node.child.on('error', function (err) { - if (err.errno === "ENOENT") { node.error('nrgpio command not found'); } - else if (err.errno === "EACCES") { node.error('nrgpio command not executable'); } - else { node.error('error: ' + err.errno); } + if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); } + else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); } + else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); } }); } else { - node.warn("Invalid GPIO pin: "+node.pin); + node.warn(RED._("rpi-gpio.errors.invalidpin")+": "+node.pin); } node.on("close", function(done) { - node.status({fill:"grey",shape:"ring",text:"close"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.close")}); delete pinsInUse[node.pin]; if (node.child != null) { node.done = done; @@ -214,14 +214,14 @@ module.exports = function(RED) { var pitype = { type:"" }; exec(gpioCommand+" rev 0", function(err,stdout,stderr) { if (err) { - RED.log.info('Version command failed for some reason.'); + RED.log.info(RED._("rpi-gpio.errors.version")); } else { if (stdout.trim() == "0") { pitype = { type:"Compute" }; } else if (stdout.trim() == "1") { pitype = { type:"A/B v1" }; } else if (stdout.trim() == "2") { pitype = { type:"A/B v2" }; } else if (stdout.trim() == "3") { pitype = { type:"Model B+" }; } - else { RED.log.info("Saw Pi Type",stdout.trim()); } + else { RED.log.info(RED._("rpi-gpio.errors.sawpitype"),stdout.trim()); } } }); RED.nodes.registerType("rpi-gpio out",GPIOOutNode); @@ -232,7 +232,7 @@ module.exports = function(RED) { var node = this; node.child = spawn(gpioCommand+".py", ["mouse",node.butt]); - node.status({fill:"green",shape:"dot",text:"OK"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.ok")}); node.child.stdout.on('data', function (data) { data = Number(data); @@ -247,22 +247,22 @@ module.exports = function(RED) { node.child.on('close', function (code) { node.child = null; node.running = false; - if (RED.settings.verbose) { node.log("closed"); } + if (RED.settings.verbose) { node.log(RED._("rpi-gpio.errors.closed")); } if (node.done) { - node.status({fill:"grey",shape:"ring",text:"closed"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.closed")}); node.done(); } - else { node.status({fill:"red",shape:"ring",text:"stopped"}); } + else { node.status({fill:"red",shape:"ring",text:RED._("common.status.stopped")}); } }); node.child.on('error', function (err) { - if (err.errno === "ENOENT") { node.error('nrgpio command not found'); } - else if (err.errno === "EACCES") { node.error('nrgpio ommand not executable'); } - else { node.error('error: ' + err.errno); } + if (err.errno === "ENOENT") { node.error(RED._("rpi-gpio.errors.commandnotfound")); } + else if (err.errno === "EACCES") { node.error(RED._("rpi-gpio.errors.commandnotexecutable")); } + else { node.error(RED._("rpi-gpio.errors.error")+': ' + err.errno); } }); node.on("close", function(done) { - node.status({fill:"grey",shape:"ring",text:"close"}); + node.status({fill:"grey",shape:"ring",text:RED._("common.status.close")}); if (node.child != null) { node.done = done; node.child.kill('SIGINT'); diff --git a/nodes/core/io/10-mqtt.html b/nodes/core/io/10-mqtt.html index 72721686e..1309482b6 100644 --- a/nodes/core/io/10-mqtt.html +++ b/nodes/core/io/10-mqtt.html @@ -16,16 +16,16 @@ @@ -58,32 +58,32 @@ diff --git a/nodes/core/io/10-mqtt.js b/nodes/core/io/10-mqtt.js index ff014ad6b..daea6a388 100644 --- a/nodes/core/io/10-mqtt.js +++ b/nodes/core/io/10-mqtt.js @@ -42,7 +42,7 @@ module.exports = function(RED) { this.broker = n.broker; this.brokerConfig = RED.nodes.getNode(this.broker); if (this.brokerConfig) { - this.status({fill:"red",shape:"ring",text:"disconnected"}); + this.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")}); this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password); var node = this; if (this.topic) { @@ -55,22 +55,22 @@ module.exports = function(RED) { node.send(msg); }, this.id); this.client.on("connectionlost",function() { - node.status({fill:"red",shape:"ring",text:"disconnected"}); + node.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")}); }); this.client.on("connect",function() { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")}); }); if (this.client.isConnected()) { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")}); } else { this.client.connect(); } } else { - this.error("topic not defined"); + this.error(RED._("mqtt.errors.not-defined")); } } else { - this.error("missing broker configuration"); + this.error(RED._("mqtt.errors.missing-config")); } this.on('close', function() { if (this.client) { @@ -90,7 +90,7 @@ module.exports = function(RED) { this.brokerConfig = RED.nodes.getNode(this.broker); if (this.brokerConfig) { - this.status({fill:"red",shape:"ring",text:"disconnected"}); + this.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")}); this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password); var node = this; this.on("input",function(msg) { @@ -110,22 +110,22 @@ module.exports = function(RED) { if (msg.hasOwnProperty("topic") && (typeof msg.topic === "string") && (msg.topic !== "")) { // topic must exist this.client.publish(msg); // send the message } - else { node.warn("Invalid topic specified"); } + else { node.warn(RED._("mqtt.errors.invalid-topic")); } } }); this.client.on("connectionlost",function() { - node.status({fill:"red",shape:"ring",text:"disconnected"}); + node.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")}); }); this.client.on("connect",function() { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")}); }); if (this.client.isConnected()) { - node.status({fill:"green",shape:"dot",text:"connected"}); + node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")}); } else { this.client.connect(); } } else { - this.error("missing broker configuration"); + this.error(RED._("mqtt.errors.missing-config")); } this.on('close', function() { if (this.client) { diff --git a/nodes/core/io/21-httpin.html b/nodes/core/io/21-httpin.html index bb3cebe41..db1cef0a1 100644 --- a/nodes/core/io/21-httpin.html +++ b/nodes/core/io/21-httpin.html @@ -16,7 +16,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nodes/core/io/22-websocket.js b/nodes/core/io/22-websocket.js index 02410587a..ed6ee37dc 100644 --- a/nodes/core/io/22-websocket.js +++ b/nodes/core/io/22-websocket.js @@ -1,232 +1,234 @@ -/** - * Copyright 2013,2015 IBM Corp. - * - * 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) { - "use strict"; - var ws = require("ws"); - var inspect = require("sys").inspect; - - // A node red node that sets up a local websocket server - function WebSocketListenerNode(n) { - // Create a RED node - RED.nodes.createNode(this,n); - var node = this; - - // Store local copies of the node configuration (as defined in the .html) - node.path = n.path; - node.wholemsg = (n.wholemsg === "true"); - - node._inputNodes = []; // collection of nodes that want to receive events - node._clients = {}; - // match absolute url - node.isServer = !/^ws{1,2}:\/\//i.test(node.path); - node.closing = false; - - function startconn() { // Connect to remote endpoint - var socket = new ws(node.path); - node.server = socket; // keep for closing - handleConnection(socket); - } - - function handleConnection(/*socket*/socket) { - var id = (1+Math.random()*4294967295).toString(16); - if (node.isServer) { node._clients[id] = socket; node.emit('opened',Object.keys(node._clients).length); } - socket.on('open',function() { - if (!node.isServer) { node.emit('opened',''); } - }); - socket.on('close',function() { - if (node.isServer) { delete node._clients[id]; node.emit('opened',Object.keys(node._clients).length); } - else { node.emit('closed'); } - if (!node.closing && !node.isServer) { - node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? - } - }); - socket.on('message',function(data,flags){ - node.handleEvent(id,socket,'message',data,flags); - }); - socket.on('error', function(err) { - node.emit('erro'); - if (!node.closing && !node.isServer) { - node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? - } - }); - } - - if (node.isServer) { - var path = RED.settings.httpNodeRoot || "/"; - path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path); - - // Workaround https://github.com/einaros/ws/pull/253 - // Listen for 'newListener' events from RED.server - node._serverListeners = {}; - - var storeListener = function(/*String*/event,/*function*/listener){ - if(event == "error" || event == "upgrade" || event == "listening"){ - node._serverListeners[event] = listener; - } - } - - RED.server.addListener('newListener',storeListener); - - // Create a WebSocket Server - node.server = new ws.Server({server:RED.server,path:path}); - - // Workaround https://github.com/einaros/ws/pull/253 - // Stop listening for new listener events - RED.server.removeListener('newListener',storeListener); - - node.server.on('connection', handleConnection); - } - else { - node.closing = false; - startconn(); // start outbound connection - } - - node.on("close", function() { - // Workaround https://github.com/einaros/ws/pull/253 - // Remove listeners from RED.server - if (node.isServer) { - var listener = null; - for (var event in node._serverListeners) { - if (node._serverListeners.hasOwnProperty(event)) { - listener = node._serverListeners[event]; - if (typeof listener === "function") { - RED.server.removeListener(event,listener); - } - } - } - node._serverListeners = {}; - node.server.close(); - node._inputNodes = []; - } - else { - node.closing = true; - node.server.close(); - if (node.tout) { clearTimeout(tout); } - } - }); - } - RED.nodes.registerType("websocket-listener",WebSocketListenerNode); - RED.nodes.registerType("websocket-client",WebSocketListenerNode); - - WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler) { - this._inputNodes.push(handler); - } - - WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){ - var msg; - if (this.wholemsg) { - try { - msg = JSON.parse(data); - } - catch(err) { - msg = { payload:data }; - } - } else { - msg = { - payload:data - }; - } - msg._session = {type:"websocket",id:id}; - for (var i = 0; i < this._inputNodes.length; i++) { - this._inputNodes[i].send(msg); - } - } - - WebSocketListenerNode.prototype.broadcast = function(data) { - try { - if(this.isServer) { - for (var i = 0; i < this.server.clients.length; i++) { - this.server.clients[i].send(data); - } - } - else { - this.server.send(data); - } - } - catch(e) { // swallow any errors - this.warn("ws:"+i+" : "+e); - } - } - - WebSocketListenerNode.prototype.reply = function(id,data) { - var session = this._clients[id]; - if (session) { - try { - session.send(data); - } - catch(e) { // swallow any errors - } - } - } - - function WebSocketInNode(n) { - RED.nodes.createNode(this,n); - this.server = (n.client)?n.client:n.server; - var node = this; - this.serverConfig = RED.nodes.getNode(this.server); - if (this.serverConfig) { - this.serverConfig.registerInputNode(this); - this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }); - this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); }); - this.serverConfig.on('closed', function() { node.status({fill:"red",shape:"ring",text:"disconnected"}); }); - } else { - this.error("Missing server configuration"); - } - } - RED.nodes.registerType("websocket in",WebSocketInNode); - - function WebSocketOutNode(n) { - RED.nodes.createNode(this,n); - var node = this; - this.server = (n.client)?n.client:n.server; - this.serverConfig = RED.nodes.getNode(this.server); - if (!this.serverConfig) { - this.error("Missing server configuration"); - } - else { - this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }); - this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); }); - this.serverConfig.on('closed', function() { node.status({fill:"red",shape:"ring",text:"disconnected"}); }); - } - this.on("input", function(msg) { - var payload; - if (this.serverConfig.wholemsg) { - delete msg._session; - payload = JSON.stringify(msg); - } else if (msg.hasOwnProperty("payload")) { - if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string. - payload = RED.util.ensureString(msg.payload); - } - else { - payload = msg.payload; - } - } - if (payload) { - if (msg._session && msg._session.type == "websocket") { - node.serverConfig.reply(msg._session.id,payload); - } else { - node.serverConfig.broadcast(payload,function(error){ - if (!!error) { - node.warn("An error occurred while sending:" + inspect(error)); - } - }); - } - } - }); - } - RED.nodes.registerType("websocket out",WebSocketOutNode); -} +/** + * Copyright 2013,2015 IBM Corp. + * + * 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) { + "use strict"; + var ws = require("ws"); + var inspect = require("sys").inspect; + + // A node red node that sets up a local websocket server + function WebSocketListenerNode(n) { + // Create a RED node + RED.nodes.createNode(this,n); + var node = this; + + // Store local copies of the node configuration (as defined in the .html) + node.path = n.path; + node.wholemsg = (n.wholemsg === "true"); + + node._inputNodes = []; // collection of nodes that want to receive events + node._clients = {}; + // match absolute url + node.isServer = !/^ws{1,2}:\/\//i.test(node.path); + node.closing = false; + + function startconn() { // Connect to remote endpoint + var socket = new ws(node.path); + node.server = socket; // keep for closing + handleConnection(socket); + } + + function handleConnection(/*socket*/socket) { + var id = (1+Math.random()*4294967295).toString(16); + if (node.isServer) { node._clients[id] = socket; node.emit('opened',Object.keys(node._clients).length); } + socket.on('open',function() { + if (!node.isServer) { node.emit('opened',''); } + }); + socket.on('close',function() { + if (node.isServer) { delete node._clients[id]; node.emit('opened',Object.keys(node._clients).length); } + else { node.emit('closed'); } + if (!node.closing && !node.isServer) { + node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? + } + }); + socket.on('message',function(data,flags){ + node.handleEvent(id,socket,'message',data,flags); + }); + socket.on('error', function(err) { + node.emit('erro'); + if (!node.closing && !node.isServer) { + node.tout = setTimeout(function(){ startconn(); }, 3000); // try to reconnect every 3 secs... bit fast ? + } + }); + } + + if (node.isServer) { + var path = RED.settings.httpNodeRoot || "/"; + path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path); + + // Workaround https://github.com/einaros/ws/pull/253 + // Listen for 'newListener' events from RED.server + node._serverListeners = {}; + + var storeListener = function(/*String*/event,/*function*/listener){ + if(event == "error" || event == "upgrade" || event == "listening"){ + node._serverListeners[event] = listener; + } + } + + RED.server.addListener('newListener',storeListener); + + // Create a WebSocket Server + node.server = new ws.Server({server:RED.server,path:path}); + + // Workaround https://github.com/einaros/ws/pull/253 + // Stop listening for new listener events + RED.server.removeListener('newListener',storeListener); + + node.server.on('connection', handleConnection); + } + else { + node.closing = false; + startconn(); // start outbound connection + } + + node.on("close", function() { + // Workaround https://github.com/einaros/ws/pull/253 + // Remove listeners from RED.server + if (node.isServer) { + var listener = null; + for (var event in node._serverListeners) { + if (node._serverListeners.hasOwnProperty(event)) { + listener = node._serverListeners[event]; + if (typeof listener === "function") { + RED.server.removeListener(event,listener); + } + } + } + node._serverListeners = {}; + node.server.close(); + node._inputNodes = []; + } + else { + node.closing = true; + node.server.close(); + if (node.tout) { clearTimeout(tout); } + } + }); + } + RED.nodes.registerType("websocket-listener",WebSocketListenerNode); + RED.nodes.registerType("websocket-client",WebSocketListenerNode); + + WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler) { + this._inputNodes.push(handler); + } + + WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){ + var msg; + if (this.wholemsg) { + try { + msg = JSON.parse(data); + } + catch(err) { + msg = { payload:data }; + } + } else { + msg = { + payload:data + }; + } + msg._session = {type:"websocket",id:id}; + for (var i = 0; i < this._inputNodes.length; i++) { + this._inputNodes[i].send(msg); + } + } + + WebSocketListenerNode.prototype.broadcast = function(data) { + try { + if(this.isServer) { + for (var i = 0; i < this.server.clients.length; i++) { + this.server.clients[i].send(data); + } + } + else { + this.server.send(data); + } + } + catch(e) { // swallow any errors + this.warn("ws:"+i+" : "+e); + } + } + + WebSocketListenerNode.prototype.reply = function(id,data) { + var session = this._clients[id]; + if (session) { + try { + session.send(data); + } + catch(e) { // swallow any errors + } + } + } + + function WebSocketInNode(n) { + RED.nodes.createNode(this,n); + this.server = (n.client)?n.client:n.server; + var node = this; + this.serverConfig = RED.nodes.getNode(this.server); + if (this.serverConfig) { + this.serverConfig.registerInputNode(this); + // TODO: nls + this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }); + this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); }); + this.serverConfig.on('closed', function() { node.status({fill:"red",shape:"ring",text:"disconnected"}); }); + } else { + this.error(RED._("websocket.errors.missing-conf")); + } + } + RED.nodes.registerType("websocket in",WebSocketInNode); + + function WebSocketOutNode(n) { + RED.nodes.createNode(this,n); + var node = this; + this.server = (n.client)?n.client:n.server; + this.serverConfig = RED.nodes.getNode(this.server); + if (!this.serverConfig) { + this.error(RED._("websocket.errors.missing-conf")); + } + else { + // TODO: nls + this.serverConfig.on('opened', function(n) { node.status({fill:"green",shape:"dot",text:"connected "+n}); }); + this.serverConfig.on('erro', function() { node.status({fill:"red",shape:"ring",text:"error"}); }); + this.serverConfig.on('closed', function() { node.status({fill:"red",shape:"ring",text:"disconnected"}); }); + } + this.on("input", function(msg) { + var payload; + if (this.serverConfig.wholemsg) { + delete msg._session; + payload = JSON.stringify(msg); + } else if (msg.hasOwnProperty("payload")) { + if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string. + payload = RED.util.ensureString(msg.payload); + } + else { + payload = msg.payload; + } + } + if (payload) { + if (msg._session && msg._session.type == "websocket") { + node.serverConfig.reply(msg._session.id,payload); + } else { + node.serverConfig.broadcast(payload,function(error){ + if (!!error) { + node.warn(RED._("websocket.errors.send-error")+inspect(error)); + } + }); + } + } + }); + } + RED.nodes.registerType("websocket out",WebSocketOutNode); +} diff --git a/nodes/core/io/23-watch.html b/nodes/core/io/23-watch.html index 1af6b4e64..f897de39e 100644 --- a/nodes/core/io/23-watch.html +++ b/nodes/core/io/23-watch.html @@ -16,14 +16,14 @@ @@ -96,14 +96,12 @@ var datamode = $("#node-input-datamode option:selected").val(); var datatype = $("#node-input-datatype option:selected").val(); if (datamode == "stream") { - $("#node-input-datamode-plural").show(); if (datatype == "utf8") { $("#node-row-newline").show(); } else { $("#node-row-newline").hide(); } } else { - $("#node-input-datamode-plural").hide(); $("#node-row-newline").hide(); } }; @@ -118,41 +116,41 @@ @@ -223,27 +221,26 @@ +
@@ -105,62 +106,44 @@ +
@@ -61,7 +61,7 @@ outputs: 1, icon: "switch.png", label: function() { - return this.name||"switch"; + return this.name||this._("switch.label.switchlabel"); }, oneditprepare: function() { diff --git a/nodes/core/logic/15-change.html b/nodes/core/logic/15-change.html index 892641d08..3202ccedf 100644 --- a/nodes/core/logic/15-change.html +++ b/nodes/core/logic/15-change.html @@ -16,11 +16,11 @@ @@ -92,6 +92,13 @@ return this.name ? "node_label_italic" : ""; }, oneditprepare: function() { + var set = this._("change.set"); + var change = this._("change.change"); + var del = this._("change.delete"); + var to = this._("change.to"); + var search = this._("change.search"); + var replace = this._("change.replace"); + var regex = this._("change.regex"); if (this.reg === null) { $("#node-input-reg").prop('checked', true); } $("#node-input-action").change(); @@ -104,7 +111,7 @@ var row3 = $('
',{style:"margin-top:8px;"}).appendTo(container); var selectField = $('',{style:"width: 220px",class:"node-input-rule-property-value",type:"text"}).appendTo(row2); var row3_1 = $('
').appendTo(row3); - $('
',{style:"display: inline-block;text-align:right; width:150px;padding-right: 10px; box-sizing: border-box;"}).text("Search for").appendTo(row3_1); + $('
',{style:"display: inline-block;text-align:right; width:150px;padding-right: 10px; box-sizing: border-box;"}).text(search).appendTo(row3_1); var fromValue = $('',{style:"width: 220px",class:"node-input-rule-property-search-value",type:"text"}).appendTo(row3_1); var row3_2 = $('
',{style:"margin-top:8px;"}).appendTo(row3); - $('
',{style:"display: inline-block;text-align:right; width:150px;padding-right: 10px; box-sizing: border-box;"}).text("replace with").appendTo(row3_2); + $('
',{style:"display: inline-block;text-align:right; width:150px;padding-right: 10px; box-sizing: border-box;"}).text(replace).appendTo(row3_2); var toValue = $('',{style:"width: 220px",class:"node-input-rule-property-replace-value",type:"text"}).appendTo(row3_2); var row3_3 = $('
',{style:"margin-top:8px;"}).appendTo(row3); var id = "node-input-rule-property-regex-"+Math.floor(Math.random()*10000); var useRegExp = $('',{id:id,class:"node-input-rule-property-re",type:"checkbox", style:"margin-left: 150px; margin-right: 10px; display: inline-block; width: auto; vertical-align: top;"}).appendTo(row3_3); - $('