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)
This commit is contained in:
Scott Yoshizawa
2015-05-10 15:47:22 -05:00
committed by Nick O'Leary
parent c105b2df37
commit 2fe859b111
49 changed files with 1903 additions and 1159 deletions

View File

@@ -16,16 +16,16 @@
<script type="text/x-red" data-template-name="mqtt in">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> Broker</label>
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topicph">
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
</script>
@@ -58,32 +58,32 @@
<script type="text/x-red" data-template-name="mqtt out">
<div class="form-row">
<label for="node-input-broker"><i class="fa fa-globe"></i> Broker</label>
<label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input type="text" id="node-input-broker">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topicph">
</div>
<div class="form-row">
<label for="node-input-qos"><i class="fa fa-empire"></i> QoS</label>
<label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
<select id="node-input-qos" style="width:125px !important">
<option value=""></option>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
&nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;Retain &nbsp;<select id="node-input-retain" style="width:125px !important">
&nbsp;&nbsp;<i class="fa fa-history"></i>&nbsp;<span data-i18n="mqtt.retain"></span> &nbsp;<select id="node-input-retain" style="width:125px !important">
<option value=""></option>
<option value="false">false</option>
<option value="true">true</option>
<option value="false" data-i18n="mqtt.false"></option>
<option value="true" data-i18n="mqtt.true"></option>
</select>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips">Tip: Leave topic, qos or retain blank if you want to set them via msg properties.</div>
<div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
</script>
<script type="text/x-red" data-help-name="mqtt out">
@@ -118,21 +118,21 @@
<script type="text/x-red" data-template-name="mqtt-broker">
<div class="form-row node-input-broker">
<label for="node-config-input-broker"><i class="fa fa-globe"></i> Broker</label>
<label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
<input class="input-append-left" type="text" id="node-config-input-broker" 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="Port" style="width:45px">
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> <span data-i18n="mqtt.port"></span></label>
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.portph" style="width:45px">
</div>
<div class="form-row">
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> Client ID</label>
<input type="text" id="node-config-input-clientid" placeholder="Leave blank for auto generated">
<label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
<input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.label.clientidph">
</div>
<div class="form-row">
<label for="node-config-input-user"><i class="fa fa-user"></i> Username</label>
<label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-config-input-user">
</div>
<div class="form-row">
<label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
<label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
<input type="password" id="node-config-input-password">
</div>
</script>

View File

@@ -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) {

View File

@@ -16,7 +16,7 @@
<script type="text/x-red" data-template-name="http in">
<div class="form-row">
<label for="node-input-method"><i class="fa fa-tasks"></i> Method</label>
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
<select type="text" id="node-input-method" style="width:72%;">
<option value="get">GET</option>
<option value="post">POST</option>
@@ -25,18 +25,18 @@
</select>
</div>
<div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> url</label>
<input type="text" id="node-input-url" placeholder="/url">
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input type="text" id="node-input-url" data-i18n="[placeholder]httpin.label.urlph">
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-row row-swagger-doc">
<label for="node-input-name"><i class="fa fa-tag"></i> Doc</label>
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="httpin.label.doc"></span></label>
<input type="text" id="node-input-swaggerDoc">
</div>
<div id="node-input-tip" class="form-tips">The url will be relative to <code><span id="node-input-path"></span></code>.</div>
<div id="node-input-tip" class="form-tips"><span data-i18n="httpin.in-tip"></span><code><span id="node-input-path"></span></code>.</div>
</script>
<script type="text/x-red" data-help-name="http in">
@@ -67,10 +67,10 @@
<script type="text/x-red" data-template-name="http response">
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips">The messages sent to this node <b>must</b> originate from an <i>http input</i> node</div>
<div class="form-tips"><span data-i18n="[html]httpin.res-tip"></span></div>
</script>
<script type="text/x-red" data-help-name="http response">
@@ -86,45 +86,45 @@
<script type="text/x-red" data-template-name="http request">
<div class="form-row">
<label for="node-input-method"><i class="fa fa-tasks"></i> Method</label>
<label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
<select type="text" id="node-input-method" style="width:72%;">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="use">- set by msg.method -</option>
<option value="use" data-i18n="httpin.setby"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-url"><i class="fa fa-globe"></i> URL</label>
<input type="text" id="node-input-url" placeholder="http://">
<label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
<input type="text" id="node-input-url" data-i18n="[placeholder]httpin.label.httpph">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-useAuth" style="width: 70%;">Use basic authentication ?</label>
<label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
</div>
<div class="form-row node-input-useAuth-row">
<label for="node-input-user"><i class="fa fa-user"></i> Username</label>
<label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
<input type="text" id="node-input-user">
</div>
<div class="form-row node-input-useAuth-row">
<label for="node-input-password"><i class="fa fa-lock"></i> Password</label>
<label for="node-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
<input type="password" id="node-input-password">
</div>
<div class="form-row">
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> Return</label>
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
<select type="text" id="node-input-ret" style="width:72%;">
<option value="txt">a UTF-8 string</option>
<option value="bin">a binary buffer</option>
<option value="obj">a parsed JSON object</option>
<option value="txt" data-i18n="httpin.utf8"></option>
<option value="bin" data-i18n="httpin.binary"></option>
<option value="obj" data-i18n="httpin.json"></option>
</select>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips" id="tip-json" hidden>Tip: If the JSON parse fails the fetched string is returned as-is.</div>
<div class="form-tips" id="tip-json" hidden><span data-i18n="httpin.req-tip"></span></div>
</script>
<script type="text/x-red" data-help-name="http request">
@@ -241,7 +241,7 @@
outputs:1,
icon: "white-globe.png",
label: function() {
return this.name||"http request";
return this.name||this._("httpin.httpreq");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@@ -137,7 +137,7 @@ module.exports = function(RED) {
}
});
} else {
this.warn("Cannot create http-in node when httpNodeRoot set to false");
this.warn(RED._("httpin.errors.not-created"));
}
}
RED.nodes.registerType("http in",HTTPIn);
@@ -172,7 +172,7 @@ module.exports = function(RED) {
msg.res.send(statusCode,msg.payload);
}
} else {
node.warn("No response object");
node.warn(RED._("httpin.errors.no-response"));
}
});
}
@@ -195,16 +195,16 @@ module.exports = function(RED) {
this.on("input",function(msg) {
var preRequestTimestamp = process.hrtime();
node.status({fill:"blue",shape:"dot",text:"requesting"});
node.status({fill:"blue",shape:"dot",text:RED._("common.status.requesting")});
var url = nodeUrl || msg.url;
if (msg.url && nodeUrl && (nodeUrl !== msg.url)) { // revert change below when warning is finally removed
node.warn("Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props");
node.warn(RED._("httpin.errors.not-overridden"));
}
if (isTemplatedUrl) {
url = mustache.render(nodeUrl,msg);
}
if (!url) {
node.error("No url specified",msg);
node.error(RED._("httpin.errors.no-url"),msg);
return;
}
// url must start http:// or https:// so assume http:// if not set
@@ -214,7 +214,7 @@ module.exports = function(RED) {
var method = nodeMethod.toUpperCase() || "GET";
if (msg.method && n.method && (n.method !== "use")) { // warn if override option not set
node.warn("Warning: msg properties can no longer override fixed node properties. Use explicit override option. See bit.ly/nr-override-msg-props");
node.warn(RED._("httpin.errors.not-overridden"));
}
if (msg.method && n.method && (n.method === "use")) {
method = msg.method.toUpperCase(); // use the msg parameter
@@ -312,7 +312,7 @@ module.exports = function(RED) {
}
else if (node.ret === "obj") {
try { msg.payload = JSON.parse(msg.payload); }
catch(e) { node.warn("JSON parse error"); }
catch(e) { node.warn(RED._("httpin.errors.json-error")); }
}
node.send(msg);
node.status({});

View File

@@ -1,279 +1,277 @@
<!--
Copyright 2013 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.
-->
<script type="text/javascript">
function ws_oneditprepare() {
$("#websocket-client-row").hide();
$("#node-input-mode").change(function(){
if( $("#node-input-mode").val() === 'client') {
$("#websocket-server-row").hide();
$("#websocket-client-row").show();
}
else {
$("#websocket-server-row").show();
$("#websocket-client-row").hide();
}
});
if(this.client) {
$("#node-input-mode").val('client').change();
}
else {
$("#node-input-mode").val('server').change();
}
}
function ws_oneditsave() {
if($("#node-input-mode").val() === 'client') {
$("#node-input-server").append('<option value="">Dummy</option>');
$("#node-input-server").val('');
}
else {
$("#node-input-client").append('<option value="">Dummy</option>');
$("#node-input-client").val('');
}
}
function ws_label() {
var nodeid = (this.client)?this.client:this.server;
var wsNode = RED.nodes.node(nodeid);
return this.name||(wsNode?"[ws] "+wsNode.label():"websocket");
}
function ws_validateserver() {
if($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
return true;
}
else {
return RED.nodes.node(this.server) != null;
}
}
function ws_validateclient() {
if($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
return RED.nodes.node(this.client) != null;
}
else {
return true;
}
}
</script>
<!-- WebSocket Input Node -->
<script type="text/x-red" data-template-name="websocket in">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> Type</label>
<select id="node-input-mode">
<option value="server">Listen on</option>
<option value="client">Connect to</option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> Path</label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> URL</label>
<input type="text" id="node-input-client">
</div>
<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>
</script>
<script type="text/x-red" data-help-name="websocket in">
<p>WebSocket input node.</p>
<p>By default, the data received from the WebSocket will be in <b>msg.payload</b>.
The socket can be configured to expect a properly formed JSON string, in which
case it will parse the JSON and send on the resulting object as the entire message.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket in',{
category: 'input',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:0,
outputs:1,
icon: "white-globe.png",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
</script>
<!-- WebSocket out Node -->
<script type="text/x-red" data-template-name="websocket out">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> Type</label>
<select id="node-input-mode">
<option value="server">Listen on</option>
<option value="client">Connect to</option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> Path</label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> URL</label>
<input type="text" id="node-input-client">
</div>
<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>
</script>
<script type="text/x-red" data-help-name="websocket out">
<p>WebSocket out node.</p>
<p>By default, <b>msg.payload</b> will be sent over the WebSocket. The socket
can be configured to encode the entire message object as a JSON string and send that
over the WebSocket.</p>
<p>If the message arriving at this node started at a WebSocket In node, the message
will be sent back to the client that triggered the flow. Otherwise, the message
will be broadcast to all connected clients.</p>
<p>If you want to broadcast a message that started at a WebSocket In node, you
should delete the <b>msg._session</b> property within the flow</p>.
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket out',{
category: 'output',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:1,
outputs:0,
icon: "white-globe.png",
align: "right",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
</script>
<!-- WebSocket Server configuration node -->
<script type="text/x-red" data-template-name="websocket-listener">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> Path</label>
<input type="text" id="node-config-input-path" placeholder="/ws/example">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg">&nbsp;</label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false">Send/Receive payload</option>
<option value="true">Send/Receive entire message</option>
</select>
</div>
<div class="form-tips">
By default, <code>payload</code> will contain the data to be sent over, or received from a websocket.
The listener can be configured to send or receive the entire message object as a JSON formatted string.
<p id="node-config-ws-tip">This path will be relative to <code><span id="node-config-ws-path"></span></code>.</p>
</div>
</script>
<script type="text/x-red" data-help-name="websocket-listener">
<p>This configuration node creates a WebSocket Server using the specified path</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket-listener',{
category: 'config',
defaults: {
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
wholemsg: {value:"false"}
},
inputs:0,
outputs:0,
label: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) != "/") {
root = root+"/";
}
if (this.path.charAt(0) == "/") {
root += this.path.slice(1);
} else {
root += this.path;
}
return root;
},
oneditprepare: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) == "/") {
root = root.slice(0,-1);
}
if (root == "") {
$("#node-config-ws-tip").hide();
} else {
$("#node-config-ws-path").html(root);
$("#node-config-ws-tip").show();
}
}
});
</script>
<!-- WebSocket Client configuration node -->
<script type="text/x-red" data-template-name="websocket-client">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> URL</label>
<input type="text" id="node-config-input-path" placeholder="ws://example.com/ws">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg">&nbsp;</label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false">Send/Receive payload</option>
<option value="true">Send/Receive entire message</option>
</select>
</div>
<div class="form-tips">
<p>URL should use ws:&#47;&#47; or wss:&#47;&#47; scheme and point to an existing websocket listener.</p>
By default, <code>payload</code> will contain the data to be sent over, or received from a websocket.
The client can be configured to send or receive the entire message object as a JSON formatted string.
</div>
</script>
<script type="text/x-red" data-help-name="websocket-client">
<p>This configuration node connects a WebSocket client to the specified URL.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket-client',{
category: 'config',
defaults: {
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
wholemsg: {value:"false"}
},
inputs:0,
outputs:0,
label: function() {
return this.path;
}
});
</script>
<!--
Copyright 2013 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.
-->
<script type="text/javascript">
function ws_oneditprepare() {
$("#websocket-client-row").hide();
$("#node-input-mode").change(function(){
if( $("#node-input-mode").val() === 'client') {
$("#websocket-server-row").hide();
$("#websocket-client-row").show();
}
else {
$("#websocket-server-row").show();
$("#websocket-client-row").hide();
}
});
if(this.client) {
$("#node-input-mode").val('client').change();
}
else {
$("#node-input-mode").val('server').change();
}
}
function ws_oneditsave() {
if($("#node-input-mode").val() === 'client') {
$("#node-input-server").append('<option value="">Dummy</option>');
$("#node-input-server").val('');
}
else {
$("#node-input-client").append('<option value="">Dummy</option>');
$("#node-input-client").val('');
}
}
function ws_label() {
var nodeid = (this.client)?this.client:this.server;
var wsNode = RED.nodes.node(nodeid);
return this.name||(wsNode?"[ws] "+wsNode.label():"websocket");
}
function ws_validateserver() {
if($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
return true;
}
else {
return RED.nodes.node(this.server) != null;
}
}
function ws_validateclient() {
if($("#node-input-mode").val() === 'client' || (this.client && !this.server)) {
return RED.nodes.node(this.client) != null;
}
else {
return true;
}
}
</script>
<!-- WebSocket Input Node -->
<script type="text/x-red" data-template-name="websocket in">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
<select id="node-input-mode">
<option value="server" data-i18n="websocket.listenon"></option>
<option value="client" data-i18n="websocket.connectto"></option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input type="text" id="node-input-client">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
</script>
<script type="text/x-red" data-help-name="websocket in">
<p>WebSocket input node.</p>
<p>By default, the data received from the WebSocket will be in <b>msg.payload</b>.
The socket can be configured to expect a properly formed JSON string, in which
case it will parse the JSON and send on the resulting object as the entire message.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket in',{
category: 'input',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:0,
outputs:1,
icon: "white-globe.png",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
</script>
<!-- WebSocket out Node -->
<script type="text/x-red" data-template-name="websocket out">
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-dot-circle-o"></i> <span data-i18n="websocket.label.type"></span></label>
<select id="node-input-mode">
<option value="server" data-i18n="websocket.listenon"></option>
<option value="client" data-i18n="websocket.connectto"></option>
</select>
</div>
<div class="form-row" id="websocket-server-row">
<label for="node-input-server"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input type="text" id="node-input-server">
</div>
<div class="form-row" id="websocket-client-row">
<label for="node-input-client"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input type="text" id="node-input-client">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
</script>
<script type="text/x-red" data-help-name="websocket out">
<p>WebSocket out node.</p>
<p>By default, <b>msg.payload</b> will be sent over the WebSocket. The socket
can be configured to encode the entire message object as a JSON string and send that
over the WebSocket.</p>
<p>If the message arriving at this node started at a WebSocket In node, the message
will be sent back to the client that triggered the flow. Otherwise, the message
will be broadcast to all connected clients.</p>
<p>If you want to broadcast a message that started at a WebSocket In node, you
should delete the <b>msg._session</b> property within the flow</p>.
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket out',{
category: 'output',
defaults: {
name: {value:""},
server: {type:"websocket-listener", validate: ws_validateserver},
client: {type:"websocket-client", validate: ws_validateclient}
},
color:"rgb(215, 215, 160)",
inputs:1,
outputs:0,
icon: "white-globe.png",
align: "right",
labelStyle: function() {
return this.name?"node_label_italic":"";
},
label: ws_label,
oneditsave: ws_oneditsave,
oneditprepare: ws_oneditprepare
});
</script>
<!-- WebSocket Server configuration node -->
<script type="text/x-red" data-template-name="websocket-listener">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.path"></span></label>
<input type="text" id="node-config-input-path" data-i18n="[placeholder]websocket.label.pathph">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg">&nbsp;</label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false" data-i18n="websocket.payload"></option>
<option value="true" data-i18n="websocket.message"></option>
</select>
</div>
<div class="form-tips">
<span data-i18n="[html]websocket.path-tip1"></span>
<p id="node-config-ws-tip"><span data-i18n="[html]websocket.path-tip2"></span><code><span id="node-config-ws-path"></span></code>.</p>
</div>
</script>
<script type="text/x-red" data-help-name="websocket-listener">
<p>This configuration node creates a WebSocket Server using the specified path</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket-listener',{
category: 'config',
defaults: {
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
wholemsg: {value:"false"}
},
inputs:0,
outputs:0,
label: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) != "/") {
root = root+"/";
}
if (this.path.charAt(0) == "/") {
root += this.path.slice(1);
} else {
root += this.path;
}
return root;
},
oneditprepare: function() {
var root = RED.settings.httpNodeRoot;
if (root.slice(-1) == "/") {
root = root.slice(0,-1);
}
if (root == "") {
$("#node-config-ws-tip").hide();
} else {
$("#node-config-ws-path").html(root);
$("#node-config-ws-tip").show();
}
}
});
</script>
<!-- WebSocket Client configuration node -->
<script type="text/x-red" data-template-name="websocket-client">
<div class="form-row">
<label for="node-config-input-path"><i class="fa fa-bookmark"></i> <span data-i18n="websocket.label.url"></span></label>
<input type="text" id="node-config-input-path" data-i18n="[placeholder]websocket.label.urlph">
</div>
<div class="form-row">
<label for="node-config-input-wholemsg">&nbsp;</label>
<select type="text" id="node-config-input-wholemsg" style="width: 70%;">
<option value="false" data-i18n="websocket.payload"></option>
<option value="true" data-i18n="websocket.message"></option>
</select>
</div>
<div class="form-tips">
<p><span data-i18n="[html]websocket.url-tip1"></span></p>
<span data-i18n="[html]websocket.url-tip2"></span>
</div>
</script>
<script type="text/x-red" data-help-name="websocket-client">
<p>This configuration node connects a WebSocket client to the specified URL.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('websocket-client',{
category: 'config',
defaults: {
path: {value:"",required:true,validate:RED.validators.regex(/^((?!\/debug\/ws).)*$/) },
wholemsg: {value:"false"}
},
inputs:0,
outputs:0,
label: function() {
return this.path;
}
});
</script>

View File

@@ -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);
}

View File

@@ -16,14 +16,14 @@
<script type="text/x-red" data-template-name="watch">
<div class="form-row node-input-filename">
<label for="node-input-files"><i class="fa fa-file"></i> File(s)</label>
<input type="text" id="node-input-files" placeholder="File(s) or Directory">
<label for="node-input-files"><i class="fa fa-file"></i> <span data-i18n="watch.label.files"></span></label>
<input type="text" id="node-input-files" data-i18n="[placeholder]watch.label.filesph">
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div id="node-input-tip" class="form-tips">On Windows you must use double back-slashes \\ in any directory names.</div>
<div id="node-input-tip" class="form-tips"><span data-i18n="watch.tip"></span></div>
</script>
<script type="text/x-red" data-help-name="watch">

View File

@@ -16,43 +16,43 @@
<script type="text/x-red" data-template-name="tcp in">
<div class="form-row">
<label for="node-input-server"><i class="fa fa-dot-circle-o"></i> Type</label>
<label for="node-input-server"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
<select id="node-input-server" style="width:120px; margin-right:5px;">
<option value="server">Listen on</option>
<option value="client">Connect to</option>
<option value="server" data-i18n="tcpin.listen"></option>
<option value="client" data-i18n="tcpin.connect"></option>
</select>
port <input type="text" id="node-input-port" style="width: 50px">
<span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width: 50px">
</div>
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
</div>
<div class="form-row">
<label><i class="fa fa-sign-out"></i> Output</label>
a
<label><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.output"></span></label>
<span data-i18n="tcpin.label.a"></span>
<select id="node-input-datamode" style="width:110px;">
<option value="stream">stream of</option>
<option value="single">single</option>
<option value="stream" data-i18n="tcpin.stream"></option>
<option value="single" data-i18n="tcpin.single"></option>
</select>
<select id="node-input-datatype" style="width:140px;">
<option value="buffer">Buffer</option>
<option value="utf8">String</option>
<option value="base64">Base64 String</option>
<option value="buffer" data-i18n="tcpin.buffer"></option>
<option value="utf8" data-i18n="tcpin.string"></option>
<option value="base64" data-i18n="tcpin.base64"></option>
</select>
payload<span id="node-input-datamode-plural">s</span>
<span data-i18n="tcpin.label.payload"></span>
</div>
<div id="node-row-newline" class="form-row hidden" style="padding-left: 110px;">
delimited by <input type="text" id="node-input-newline" style="width: 110px;">
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width: 110px;">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
<input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topicph">
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
</script>
@@ -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 @@
<script type="text/x-red" data-template-name="tcp out">
<div class="form-row">
<label for="node-input-beserver"><i class="fa fa-dot-circle-o"></i> Type</label>
<label for="node-input-beserver"><i class="fa fa-dot-circle-o"></i> <span data-i18n="tcpin.label.type"></span></label>
<select id="node-input-beserver" style="width:150px; margin-right:5px;">
<option value="server">Listen on</option>
<option value="client">Connect to</option>
<option value="reply">Reply to TCP</option>
<option value="server" data-i18n="tcpin.listen"></option>
<option value="client" data-i18n="tcpin.connect"></option>
<option value="reply" data-i18n="tcpin.reply"></option>
</select>
<span id="node-input-port-row">port <input type="text" id="node-input-port" style="width: 50px"></span>
<span id="node-input-port-row"><span data-i18n="tcpin.label.port"></span> <input type="text" id="node-input-port" style="width: 50px"></span>
</div>
<div class="form-row hidden" id="node-input-host-row" style="padding-left: 110px;">
at host <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
<span data-i18n="tcpin.label.host"></span> <input type="text" id="node-input-host" placeholder="localhost" style="width: 60%;">
</div>
<div class="form-row hidden" id="node-input-end-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-end" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-end" style="width: 70%;">Close connection after each message is sent ?</label>
<label for="node-input-end" style="width: 70%;"><span data-i18n="tcpin.label.close-connection"></span></label>
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-base64" placeholder="base64" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-base64" style="width: 70%;">Decode Base64 message ?</label>
<label for="node-input-base64" style="width: 70%;"><span data-i18n="tcpin.label.decode-base64"></span></label>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips hidden" id="fin-tip">
<b>Note:</b> Closing the connection after each message is generally not a good thing - but is useful to indicate an end-of-file for example.
<span data-i18n="[html]tcpin.out-tip1"></span>
</div>
<div class="form-tips hidden" id="fin-tip2">
<b>Note:</b> Closing the connection after each message is generally not a good thing - but is useful to indicate an end-of-file for example. The receiving client will need to reconnect.
<span data-i18n="[html]tcpin.out-tip2"></span>
</div>
</script>
@@ -223,27 +221,26 @@
<script type="text/x-red" data-template-name="tcp request">
<div class="form-row">
<label for="node-input-server"><i class="fa fa-globe"></i> Server</label>
<label for="node-input-server"><i class="fa fa-globe"></i> <span data-i18n="tcpin.label.server"></span></label>
<input type="text" id="node-input-server" placeholder="ip.address" style="width:45%">
&nbsp;port <input type="text" id="node-input-port" placeholder="number" style="width:60px">
&nbsp;port <input type="text" id="node-input-port" data-i18n="[placeholder]tcpin.label.numberph" style="width:60px">
</div>
<div class="form-row">
<label for="node-input-out"><i class="fa fa-sign-out"></i> Return</label>
<label for="node-input-out"><i class="fa fa-sign-out"></i> <span data-i18n="tcpin.label.return"></span></label>
<select type="text" id="node-input-out" style="width:56%;">
<option value="time">after a fixed timeout of</option>
<option value="char">when character received is</option>
<option value="count">a fixed number of characters</option>
<option value="sit">never. Keep connection open</option>
<option value="time" data-i18n="tcpin.timeout"></option>
<option value="char" data-i18n="tcpin.character"></option>
<option value="count" data-i18n="tcpin.number"></option>
<option value="sit" data-i18n="tcpin.never"></option>
</select>
<input type="text" id="node-input-splitc" style="width:50px;">
<span id="node-units"></span>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips"><b>Tip:</b> Outputs a binary <b>Buffer</b>, so you may want to .toString() it.</br/>
<b>Tip:</b> Leave host and port blank if you want to overide with msg.host and msg.port properties.</div>
<div class="form-tips"><span data-i18n="[html]tcpin.req-tip"></span></div>
<script>
var previous = null;
$("#node-input-out").on('focus', function () { previous = this.value; }).change(function() {

View File

@@ -43,14 +43,14 @@ module.exports = function(RED) {
var reconnectTimeout;
var end = false;
var setupTcpClient = function() {
node.log("connecting to "+node.host+":"+node.port);
node.status({fill:"grey",shape:"dot",text:"connecting"});
node.log(RED._("tcpin.errors.connecting-to")+" "+node.host+":"+node.port);
node.status({fill:"grey",shape:"dot",text:RED._("common.status.connecting")});
var id = (1+Math.random()*4294967295).toString(16);
client = net.connect(node.port, node.host, function() {
buffer = (node.datatype == 'buffer')? new Buffer(0):"";
node.connected = true;
node.log("connected to "+node.host+":"+node.port);
node.status({fill:"green",shape:"dot",text:"connected"});
node.log(RED._("tcpin.errors.connected-to")+" "+node.host+":"+node.port);
node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")});
});
connectionPool[id] = client;
@@ -96,14 +96,14 @@ module.exports = function(RED) {
client.on('close', function() {
delete connectionPool[id];
node.connected = false;
node.status({fill:"red",shape:"ring",text:"disconnected"});
node.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")});
if (!node.closing) {
if (end) { // if we were asked to close then try to reconnect once very quick.
end = false;
reconnectTimeout = setTimeout(setupTcpClient, 20);
}
else {
node.log("connection lost to "+node.host+":"+node.port);
node.log(RED._("tcpin.errors.connection-lost")+" "+node.host+":"+node.port);
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
}
} else {
@@ -128,7 +128,7 @@ module.exports = function(RED) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16);
connectionPool[id] = socket;
node.status({text:++count+" connections"});
node.status({text:++count+" "+RED._("common.status.connections")});
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
socket.on('data', function (data) {
@@ -170,12 +170,12 @@ module.exports = function(RED) {
}
});
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
node.log(RED._("tcpin.errors.timeout")+' '+node.port);
socket.end();
});
socket.on('close', function() {
delete connectionPool[id];
node.status({text:--count+" connections"});
node.status({text:--count+" "+RED._("common.status.connections")});
});
socket.on('error',function(err) {
node.log(err);
@@ -183,15 +183,15 @@ module.exports = function(RED) {
});
server.on('error', function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
node.error(RED._("tcpin.errors.cannot-listen")+' '+node.port+' : '+err);
}
});
server.listen(node.port, function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
node.error(RED._("tcpin.errors.cannot-listen")+' '+node.port+' : '+err);
} else {
node.log('listening on port '+node.port);
node.log(RED._("tcpin.errors.listening-port")+' '+node.port);
node.on('close', function() {
for (var c in connectionPool) {
if (connectionPool.hasOwnProperty(c)) {
@@ -201,7 +201,7 @@ module.exports = function(RED) {
}
node.closing = true;
server.close();
node.log('stopped listening on port '+node.port);
node.log(RED._("tcpin.errors.stopped-listening")+' '+node.port);
});
}
});
@@ -228,20 +228,20 @@ module.exports = function(RED) {
var end = false;
var setupTcpClient = function() {
node.log("connecting to "+node.host+":"+node.port);
node.status({fill:"grey",shape:"dot",text:"connecting"});
node.log(RED._("tcpin.errors.connecting-to")+" "+node.host+":"+node.port);
node.status({fill:"grey",shape:"dot",text:RED._("common.status.connecting")});
client = net.connect(node.port, node.host, function() {
node.connected = true;
node.log("connected to "+node.host+":"+node.port);
node.status({fill:"green",shape:"dot",text:"connected"});
node.log(RED._("tcpin.errors.connected-to")+" "+node.host+":"+node.port);
node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")});
});
client.on('error', function (err) {
node.log(err);
node.log(RED._("tcpin.errors.error")+' : '+err);
});
client.on('end', function (err) {
});
client.on('close', function() {
node.status({fill:"red",shape:"ring",text:"disconnected"});
node.status({fill:"red",shape:"ring",text:RED._("common.status.disconnected")});
node.connected = false;
client.destroy();
if (!node.closing) {
@@ -250,7 +250,7 @@ module.exports = function(RED) {
reconnectTimeout = setTimeout(setupTcpClient,20);
}
else {
node.log("connection lost to "+node.host+":"+node.port);
node.log(RED._("tcpin.errors.connection-lost")+" "+node.host+":"+node.port);
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
}
} else {
@@ -301,26 +301,26 @@ module.exports = function(RED) {
});
} else {
var connectedSockets = [];
node.status({text:"0 connections"});
node.status({text:"0 "+RED._("common.status.connections")});
var server = net.createServer(function (socket) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
node.log("connection from "+remoteDetails);
node.log(RED._("tcpin.errors.connection-from")+" "+remoteDetails);
connectedSockets.push(socket);
node.status({text:connectedSockets.length+" connections"});
node.status({text:connectedSockets.length+" "+RED._("common.status.connections")});
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
node.log(RED._("tcpin.errors.timeout")+' '+node.port);
socket.end();
});
socket.on('close',function() {
node.log("connection closed from "+remoteDetails);
node.log(RED._("tcpin.errors.connection-closed")+" "+remoteDetails);
connectedSockets.splice(connectedSockets.indexOf(socket),1);
node.status({text:connectedSockets.length+" connections"});
node.status({text:connectedSockets.length+" "+RED._("common.status.connections")});
});
socket.on('error',function() {
node.log("socket error from "+remoteDetails);
node.log(RED._("tcpin.errors.socket-error")+" "+remoteDetails);
connectedSockets.splice(connectedSockets.indexOf(socket),1);
node.status({text:connectedSockets.length+" connections"});
node.status({text:connectedSockets.length+" "+RED._("common.status.connections")});
});
});
@@ -343,15 +343,15 @@ module.exports = function(RED) {
server.on('error', function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
node.error(RED._("tcpin.errors.cannot-listen")+' '+node.port+' : '+err);
}
});
server.listen(node.port, function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
node.error(RED._("tcpin.errors.cannot-listen")+' '+node.port+' : '+err);
} else {
node.log('listening on port '+node.port);
node.log(RED._("tcpin.errors.listening-port")+' '+node.port);
node.on('close', function() {
for (var c in connectedSockets) {
if (connectedSockets.hasOwnProperty(c)) {
@@ -360,7 +360,7 @@ module.exports = function(RED) {
}
}
server.close();
node.log('stopped listening on port '+node.port);
node.log(RED._("tcpin.errors.stopped-listening")+' '+node.port);
});
}
});
@@ -401,18 +401,17 @@ module.exports = function(RED) {
if (host && port) {
client.connect(port, host, function() {
//node.log('client connected');
node.status({fill:"green",shape:"dot",text:"connected"});
//node.log(RED._("tcpin.errors.client-connected"));
node.status({fill:"green",shape:"dot",text:RED._("common.status.connected")});
node.connected = true;
client.write(msg.payload);
});
}
else {
node.warn("Host and/or port not set");
node.warn(RED._("tcpin.errors.no-host"));
}
client.on('data', function(data) {
//node.log("data:"+ data.length+":"+ data);
if (node.out == "sit") { // if we are staying connected just send the buffer
node.send({"payload": data});
}
@@ -477,18 +476,17 @@ module.exports = function(RED) {
});
client.on('error', function() {
node.error('connect failed',msg);
node.status({fill:"red",shape:"ring",text:"error"});
node.error(RED._("tcpin.errors.connect-fail"),msg);
node.status({fill:"red",shape:"ring",text:RED._("common.status.error")});
if (client) { client.end(); }
});
client.on('timeout',function() {
node.warn('connect timeout');
node.warn(RED._("tcpin.errors.timeout"));
if (client) {
client.end();
setTimeout(function() {
client.connect(port, host, function() {
//node.log('client connected');
node.connected = true;
client.write(msg.payload);
});

View File

@@ -17,54 +17,41 @@
<!-- The Input Node -->
<script type="text/x-red" data-template-name="udp in">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-sign-in"></i> Listen for</label>
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.listen"></span></label>
<select id="node-input-multicast" style='width:62%'>
<option value="false">udp messages</option>
<option value="true">multicast messages</option>
<option value="false" data-i18n="udp.udpmsgs"></option>
<option value="true" data-i18n="udp.mcmsgs"></option>
</select>
</div>
<div class="form-row node-input-group">
<label for="node-input-group"><i class="fa fa-list"></i> Group</label>
<label for="node-input-group"><i class="fa fa-list"></i> <span data-i18n="udp.label.group"></span></label>
<input type="text" id="node-input-group" placeholder="225.0.18.83">
</div>
<div class="form-row node-input-iface">
<label for="node-input-iface"><i class="fa fa-random"></i> Interface</label>
<input type="text" id="node-input-iface" placeholder="(optional) ip address of eth0">
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceph">
</div>
<div class="form-row">
<label for="node-input-port"><i class="fa fa-sign-in"></i> on Port</label>
<input type="text" id="node-input-port" placeholder="Port" style="width: 80px">
&nbsp;&nbsp;using <select id="node-input-ipv" style="width:80px">
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
<input type="text" id="node-input-port" data-i18n="[placeholder]udp.label.onportph" style="width: 80px">
&nbsp;&nbsp;<span data-i18n="udp.label.using"></span> <select id="node-input-ipv" style="width:80px">
<option value="udp4">ipv4</option>
<option value="udp6">ipv6</option>
</select>
</div>
<div class="form-row">
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> Output</label>
<label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="udp.label.output"></span></label>
<select id="node-input-datatype" style="width: 70%;">
<option value="buffer">a Buffer</option>
<option value="utf8">a String</option>
<option value="base64">a Base64 encoded string</option>
<option value="buffer" data-i18n="udp.buffer"></option>
<option value="utf8" data-i18n="udp.string"></option>
<option value="base64" data-i18n="udp.base64"></option>
</select>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips">Tip: Make sure your firewall will allow the data in.</div>
<script>
$("#node-input-multicast").change(function() {
var id = $("#node-input-multicast option:selected").val();
if (id == "false") {
$(".node-input-group").hide();
$(".node-input-iface").hide();
}
else {
$(".node-input-group").show();
$(".node-input-iface").show();
}
});
</script>
<div class="form-tips"><span data-i18n="udp.in-tip"></span></div>
</script>
<script type="text/x-red" data-help-name="udp in">
@@ -97,6 +84,20 @@
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-multicast").change(function() {
var id = $("#node-input-multicast option:selected").val();
if (id == "false") {
$(".node-input-group").hide();
$(".node-input-iface").hide();
}
else {
$(".node-input-group").show();
$(".node-input-iface").show();
}
});
$("#node-input-multicast").change();
}
});
</script>
@@ -105,62 +106,44 @@
<!-- The Output Node -->
<script type="text/x-red" data-template-name="udp out">
<div class="form-row">
<label for="node-input-port"><i class="fa fa-envelope"></i> Send a</label>
<label for="node-input-port"><i class="fa fa-envelope"></i> <span data-i18n="udp.label.send"></span></label>
<select id="node-input-multicast" style="width:40%">
<option value="false">udp message</option>
<option value="broad">broadcast message</option>
<option value="multi">multicast message</option>
<option value="false" data-i18n="udp.udpmsg"></option>
<option value="broad" data-i18n="udp.bcmsg"></option>
<option value="multi" data-i18n="udp.mcmsg"></option>
</select>
to port <input type="text" id="node-input-port" placeholder="port" style="width: 70px">
<span data-i18n="udp.label.toport"></span> <input type="text" id="node-input-port" data-i18n="[placeholder]udp.label.toportph" style="width: 70px">
</div>
<div class="form-row node-input-addr">
<label for="node-input-addr" id="node-input-addr-label"><i class="fa fa-list"></i> Address</label>
<input type="text" id="node-input-addr" placeholder="destination ip" style="width: 50%;">
<label for="node-input-addr" id="node-input-addr-label"><i class="fa fa-list"></i> <span data-i18n="udp.label.address"></span></label>
<input type="text" id="node-input-addr" data-i18n="[placeholder]udp.label.addressph" style="width: 50%;">
<select id="node-input-ipv" style="width:70px">
<option value="udp4">ipv4</option>
<option value="udp6">ipv6</option>
</select>
</div>
<div class="form-row node-input-iface">
<label for="node-input-iface"><i class="fa fa-random"></i> Interface</label>
<input type="text" id="node-input-iface" placeholder="(optional) ip address of eth0">
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceph">
</div>
<div class="form-row">
<label for="node-input-outport-type">&nbsp;</label>
<select id="node-input-outport-type">
<option id="node-input-outport-type-random" value="random">use random local port</option>
<option value="fixed">bind to local port</option>
<option id="node-input-outport-type-random" value="random" data-i18n="udp.bindrandom"></option>
<option value="fixed" data-i18n="udp.bindlocal"></option>
</select>
<input type="text" id="node-input-outport" style="width: 70px;" placeholder="port">
<input type="text" id="node-input-outport" style="width: 70px;" data-i18n="[placeholder]udp.label.outportph">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-base64" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-base64" style="width: 70%;">Decode Base64 encoded payload ?</label>
<label for="node-input-base64" style="width: 70%;"><span data-i18n="udp.label.decode-base64"></span></label>
</div>
<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">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.nameph">
</div>
<div class="form-tips">Tip: leave address and port blank if you want to set using <b>msg.ip</b> and <b>msg.port</b>.</div>
<script>
$("#node-input-multicast").change(function() {
var id = $("#node-input-multicast option:selected").val();
if (id !== "multi") {
$(".node-input-iface").hide();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> Address');
$("#node-input-addr")[0].placeholder = 'destination ip';
}
else {
$(".node-input-iface").show();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> Group');
$("#node-input-addr")[0].placeholder = '225.0.18.83';
}
if (id === "broad") {
$("#node-input-addr")[0].placeholder = '255.255.255.255';
}
});
</script>
<div class="form-tips"><span data-i18n="[html]udp.out-tip"></span></div>
</script>
<script type="text/x-red" data-help-name="udp out">
@@ -195,6 +178,12 @@
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var addresslabel = this._("udp.label.address");
var addressph = this._("udp.label.addressph");
var grouplabel = this._("udp.label.group");
var bindrandom = this._("udp.bindrandom");
var bindtarget = this._("udp.bindtarget");
var type = this.outport==""?"random":"fixed";
$("#node-input-outport-type option").filter(function() {
return $(this).val() == type;
@@ -208,15 +197,30 @@
$("#node-input-outport").show();
}
});
$("#node-input-outport-type").change();
$("#node-input-multicast").change(function() {
var id = $("#node-input-multicast option:selected").val();
if (id === "multi") {
$(".node-input-iface").show();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + grouplabel);
$("#node-input-addr")[0].placeholder = '225.0.18.83';
}
else if (id === "broad") {
$(".node-input-iface").hide();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + addresslabel);
$("#node-input-addr")[0].placeholder = '255.255.255.255';
}
else {
$(".node-input-iface").hide();
$("#node-input-addr-label").html('<i class="fa fa-list"></i> ' + addresslabel);
$("#node-input-addr")[0].placeholder = addressph;
}
var type = $(this).children("option:selected").val();
if (type == "false") {
$("#node-input-outport-type-random").html("bind to random local port");
$("#node-input-outport-type-random").html(bindrandom);
} else {
$("#node-input-outport-type-random").html("bind to target port");
$("#node-input-outport-type-random").html(bindtarget);
}
});
$("#node-input-multicast").change();

View File

@@ -33,9 +33,9 @@ module.exports = function(RED) {
server.on("error", function (err) {
if ((err.code == "EACCES") && (node.port < 1024)) {
node.error("UDP access error, you may need root access for ports below 1024");
node.error(RED._("udp.errors.access-error"));
} else {
node.error("UDP error : "+err.code);
node.error(RED._("udp.errors.udp-error")+" : "+err.code);
}
server.close();
});
@@ -54,20 +54,20 @@ module.exports = function(RED) {
server.on('listening', function () {
var address = server.address();
node.log('udp listener at ' + address.address + ":" + address.port);
node.log(RED._("udp.errors.listener-at") + ' ' + address.address + ":" + address.port);
if (node.multicast == "true") {
server.setBroadcast(true);
try {
server.setMulticastTTL(128);
server.addMembership(node.group,node.iface);
node.log("udp multicast group "+node.group);
node.log(RED._("udp.errors.mc-group")+" "+node.group);
} catch (e) {
if (e.errno == "EINVAL") {
node.error("Bad Multicast Address");
node.error(RED._("udp.errors.bad-mcaddress"));
} else if (e.errno == "ENODEV") {
node.error("Must be ip address of the required interface");
node.error(RED._("udp.errors.interface"));
} else {
node.error("Error :"+e.errno);
node.error(RED._("udp.errors.error")+" :"+e.errno);
}
}
}
@@ -76,7 +76,7 @@ module.exports = function(RED) {
node.on("close", function() {
try {
server.close();
node.log('udp listener stopped');
node.log(RED._("udp.errors.listener-stopped"));
} catch (err) {
node.error(err);
}
@@ -118,25 +118,25 @@ module.exports = function(RED) {
try {
sock.setMulticastTTL(128);
sock.addMembership(node.addr,node.iface); // Add to the multicast group
node.log('udp multicast ready : '+node.outport+' -> '+node.addr+":"+node.port);
node.log(RED._("udp.errors.mc-ready")+' : '+node.outport+' -> '+node.addr+":"+node.port);
} catch (e) {
if (e.errno == "EINVAL") {
node.error("Bad Multicast Address");
node.error(RED._("udp.errors.bad-mcaddress"));
} else if (e.errno == "ENODEV") {
node.error("Must be ip address of the required interface");
node.error(RED._("udp.errors.interface"));
} else {
node.error("Error :"+e.errno);
node.error(RED._("udp.errors.error")+" :"+e.errno);
}
}
} else {
node.log('udp broadcast ready : '+node.outport+' -> '+node.addr+":"+node.port);
node.log(RED._("udp.errors.bc-ready")+' : '+node.outport+' -> '+node.addr+":"+node.port);
}
});
} else if (node.outport != "") {
sock.bind(node.outport);
node.log('udp ready : '+node.outport+' -> '+node.addr+":"+node.port);
node.log(RED._("udp.errors.ready")+' : '+node.outport+' -> '+node.addr+":"+node.port);
} else {
node.log('udp ready : '+node.addr+":"+node.port);
node.log(RED._("udp.errors.ready")+' : '+node.addr+":"+node.port);
}
node.on("input", function(msg) {
@@ -144,11 +144,11 @@ module.exports = function(RED) {
var add = node.addr || msg.ip || "";
var por = node.port || msg.port || 0;
if (add == "") {
node.warn("udp: ip address not set");
node.warn(RED._("udp.errors.ip-notset"));
} else if (por == 0) {
node.warn("udp: port not set");
node.warn(RED._("udp.errors.port-notset"));
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
node.warn("udp: port number not valid");
node.warn(RED._("udp.errors.port-invalid"));
} else {
var message;
if (node.base64) {
@@ -171,7 +171,7 @@ module.exports = function(RED) {
node.on("close", function() {
try {
sock.close();
node.log('udp output stopped');
node.log(RED._("udp.errors.output-stopped"));
} catch (err) {
node.error(err);
}