mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Move all nodes into core subdirectory
This makes it easier to distinguish core nodes from those added later
This commit is contained in:
121
nodes/core/io/10-mqtt.html
Normal file
121
nodes/core/io/10-mqtt.html
Normal file
@@ -0,0 +1,121 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="mqtt in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="icon-tag"></i> Broker</label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="Topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt in">
|
||||
<p>MQTT input node. Connects to the specified broker and subscribes to the specified topic. The topic may contain MQTT wildcards.</p>
|
||||
<p>Outputs an object called <b>msg</b> containing <b>msg.topic, msg.payload, msg.qos</b> and <b>msg.retain</b>. <b>msg.payload</b> is a String.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt in',{
|
||||
category: 'input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:"",required:true},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#c6dbef",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge.png",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="mqtt out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-broker"><i class="icon-tag"></i> Broker</label>
|
||||
<input type="text" id="node-input-broker">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="Topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="mqtt out">
|
||||
<p>Connects to a MQTT broker and publishes <b>msg.payload</b> either to the <b>msg.topic</b> OR to the topic specified in the edit window. The value in the edit window has precedence.</p>
|
||||
<p><b>msg.qos</b> and <b>msg.retain</b> may also optionally have been set. If not set they are set to 0 and false respectively.</p>
|
||||
<p>If <b>msg.payload</b> contains a buffer or an object it will be stringified before being sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
topic: {value:""},
|
||||
broker: {type:"mqtt-broker", required:true}
|
||||
},
|
||||
color:"#c6dbef",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||this.topic||"mqtt";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<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="icon-bookmark"></i> Broker</label>
|
||||
<input class="input-append-left" type="text" id="node-config-input-broker" placeholder="Broker" 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">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('mqtt-broker',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
broker: {value:"localhost",required:true},
|
||||
port: {value:1883,required:true,validate:RED.validators.number()}
|
||||
},
|
||||
label: function() {
|
||||
return this.broker+":"+this.port;
|
||||
}
|
||||
});
|
||||
</script>
|
90
nodes/core/io/10-mqtt.js
Normal file
90
nodes/core/io/10-mqtt.js
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var connectionPool = require("./lib/mqttConnectionPool");
|
||||
var util = require("util");
|
||||
|
||||
function MQTTBrokerNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.broker = n.broker;
|
||||
this.port = n.port;
|
||||
}
|
||||
RED.nodes.registerType("mqtt-broker",MQTTBrokerNode);
|
||||
|
||||
|
||||
function MQTTInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.topic = n.topic;
|
||||
this.broker = n.broker;
|
||||
this.brokerConfig = RED.nodes.getNode(this.broker);
|
||||
if (this.brokerConfig) {
|
||||
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port);
|
||||
var node = this;
|
||||
this.client.subscribe(this.topic,2,function(topic,payload,qos,retain) {
|
||||
var msg = {topic:topic,payload:payload,qos:qos,retain:retain};
|
||||
if ((node.brokerConfig.broker == "localhost")||(node.brokerConfig.broker == "127.0.0.1")) {
|
||||
msg._topic = topic;
|
||||
}
|
||||
node.send(msg);
|
||||
});
|
||||
this.client.connect();
|
||||
} else {
|
||||
this.error("missing broker configuration");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("mqtt in",MQTTInNode);
|
||||
|
||||
MQTTInNode.prototype.close = function() {
|
||||
if (this.client) {
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function MQTTOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.topic = n.topic;
|
||||
this.broker = n.broker;
|
||||
|
||||
this.brokerConfig = RED.nodes.getNode(this.broker);
|
||||
|
||||
if (this.brokerConfig) {
|
||||
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port);
|
||||
this.on("input",function(msg) {
|
||||
if (msg != null) {
|
||||
if (this.topic) {
|
||||
msg.topic = this.topic;
|
||||
}
|
||||
this.client.publish(msg);
|
||||
}
|
||||
});
|
||||
this.client.connect();
|
||||
} else {
|
||||
this.error("missing broker configuration");
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("mqtt out",MQTTOutNode);
|
||||
|
||||
MQTTOutNode.prototype.close = function() {
|
||||
if (this.client) {
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
|
195
nodes/core/io/21-httpin.html
Normal file
195
nodes/core/io/21-httpin.html
Normal file
@@ -0,0 +1,195 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="http in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="icon-tasks"></i> Method</label>
|
||||
<select type="text" id="node-input-method" style="width: 150px;">
|
||||
<option value="get">GET</option>
|
||||
<option value="post">POST</option>
|
||||
<option value="put">PUT</option>
|
||||
<option value="delete">DELETE</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-globe"></i> url</label>
|
||||
<input type="text" id="node-input-url" placeholder="/url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http in">
|
||||
<p>Provides an input node for http requests, allowing the creation of simple web services.</p>
|
||||
<p>The resulting message has the following properties:
|
||||
<ul>
|
||||
<li>msg.req : <a href="http://expressjs.com/api.html#req">http request</a></li>
|
||||
<li>msg.res : <a href="http://expressjs.com/api.html#res">http response</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>For POST/PUT requests, the body is available under <code>msg.req.body</code>. This
|
||||
uses the <a href="http://expressjs.com/api.html#bodyParser">Express bodyParser middleware</a> to parse the content to a JSON object.
|
||||
</p>
|
||||
<p>
|
||||
By default, this expects the body of the request to be url encoded:
|
||||
<pre>foo=bar&this=that</pre>
|
||||
</p>
|
||||
<p>
|
||||
To send JSON encoded data to the node, the content-type header of the request must be set to
|
||||
<code>application/json</code>.
|
||||
</p>
|
||||
<p>
|
||||
<b>Note: </b>This node does not send any response to the http request. This should be done with
|
||||
a subsequent HTTP Response node, or Function node.
|
||||
In the case of a Function node, the <a href="http://expressjs.com/api.html#res">Express response documentation</a>
|
||||
describes how this should be done. For example:
|
||||
<pre>msg.res.send(200, 'Thanks for the request ');<br/>return msg;</pre>
|
||||
</p>
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http in',{
|
||||
category: 'input',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
url: {value:"",required:true},
|
||||
method: {value:"get",required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||(this.url?("["+this.method+"] "+this.url):"http");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="http response">
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">The messages sent to this node <b>must</b> originate from an <i>http input</i> node</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http response">
|
||||
<p>Sends responses back to http requests received from an HTTP Input node.</p>
|
||||
<p>The response can be customised using the following message properties:</p>
|
||||
<ul>
|
||||
<li><code>payload</code> is sent as the body of the reponse</li>
|
||||
<li><code>statusCode</code>, if set, is used as the response status code (default: 200)</li>
|
||||
<li><code>headers</code>, if set, should be an object containing field/value
|
||||
pairs to be added as response headers.</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http response',{
|
||||
category: 'output',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
align: "right",
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||"http";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="http request">
|
||||
<div class="form-row">
|
||||
<label for="node-input-method"><i class="icon-tasks"></i> Method</label>
|
||||
<select type="text" id="node-input-method" style="width: 150px;">
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-url"><i class="icon-tasks"></i> URL</label>
|
||||
<input type="text" id="node-input-url" placeholder="http://">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="http request">
|
||||
<p>Provides a node for making http requests.</p>
|
||||
<p>The URL and HTTP method can be configured in the node, but also
|
||||
overridden by the incoming message:
|
||||
<ul>
|
||||
<li><code>url</code>, if set, is used as the url of the request</li>
|
||||
<li><code>method</code>, if set, is used as the HTTP method of the request. Must be one of <code>GET</code>, <code>PUT</code>, <code>POST</code> or <code>DELETE</code> (default: GET)</li>
|
||||
<li><code>headers</code>, if set, should be an object containing field/value
|
||||
pairs to be added as request headers</li>
|
||||
<li><code>payload</code> is sent as the body of the request</li>
|
||||
</ul>
|
||||
|
||||
The output message contains the following properties:
|
||||
<ul>
|
||||
<li><code>payload</code> is the body of the response</li>
|
||||
<li><code>statusCode</code> is the status code of the response, or the error code if the request could not be completed</li>
|
||||
<li><code>headers</code> is an object containing the response headers</li>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('http request',{
|
||||
category: 'function',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
method:{value:"GET"},
|
||||
url:{value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
align: "right",
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||"http request";
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
124
nodes/core/io/21-httpin.js
Normal file
124
nodes/core/io/21-httpin.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var util = require("util");
|
||||
var http = require("http");
|
||||
var https = require("https");
|
||||
var urllib = require("url");
|
||||
var express = require("express");
|
||||
var jsonParser = express.json();
|
||||
var urlencParser = express.urlencoded();
|
||||
|
||||
function HTTPIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.url = n.url;
|
||||
this.method = n.method;
|
||||
|
||||
var node = this;
|
||||
this.callback = function(req,res) {
|
||||
if (node.method == "post") { node.send({req:req,res:res,payload:req.body}); }
|
||||
else if (node.method == "get") { node.send({req:req,res:res,payload:req.query}); }
|
||||
else node.send({req:req,res:res});
|
||||
}
|
||||
if (this.method == "get") {
|
||||
RED.app.get(this.url,this.callback);
|
||||
} else if (this.method == "post") {
|
||||
RED.app.post(this.url,jsonParser,urlencParser,this.callback);
|
||||
} else if (this.method == "put") {
|
||||
RED.app.put(this.url,jsonParser,urlencParser,this.callback);
|
||||
} else if (this.method == "delete") {
|
||||
RED.app.delete(this.url,this.callback);
|
||||
}
|
||||
|
||||
this.on("close",function() {
|
||||
var routes = RED.app.routes[this.method];
|
||||
for (var i in routes) {
|
||||
if (routes[i].path == this.url) {
|
||||
routes.splice(i,1);
|
||||
//break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http in",HTTPIn);
|
||||
|
||||
|
||||
function HTTPOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
if (msg.res) {
|
||||
if (msg.headers) {
|
||||
msg.res.set(msg.headers);
|
||||
}
|
||||
var statusCode = msg.statusCode || 200;
|
||||
msg.res.send(statusCode,msg.payload);
|
||||
} else {
|
||||
node.warn("No response object");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http response",HTTPOut);
|
||||
|
||||
function HTTPRequest(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
var url = n.url;
|
||||
var method = n.method || "GET";
|
||||
var httplib = (/^https/.test(url))?https:http;
|
||||
var node = this;
|
||||
this.on("input",function(msg) {
|
||||
|
||||
var opts = urllib.parse(msg.url||url);
|
||||
opts.method = (msg.method||method).toUpperCase();
|
||||
if (msg.headers) {
|
||||
opts.headers = msg.headers;
|
||||
}
|
||||
var req = httplib.request(opts,function(res) {
|
||||
res.setEncoding('utf8');
|
||||
msg.statusCode = res.statusCode;
|
||||
msg.headers = res.headers;
|
||||
msg.payload = "";
|
||||
res.on('data',function(chunk) {
|
||||
msg.payload += chunk;
|
||||
});
|
||||
res.on('end',function() {
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
req.on('error',function(err) {
|
||||
msg.payload = err.toString();
|
||||
msg.statusCode = err.code;
|
||||
node.send(msg);
|
||||
});
|
||||
if (msg.payload && (method == "POST" || method == "PUT") ) {
|
||||
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
|
||||
req.write(msg.payload);
|
||||
} else if (typeof msg.payload == "number") {
|
||||
req.write(msg.payload+"");
|
||||
} else {
|
||||
req.write(JSON.stringify(msg.payload));
|
||||
}
|
||||
}
|
||||
req.end();
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("http request",HTTPRequest);
|
53
nodes/core/io/23-watch.html
Normal file
53
nodes/core/io/23-watch.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="watch">
|
||||
<div class="form-row node-input-filename">
|
||||
<label for="node-input-files"><i class="icon-file"></i> File(s)</label>
|
||||
<input type="text" id="node-input-files" placeholder="File(s) or Directory">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="watch">
|
||||
<p>Watches a file or directory for any changes.</p>
|
||||
<p>You can enter a list of comma separated files, or directories if you like. You will need to put " around any that have spaces in.</p>
|
||||
<p>The filename of the file that actually changed is put into <b>msg.payload</b>, while a stringified version of the watched criteria is returned in <b>msg.topic</b>.</p>
|
||||
<p>Of course in Linux, <i>everything</i> could be a file and thus watched...</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('watch',{
|
||||
category: 'advanced-input',
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
files: {value:"",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "watch.png",
|
||||
label: function() {
|
||||
return this.name||this.files;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
45
nodes/core/io/23-watch.js
Normal file
45
nodes/core/io/23-watch.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var notify = require("fs.notify");
|
||||
|
||||
function WatchNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
|
||||
this.files = n.files.split(",");
|
||||
for (var f in this.files) {
|
||||
this.files[f] = this.files[f].trim();
|
||||
}
|
||||
var node = this;
|
||||
var notifications = new notify(this.files);
|
||||
notifications.on('change', function (file) {
|
||||
node.log('file changed '+file);
|
||||
var msg = { payload: file, topic: JSON.stringify(node.files) };
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
this._close = function() {
|
||||
notifications.close();
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("watch",WatchNode);
|
||||
|
||||
WatchNode.prototype.close = function() {
|
||||
this._close();
|
||||
}
|
||||
|
148
nodes/core/io/25-serial.html
Normal file
148
nodes/core/io/25-serial.html
Normal file
@@ -0,0 +1,148 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="serial in">
|
||||
<div class="form-row node-input-serial">
|
||||
<label for="node-input-serial"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-input-serial">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="serial in">
|
||||
<p>Reads data from a local serial port.</p>
|
||||
<p>Keeps reading from the serial port until it sees \n (default) or the character(s) requested. Only sets <b>msg.payload</b>.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial in',{
|
||||
category: 'input',
|
||||
defaults: {
|
||||
name: {name:""},
|
||||
serial: {type:"serial-port",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "serial.png",
|
||||
label: function() {
|
||||
var serialNode = RED.nodes.node(this.serial);
|
||||
return this.name||(serialNode?serialNode.label():"serial");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="serial out">
|
||||
<div class="form-row node-input-serial">
|
||||
<label for="node-input-serial"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-input-serial">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="serial out">
|
||||
<p>Provides a connection to an outbound serial port.</p>
|
||||
<p>Only the <b>msg.payload</b> is sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial out',{
|
||||
category: 'output',
|
||||
defaults: {
|
||||
name: {name:""},
|
||||
serial: {type:"serial-port",required:true}
|
||||
},
|
||||
color:"BurlyWood",
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "serial.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
var serialNode = RED.nodes.node(this.serial);
|
||||
return this.name||(serialNode?serialNode.label():"serial");
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/x-red" data-template-name="serial-port">
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-serialport"><i class="icon-bullhorn"></i> Serial Port</label>
|
||||
<input type="text" id="node-config-input-serialport" placeholder="/dev/ttyUSB0" style="width:50%;">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-serialbaud"><i class="icon-wrench"></i> Baud Rate</label>
|
||||
<select type="text" id="node-config-input-serialbaud" style="width: 150px;">
|
||||
<option value="115200">115200</option>
|
||||
<option value="57600">57600</option>
|
||||
<option value="38400">38400</option>
|
||||
<option value="19200">19200</option>
|
||||
<option value="9600">9600</option>
|
||||
<option value="4800">4800</option>
|
||||
<option value="2400">2400</option>
|
||||
<option value="1800">1800</option>
|
||||
<option value="1200">1200</option>
|
||||
<option value="600">600</option>
|
||||
<option value="300">300</option>
|
||||
<option value="200">200</option>
|
||||
<option value="150">150</option>
|
||||
<option value="134">134</option>
|
||||
<option value="110">110</option>
|
||||
<option value="75">75</option>
|
||||
<option value="50">50</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-newline"><i class="icon-text-width"></i> New line</label>
|
||||
<input type="text" id="node-config-input-newline">
|
||||
</div>
|
||||
<!--
|
||||
<div class="form-row">
|
||||
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-config-input-name" placeholder="Name">
|
||||
</div>
|
||||
-->
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('serial-port',{
|
||||
category: 'config',
|
||||
defaults: {
|
||||
//name: {value:""},
|
||||
serialport: {value:"",required:true},
|
||||
serialbaud: {value:57600,required:true},
|
||||
newline: {value:"\\n"}
|
||||
},
|
||||
label: function() {
|
||||
//return this.name||this.serialport;
|
||||
return this.serialport+":"+this.serialbaud;
|
||||
}
|
||||
});
|
||||
</script>
|
195
nodes/core/io/25-serial.js
Normal file
195
nodes/core/io/25-serial.js
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var settings = RED.settings;
|
||||
var events = require("events");
|
||||
var util = require("util");
|
||||
var serialp = require("serialport");
|
||||
|
||||
// TODO: 'serialPool' should be encapsulated in SerialPortNode
|
||||
|
||||
function SerialPortNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serialport = n.serialport;
|
||||
this.serialbaud = n.serialbaud * 1;
|
||||
this.newline = n.newline;
|
||||
}
|
||||
RED.nodes.registerType("serial-port",SerialPortNode);
|
||||
|
||||
|
||||
function SerialOutNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serial = n.serial;
|
||||
this.serialConfig = RED.nodes.getNode(this.serial);
|
||||
|
||||
if (this.serialConfig) {
|
||||
var node = this;
|
||||
try {
|
||||
node.port = serialPool.get(this.serialConfig.serialport,this.serialConfig.serialbaud,this.serialConfig.newline);
|
||||
} catch(err) {
|
||||
this.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
node.on("input",function(msg) {
|
||||
//console.log("{",msg,"}");
|
||||
node.port.write(msg.payload,function(err,res) {
|
||||
if (err) {
|
||||
node.error(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.error("missing serial config");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("serial out",SerialOutNode);
|
||||
|
||||
|
||||
SerialOutNode.prototype.close = function() {
|
||||
if (this.serialConfig) {
|
||||
serialPool.close(this.serialConfig.serialport);
|
||||
}
|
||||
}
|
||||
|
||||
function SerialInNode(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.serial = n.serial;
|
||||
this.serialConfig = RED.nodes.getNode(this.serial);
|
||||
|
||||
if (this.serialConfig) {
|
||||
var node = this;
|
||||
try {
|
||||
this.port = serialPool.get(this.serialConfig.serialport,this.serialConfig.serialbaud,this.serialConfig.newline);
|
||||
} catch(err) {
|
||||
this.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.on('data', function(msg) {
|
||||
// console.log("{",msg,"}");
|
||||
var m = { "payload": msg };
|
||||
node.send(m);
|
||||
});
|
||||
} else {
|
||||
this.error("missing serial config");
|
||||
}
|
||||
}
|
||||
RED.nodes.registerType("serial in",SerialInNode);
|
||||
|
||||
|
||||
SerialInNode.prototype.close = function() {
|
||||
if (this.serialConfig) {
|
||||
try {
|
||||
serialPool.close(this.serialConfig.serialport);
|
||||
} catch(err) {
|
||||
}
|
||||
this.warn("Deploying with serial-port nodes is known to occasionally cause Node-RED to hang. This is due to an open issue with the underlying module.");
|
||||
}
|
||||
}
|
||||
|
||||
var serialPool = function() {
|
||||
var connections = {};
|
||||
return {
|
||||
get:function(port,baud,newline,callback) {
|
||||
var id = port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var obj = {
|
||||
_emitter: new events.EventEmitter(),
|
||||
serial: null,
|
||||
_closing: false,
|
||||
tout: null,
|
||||
on: function(a,b) { this._emitter.on(a,b); },
|
||||
close: function(cb) { this.serial.close(cb)},
|
||||
write: function(m,cb) { this.serial.write(m,cb)},
|
||||
}
|
||||
newline = newline.replace("\\n","\n").replace("\\r","\r");
|
||||
var setupSerial = function() {
|
||||
try {
|
||||
if (newline == "") {
|
||||
obj.serial = new serialp.SerialPort(port,{
|
||||
baudrate: baud,
|
||||
parser: serialp.parsers.raw
|
||||
});
|
||||
}
|
||||
else {
|
||||
obj.serial = new serialp.SerialPort(port,{
|
||||
baudrate: baud,
|
||||
parser: serialp.parsers.readline(newline)
|
||||
});
|
||||
}
|
||||
obj.serial.on('error', function(err) {
|
||||
util.log("[serial] serial port "+port+" error "+err);
|
||||
obj.tout = setTimeout(function() {
|
||||
setupSerial();
|
||||
},settings.serialReconnectTime);
|
||||
});
|
||||
obj.serial.on('close', function() {
|
||||
if (!obj._closing) {
|
||||
util.log("[serial] serial port "+port+" closed unexpectedly");
|
||||
obj.tout = setTimeout(function() {
|
||||
setupSerial();
|
||||
},settings.serialReconnectTime);
|
||||
}
|
||||
});
|
||||
obj.serial.on('open',function() {
|
||||
util.log("[serial] serial port "+port+" opened at "+baud+" baud");
|
||||
obj.serial.flush();
|
||||
obj._emitter.emit('ready');
|
||||
});
|
||||
obj.serial.on('data',function(d) {
|
||||
if (typeof d !== "string") {
|
||||
d = d.toString();
|
||||
for (i=0; i<d.length; i++) {
|
||||
obj._emitter.emit('data',d.charAt(i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj._emitter.emit('data',d);
|
||||
}
|
||||
});
|
||||
} catch(err) { console.log("Booo!",err,"Booo!"); }
|
||||
}
|
||||
setupSerial();
|
||||
return obj;
|
||||
}();
|
||||
}
|
||||
return connections[id];
|
||||
},
|
||||
close: function(port) {
|
||||
if (connections[port]) {
|
||||
if (connections[port].tout != null) clearTimeout(connections[port].tout);
|
||||
connections[port]._closing = true;
|
||||
try {
|
||||
connections[port].close(function() {
|
||||
util.log("[serial] serial port closed");
|
||||
});
|
||||
} catch(err) { };
|
||||
}
|
||||
delete connections[port];
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
RED.app.get("/serialports",function(req,res) {
|
||||
serialp.list(function (err, ports) {
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.write(JSON.stringify(ports));
|
||||
res.end();
|
||||
});
|
||||
});
|
187
nodes/core/io/31-tcpin.html
Normal file
187
nodes/core/io/31-tcpin.html
Normal file
@@ -0,0 +1,187 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="tcp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-server"><i class="icon-resize-small"></i> Type</label>
|
||||
<select id="node-input-server" style="width:120px; margin-right:5px;">
|
||||
<option value="server">Listen on</option>
|
||||
<option value="client">Connect to</option>
|
||||
</select>
|
||||
port <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: 40%;">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label><i class="icon-th"></i> Output</label>
|
||||
a
|
||||
<select id="node-input-datamode" style="width:110px;">
|
||||
<option value="stream">stream of</option>
|
||||
<option value="single">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>
|
||||
</select>
|
||||
payload<span id="node-input-datamode-plural">s</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;">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
|
||||
<input type="text" id="node-input-topic" placeholder="Topic">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp in">
|
||||
<p>Provides a choice of tcp inputs. Can either connect to a remote tcp port,
|
||||
or accept incoming connections.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp in',{
|
||||
category: 'input',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
server: {value:"server",required:true},
|
||||
host: {value:"",validate:function(v) { return (this.server == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
datamode:{value:"stream"},
|
||||
datatype:{value:"buffer"},
|
||||
newline:{value:""},
|
||||
topic: {value:""},
|
||||
name: {value:""},
|
||||
base64: {/*deprecated*/ value:false,required:true}
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
var sockettype = $("#node-input-server option:selected").val();
|
||||
if (sockettype == "client") {
|
||||
$("#node-input-host-row").show();
|
||||
} else {
|
||||
$("#node-input-host-row").hide();
|
||||
}
|
||||
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();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-server").change(updateOptions);
|
||||
$("#node-input-datatype").change(updateOptions);
|
||||
$("#node-input-datamode").change(updateOptions);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-template-name="tcp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-beserver"><i class="icon-resize-small"></i> Type</label>
|
||||
<select id="node-input-beserver" style="width:120px; margin-right:5px;">
|
||||
<option value="server">Listen on</option>
|
||||
<option value="client">Connect to</option>
|
||||
</select>
|
||||
port <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: 40%;">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label> </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>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="tcp out">
|
||||
<p>Provides a choice of tcp outputs. Can either connect to a remote tcp port,
|
||||
or accept incoming connections.</p>
|
||||
<p>Only <b>msg.payload</b> is sent.</p>
|
||||
<p>If <b>msg.payload</b> is a string containing a base64 encoding of binary
|
||||
data, the Base64 decoding option will cause it to be converted back to binary
|
||||
before being sent.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('tcp out',{
|
||||
category: 'output',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
host: {value:"",validate:function(v) { return (this.beserver == "server")||v.length > 0;} },
|
||||
port: {value:"",required:true},
|
||||
beserver: {value:"client",required:true},
|
||||
base64: {value:false,required:true},
|
||||
name: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name || "tcp:"+(this.host?this.host+":":"")+this.port;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return (this.name)?"node_label_italic":"";
|
||||
},
|
||||
oneditprepare: function() {
|
||||
var updateOptions = function() {
|
||||
var sockettype = $("#node-input-beserver option:selected").val();
|
||||
if (sockettype == "client") {
|
||||
$("#node-input-host-row").show();
|
||||
} else {
|
||||
$("#node-input-host-row").hide();
|
||||
}
|
||||
};
|
||||
updateOptions();
|
||||
$("#node-input-beserver").change(updateOptions);
|
||||
}
|
||||
});
|
||||
</script>
|
253
nodes/core/io/31-tcpin.js
Normal file
253
nodes/core/io/31-tcpin.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||
var net = require('net');
|
||||
|
||||
function TcpIn(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.host = n.host;
|
||||
this.port = n.port * 1;
|
||||
this.topic = n.topic;
|
||||
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
|
||||
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||
this.base64 = n.base64;
|
||||
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||
this.closing = false;
|
||||
var node = this;
|
||||
|
||||
if (!node.server) {
|
||||
var buffer = null;
|
||||
var client;
|
||||
var reconnectTimeout;
|
||||
function setupTcpClient() {
|
||||
node.log("connecting to "+node.host+":"+node.port);
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||
node.log("connected to "+node.host+":"+node.port);
|
||||
});
|
||||
|
||||
client.on('data', function (data) {
|
||||
if (node.datatype != 'buffer') {
|
||||
data = data.toString(node.datatype);
|
||||
}
|
||||
if (node.stream) {
|
||||
if ((node.datatype) === "utf8" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0;i<parts.length-1;i+=1) {
|
||||
var msg = {topic:node.topic, payload:parts[i]};
|
||||
node.send(msg);
|
||||
}
|
||||
buffer = parts[parts.length-1];
|
||||
} else {
|
||||
var msg = {topic:node.topic, payload:data};
|
||||
node.send(msg);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
client.on('end', function() {
|
||||
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||
var msg = {topic:node.topic,payload:buffer};
|
||||
node.send(msg);
|
||||
buffer = null;
|
||||
}
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
node.log("connection lost to "+node.host+":"+node.port);
|
||||
if (!node.closing) {
|
||||
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('error', function(err) {
|
||||
node.log(err);
|
||||
});
|
||||
}
|
||||
setupTcpClient();
|
||||
|
||||
this.on('close', function() {
|
||||
this.closing = true;
|
||||
client.end();
|
||||
clearTimeout(reconnectTimeout);
|
||||
});
|
||||
} else {
|
||||
var server = net.createServer(function (socket) {
|
||||
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
|
||||
socket.on('data', function (data) {
|
||||
if (node.datatype != 'buffer') {
|
||||
data = data.toString(node.datatype);
|
||||
}
|
||||
|
||||
if (node.stream) {
|
||||
if ((typeof data) === "string" && node.newline != "") {
|
||||
buffer = buffer+data;
|
||||
var parts = buffer.split(node.newline);
|
||||
for (var i = 0;i<parts.length-1;i+=1) {
|
||||
var msg = {topic:node.topic, payload:parts[i],ip:socket.remoteAddress,port:socket.remotePort};
|
||||
node.send(msg);
|
||||
}
|
||||
buffer = parts[parts.length-1];
|
||||
} else {
|
||||
var msg = {topic:node.topic, payload:data};
|
||||
node.send(msg);
|
||||
}
|
||||
} else {
|
||||
if ((typeof data) === "string") {
|
||||
buffer = buffer+data;
|
||||
} else {
|
||||
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
|
||||
}
|
||||
}
|
||||
});
|
||||
socket.on('end', function() {
|
||||
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
|
||||
var msg = {topic:node.topic,payload:buffer};
|
||||
node.send(msg);
|
||||
buffer = null;
|
||||
}
|
||||
});
|
||||
socket.on('error',function(err) {
|
||||
node.log(err);
|
||||
});
|
||||
});
|
||||
server.listen(node.port);
|
||||
node.log('listening on port '+node.port);
|
||||
|
||||
this.on('close', function() {
|
||||
this.closing = true;
|
||||
server.close();
|
||||
node.log('stopped listening on port '+node.port);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tcp in",TcpIn);
|
||||
|
||||
function TcpOut(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.host = n.host;
|
||||
this.port = n.port * 1;
|
||||
this.base64 = n.base64;
|
||||
this.beserver = n.beserver;
|
||||
this.name = n.name;
|
||||
this.closing = false;
|
||||
var node = this;
|
||||
|
||||
if (!node.beserver||node.beserver=="client") {
|
||||
var reconnectTimeout;
|
||||
var client = null;
|
||||
var connected = false;
|
||||
|
||||
function setupTcpClient() {
|
||||
node.log("connecting to "+node.host+":"+node.port);
|
||||
client = net.connect(node.port, node.host, function() {
|
||||
connected = true;
|
||||
node.log("connected to "+node.host+":"+node.port);
|
||||
});
|
||||
|
||||
client.on('error', function (err) {
|
||||
node.log('error : '+err);
|
||||
});
|
||||
|
||||
client.on('end', function (err) {
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
node.log("connection lost to "+node.host+":"+node.port);
|
||||
connected = false;
|
||||
client.destroy();
|
||||
if (!node.closing) {
|
||||
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
setupTcpClient();
|
||||
|
||||
|
||||
node.on("input", function(msg) {
|
||||
if (connected && msg.payload != null) {
|
||||
if (Buffer.isBuffer(msg.payload)) {
|
||||
client.write(msg.payload);
|
||||
} else if (typeof msg.payload === "string" && node.base64) {
|
||||
client.write(new Buffer(msg.payload,'base64'));
|
||||
} else {
|
||||
client.write(new Buffer(""+msg.payload));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
this.closing = true;
|
||||
client.end();
|
||||
clearTimeout(reconnectTimeout);
|
||||
});
|
||||
|
||||
} else {
|
||||
var connectedSockets = [];
|
||||
var server = net.createServer(function (socket) {
|
||||
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
|
||||
node.log("connection from "+remoteDetails);
|
||||
connectedSockets.push(socket);
|
||||
socket.on('close',function() {
|
||||
node.log("connection closed from "+remoteDetails);
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
});
|
||||
socket.on('error',function() {
|
||||
node.log("socket error from "+remoteDetails);
|
||||
connectedSockets.splice(connectedSockets.indexOf(socket),1);
|
||||
});
|
||||
|
||||
});
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload != null) {
|
||||
var buffer;
|
||||
if (Buffer.isBuffer(msg.payload)) {
|
||||
buffer = msg.payload;
|
||||
} else if (typeof msg.payload === "string" && node.base64) {
|
||||
buffer = new Buffer(msg.payload,'base64');
|
||||
} else {
|
||||
buffer = new Buffer(""+msg.payload);
|
||||
}
|
||||
for (var i = 0; i<connectedSockets.length;i+=1) {
|
||||
connectedSockets[i].write(buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(node.port);
|
||||
node.log('listening on port '+node.port);
|
||||
|
||||
node.on('close', function() {
|
||||
server.close();
|
||||
node.log('stopped listening on port '+node.port);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RED.nodes.registerType("tcp out",TcpOut);
|
||||
|
||||
|
178
nodes/core/io/32-udp.html
Normal file
178
nodes/core/io/32-udp.html
Normal file
@@ -0,0 +1,178 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- The Input Node -->
|
||||
<script type="text/x-red" data-template-name="udp in">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="icon-inbox"></i> Listen</label>
|
||||
on port <input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
for <select id="node-input-multicast" style='width:40%'>
|
||||
<option value="false">udp messages</option>
|
||||
<option value="true">multicast messages</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row node-input-group">
|
||||
<label for="node-input-group"><i class="icon-list"></i> Group</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="icon-random"></i> Interface</label>
|
||||
<input type="text" id="node-input-iface" placeholder="eth0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-datatype"><i class="icon-file"></i> Output</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>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</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>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="udp in">
|
||||
<p>A udp input node, that produces a <b>msg.payload</b> containing a <i>BUFFER</i>, string, or base64 encoded string. Supports multicast.</p>
|
||||
<p>It also provides <b>msg.ip</b> and <b>msg.port</b> to the ip address and port from which the message was received.</b>
|
||||
<p>On some systems you may need to be root to use ports below 1024 and/or broadcast.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('udp in',{
|
||||
category: 'input',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
host: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:"",required:true,validate:RED.validators.number()},
|
||||
datatype: {value:"buffer",required:true},
|
||||
multicast: {value:"false"},
|
||||
group: {value:"",validate:function(v) { return (this.multicast !== "true")||v.length > 0;} }
|
||||
},
|
||||
inputs:0,
|
||||
outputs:1,
|
||||
icon: "bridge-dash.png",
|
||||
label: function() {
|
||||
if (this.multicast=="false") {
|
||||
return this.name||"udp "+this.port;
|
||||
}
|
||||
else return this.name||"udp "+(this.group+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<!-- The Output Node -->
|
||||
<script type="text/x-red" data-template-name="udp out">
|
||||
<div class="form-row">
|
||||
<label for="node-input-port"><i class="icon-envelope"></i> Send a</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>
|
||||
</select>
|
||||
to port <input type="text" id="node-input-port" placeholder="Port" style="width: 45px">
|
||||
</div>
|
||||
<div class="form-row node-input-addr">
|
||||
<label for="node-input-addr" id="node-input-addr-label"><i class="icon-list"></i> Address</label>
|
||||
<input type="text" id="node-input-addr" placeholder="destination ip" style="width: 70%;">
|
||||
</div>
|
||||
<div class="form-row node-input-iface">
|
||||
<label for="node-input-iface"><i class="icon-random"></i> Interface</label>
|
||||
<input type="text" id="node-input-iface" placeholder="eth0">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </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 encoded payload ?</label>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</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();
|
||||
console.log(id,$("#node-input-addr")[0].placeholder);
|
||||
if (id !== "multi") {
|
||||
$(".node-input-iface").hide();
|
||||
$("#node-input-addr-label").html('<i class="icon-list"></i> Address');
|
||||
$("#node-input-addr")[0].placeholder = 'destination ip';
|
||||
}
|
||||
else {
|
||||
$(".node-input-iface").show();
|
||||
$("#node-input-addr-label").html('<i class="icon-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>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="udp out">
|
||||
<p>This node sends <b>msg.payload</b> to the designated udp host and port. Supports multicast.</p>
|
||||
<p>You may also use <b>msg.ip</b> and <b>msg.port</b> to set the destination values.<br/><b>Note</b>: the statically configured values have precedence.</p>
|
||||
<p>If you select broadcast either set the address to the local broadcast ip address, or maybe try 255.255.255.255, which is the global broadcast address.</p>
|
||||
<p>On some systems you may need to be root to use ports below 1024 and/or broadcast.</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('udp out',{
|
||||
category: 'output',
|
||||
color:"Silver",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
addr: {value:""},
|
||||
iface: {value:""},
|
||||
port: {value:""},
|
||||
base64: {value:false,required:true},
|
||||
multicast: {value:"false"}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:0,
|
||||
icon: "bridge-dash.png",
|
||||
align: "right",
|
||||
label: function() {
|
||||
return this.name||"udp "+(this.addr+":"+this.port);
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
124
nodes/core/io/32-udp.js
Normal file
124
nodes/core/io/32-udp.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
var dgram = require('dgram');
|
||||
|
||||
// The Input Node
|
||||
function UDPin(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.host = n.host || null;
|
||||
this.datatype = n.datatype;
|
||||
this.iface = n.iface || null;
|
||||
this.multicast = n.multicast;
|
||||
var node = this;
|
||||
|
||||
var server = dgram.createSocket('udp4');
|
||||
|
||||
server.on("error", function (err) {
|
||||
//console.log("udp listener error:\n" + err.stack);
|
||||
if ((err.code == "EACCES") && (node.port < 1024)) { node.error("UDP access error, you may need root access for ports below 1024"); }
|
||||
else { node.error("UDP error : "+err.code); }
|
||||
server.close();
|
||||
});
|
||||
|
||||
server.on('message', function (message, remote) {
|
||||
var msg;
|
||||
if (node.datatype =="base64") { msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port }; }
|
||||
else if (node.datatype =="utf8") { msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port }; }
|
||||
else { msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port }; }
|
||||
node.send(msg);
|
||||
});
|
||||
|
||||
server.on('listening', function () {
|
||||
var address = server.address();
|
||||
node.log('udp listener at ' + address.address + ":" + address.port);
|
||||
if (node.multicast == "true") {
|
||||
server.setBroadcast(true)
|
||||
server.setMulticastTTL(128);
|
||||
server.addMembership(node.group,node.iface);
|
||||
node.log("udp multicast group "+node.group);
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
try {
|
||||
server.close();
|
||||
node.log('udp listener stopped');
|
||||
}
|
||||
catch (err) { console.log(err); }
|
||||
});
|
||||
|
||||
server.bind(node.port,node.host);
|
||||
}
|
||||
RED.nodes.registerType("udp in",UDPin);
|
||||
|
||||
|
||||
// The Output Node
|
||||
function UDPout(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
//this.group = n.group;
|
||||
this.port = n.port;
|
||||
this.base64 = n.base64;
|
||||
this.addr = n.addr;
|
||||
this.iface = n.iface || null;
|
||||
this.multicast = n.multicast;
|
||||
var node = this;
|
||||
|
||||
var sock = dgram.createSocket('udp4'); // only use ipv4 for now
|
||||
sock.bind(node.port); // have to bind before you can enable broadcast...
|
||||
if (this.multicast != "false") {
|
||||
sock.setBroadcast(true); // turn on broadcast
|
||||
if (this.multicast == "multi") {
|
||||
sock.setMulticastTTL(128);
|
||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||
node.log('udp multicast ready : '+node.addr+":"+node.port);
|
||||
}
|
||||
else node.log('udp broadcast ready : '+node.addr+":"+node.port);
|
||||
}
|
||||
else node.log('udp ready : '+node.addr+":"+node.port);
|
||||
|
||||
node.on("input", function(msg) {
|
||||
if (msg.payload != null) {
|
||||
var add = node.addr || msg.ip || "";
|
||||
var por = node.port || msg.port || 0;
|
||||
if (add == "") { node.warn("udp: ip address not set"); }
|
||||
else if (por == 0) { node.warn("udp: port not set"); }
|
||||
else if (isNaN(por) || (por < 1) || (por > 65535)) { node.warn("udp: port number not valid"); }
|
||||
else {
|
||||
var message;
|
||||
if (node.base64) { message = new Buffer(b64string, 'base64'); }
|
||||
else if (msg.payload instanceof Buffer) { message = msg.payload; }
|
||||
else { message = new Buffer(""+msg.payload); }
|
||||
console.log("UDP send :",add,por,msg.payload.toString());
|
||||
sock.send(message, 0, message.length, por, add, function(err, bytes) {
|
||||
if (err) node.error("udp : "+err);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
node.on("close", function() {
|
||||
try {
|
||||
sock.close();
|
||||
node.log('udp output stopped');
|
||||
}
|
||||
catch (err) { console.log(err); }
|
||||
});
|
||||
}
|
||||
RED.nodes.registerType("udp out",UDPout);
|
61
nodes/core/io/90-httpget.html
Normal file
61
nodes/core/io/90-httpget.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!--
|
||||
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/x-red" data-template-name="httpget">
|
||||
<div class="form-tips"><b>Deprecated</b>: please use the <i>http request</i> node.</div>
|
||||
<br>
|
||||
<div class="form-row">
|
||||
<label for="node-input-baseurl"><i class="icon-tasks"></i> Base URL</label>
|
||||
<input type="text" id="node-input-baseurl" placeholder="http(s)://url">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-append"><i class="icon-tasks"></i> Append</label>
|
||||
<input type="text" id="node-input-append" placeholder="">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||
<input type="text" id="node-input-name" placeholder="Name">
|
||||
</div>
|
||||
<div class="form-tips">The <b>Base URL</b> gets prepended to whatever payload is passed in. Leave blank if you pass in a full url.<br/>The append gets added to the end after any payload.<br/>The output Topic is the same as the input Topic.</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-red" data-help-name="httpget">
|
||||
<p>Performs an HTTP or HTTPS GET and returns the fetched page.</p>
|
||||
<p>The return code is placed in <b>msg.rc</b>, and the full text of the result is in <b>msg.payload</b>.</p>
|
||||
<p>The <b>msg.payload</b> is added to the base url, and then the optional append is added after.</p>
|
||||
<p>This is mostly suitable for small pages as large results will need a lot of parsing....</p>
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
RED.nodes.registerType('httpget',{
|
||||
category: 'advanced-function',
|
||||
color:"rgb(231, 231, 174)",
|
||||
defaults: {
|
||||
name: {value:""},
|
||||
baseurl: {value:""},
|
||||
append: {value:""}
|
||||
},
|
||||
inputs:1,
|
||||
outputs:1,
|
||||
icon: "white-globe.png",
|
||||
label: function() {
|
||||
return this.name||this.baseurl;
|
||||
},
|
||||
labelStyle: function() {
|
||||
return this.name?"node_label_italic":"";
|
||||
}
|
||||
});
|
||||
</script>
|
52
nodes/core/io/90-httpget.js
Normal file
52
nodes/core/io/90-httpget.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
var RED = require(process.env.NODE_RED_HOME+"/red/red");
|
||||
|
||||
function HttpGet(n) {
|
||||
RED.nodes.createNode(this,n);
|
||||
this.baseurl = n.baseurl || "";
|
||||
this.append = n.append || "";
|
||||
var node = this;
|
||||
if (this.baseurl.substring(0,5) === "https") { var http = require("https"); }
|
||||
else { var http = require("http"); }
|
||||
this.on("input", function(msg) {
|
||||
msg._payload = msg.payload;
|
||||
//util.log("[httpget] "+this.baseurl+msg.payload+this.append);
|
||||
http.get(this.baseurl+msg.payload+this.append, function(res) {
|
||||
node.log("Http response: " + res.statusCode);
|
||||
msg.rc = res.statusCode;
|
||||
msg.payload = "";
|
||||
if ((msg.rc != 200) && (msg.rc != 404)) {
|
||||
node.send(msg);
|
||||
}
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', function(chunk) {
|
||||
msg.payload += chunk;
|
||||
});
|
||||
res.on('end', function() {
|
||||
node.send(msg);
|
||||
});
|
||||
}).on('error', function(e) {
|
||||
//node.error(e);
|
||||
msg.rc = 503;
|
||||
msg.payload = e;
|
||||
node.send(msg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
RED.nodes.registerType("httpget",HttpGet);
|
225
nodes/core/io/lib/mqtt.js
Normal file
225
nodes/core/io/lib/mqtt.js
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
var util = require("util");
|
||||
var mqtt = require("mqtt");
|
||||
var events = require("events");
|
||||
|
||||
//var Client = module.exports.Client = function(
|
||||
|
||||
var port = 1883;
|
||||
var host = "localhost";
|
||||
|
||||
function MQTTClient(port,host) {
|
||||
this.port = port||1883;
|
||||
this.host = host||"localhost";
|
||||
this.messageId = 1;
|
||||
this.pendingSubscriptions = {};
|
||||
this.inboundMessages = {};
|
||||
this.lastOutbound = (new Date()).getTime();
|
||||
this.lastInbound = (new Date()).getTime();
|
||||
this.connected = false;
|
||||
|
||||
this._nextMessageId = function() {
|
||||
this.messageId += 1;
|
||||
if (this.messageId > 0xFFFF) {
|
||||
this.messageId = 1;
|
||||
}
|
||||
return this.messageId;
|
||||
}
|
||||
events.EventEmitter.call(this);
|
||||
}
|
||||
util.inherits(MQTTClient, events.EventEmitter);
|
||||
|
||||
MQTTClient.prototype.connect = function(options) {
|
||||
var self = this;
|
||||
options = options||{};
|
||||
self.options = options;
|
||||
self.options.keepalive = options.keepalive||15;
|
||||
self.options.clean = self.options.clean||true;
|
||||
self.options.protocolId = 'MQIsdp';
|
||||
self.options.protocolVersion = 3;
|
||||
|
||||
self.client = mqtt.createConnection(this.port,this.host,function(err,client) {
|
||||
if (err) {
|
||||
self.emit('connectionlost',err);
|
||||
return;
|
||||
}
|
||||
client.on('close',function(e) {
|
||||
clearInterval(self.watchdog);
|
||||
if (self.connected) {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost',e);
|
||||
} else {
|
||||
self.emit('disconnect');
|
||||
}
|
||||
});
|
||||
client.on('error',function(e) {
|
||||
clearInterval(self.watchdog);
|
||||
if (self.connected) {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost',e);
|
||||
}
|
||||
});
|
||||
client.on('connack',function(packet) {
|
||||
if (packet.returnCode == 0) {
|
||||
self.watchdog = setInterval(function(self) {
|
||||
var now = (new Date()).getTime();
|
||||
if (now - self.lastOutbound > self.options.keepalive*500 || now - self.lastInbound > self.options.keepalive*500) {
|
||||
if (self.pingOutstanding) {
|
||||
// DO DISCONNECT
|
||||
} else {
|
||||
self.lastOutbound = (new Date()).getTime();
|
||||
self.lastInbound = (new Date()).getTime();
|
||||
self.pingOutstanding = true;
|
||||
self.client.pingreq();
|
||||
}
|
||||
}
|
||||
|
||||
},self.options.keepalive*500,self);
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.connected = true;
|
||||
self.emit('connect');
|
||||
} else {
|
||||
self.connected = false;
|
||||
self.emit('connectionlost');
|
||||
}
|
||||
});
|
||||
client.on('suback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var topic = self.pendingSubscriptions[packet.messageId];
|
||||
self.emit('subscribe',topic,packet.granted[0]);
|
||||
delete self.pendingSubscriptions[packet.messageId];
|
||||
});
|
||||
client.on('unsuback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var topic = self.pendingSubscriptions[packet.messageId];
|
||||
self.emit('unsubscribe',topic,packet.granted[0]);
|
||||
delete self.pendingSubscriptions[packet.messageId];
|
||||
});
|
||||
client.on('publish',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
if (packet.qos < 2) {
|
||||
var p = packet;
|
||||
self.emit('message',p.topic,p.payload,p.qos,p.retain);
|
||||
} else {
|
||||
self.inboundMessages[packet.messageId] = packet;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubrec(packet);
|
||||
}
|
||||
if (packet.qos == 1) {
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.puback(packet);
|
||||
}
|
||||
});
|
||||
|
||||
client.on('pubrel',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
var p = self.inboundMessages[packet.messageId];
|
||||
self.emit('message',p.topic,p.payload,p.qos,p.retain);
|
||||
delete self.inboundMessages[packet.messageId];
|
||||
self.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubcomp(packet);
|
||||
});
|
||||
|
||||
client.on('puback',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
// outbound qos-1 complete
|
||||
});
|
||||
|
||||
client.on('pubrec',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.lastOutbound = (new Date()).getTime()
|
||||
self.client.pubrel(packet);
|
||||
});
|
||||
client.on('pubcomp',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
// outbound qos-2 complete
|
||||
});
|
||||
client.on('pingresp',function(packet) {
|
||||
self.lastInbound = (new Date()).getTime()
|
||||
self.pingOutstanding = false;
|
||||
});
|
||||
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
client.connect(self.options);
|
||||
});
|
||||
}
|
||||
|
||||
MQTTClient.prototype.subscribe = function(topic,qos) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
var options = {
|
||||
subscriptions:[{topic:topic,qos:qos}],
|
||||
messageId: self._nextMessageId()
|
||||
};
|
||||
this.pendingSubscriptions[options.messageId] = topic;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.subscribe(options);
|
||||
}
|
||||
}
|
||||
MQTTClient.prototype.unsubscribe = function(topic) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
var options = {
|
||||
topic:topic,
|
||||
messageId: self._nextMessageId()
|
||||
};
|
||||
this.pendingSubscriptions[options.messageId] = topic;
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.unsubscribe(options);
|
||||
}
|
||||
}
|
||||
|
||||
MQTTClient.prototype.publish = function(topic,payload,qos,retain) {
|
||||
var self = this;
|
||||
if (self.connected) {
|
||||
|
||||
if (Buffer.isBuffer(payload)) {
|
||||
payload = payload.toString();
|
||||
} else if (typeof payload === "object") {
|
||||
payload = JSON.stringify(payload);
|
||||
} else if (typeof payload !== "string") {
|
||||
payload = ""+payload;
|
||||
}
|
||||
var options = {
|
||||
topic: topic,
|
||||
payload: payload,
|
||||
qos: qos||0,
|
||||
retain:retain||false
|
||||
};
|
||||
if (options.qos != 0) {
|
||||
options.messageId = self._nextMessageId();
|
||||
}
|
||||
this.lastOutbound = (new Date()).getTime()
|
||||
self.client.publish(options);
|
||||
}
|
||||
}
|
||||
|
||||
MQTTClient.prototype.disconnect = function() {
|
||||
var self = this;
|
||||
if (this.connected) {
|
||||
this.connected = false;
|
||||
this.client.disconnect();
|
||||
}
|
||||
}
|
||||
MQTTClient.prototype.isConnected = function() {
|
||||
return this.connected;
|
||||
}
|
||||
module.exports.createClient = function(port,host) {
|
||||
var mqtt_client = new MQTTClient(port,host);
|
||||
return mqtt_client;
|
||||
}
|
||||
|
120
nodes/core/io/lib/mqttConnectionPool.js
Normal file
120
nodes/core/io/lib/mqttConnectionPool.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
var util = require("util");
|
||||
var mqtt = require("./mqtt");
|
||||
var settings = require(process.env.NODE_RED_HOME+"/red/red").settings;
|
||||
|
||||
var connections = {};
|
||||
|
||||
function matchTopic(ts,t) {
|
||||
var re = new RegExp("^"+ts.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/#$/,".*"));
|
||||
return re.test(t);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: function(broker,port) {
|
||||
var id = broker+":"+port;
|
||||
if (!connections[id]) {
|
||||
connections[id] = function() {
|
||||
var client = mqtt.createClient(port,broker);
|
||||
client.setMaxListeners(0);
|
||||
var options = {keepalive:15,clientId:'mqtt_' + (1+Math.random()*4294967295).toString(16)};
|
||||
var queue = [];
|
||||
var subscriptions = [];
|
||||
var connecting = false;
|
||||
var obj = {
|
||||
_instances: 0,
|
||||
publish: function(msg) {
|
||||
if (client.isConnected()) {
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
} else {
|
||||
if (!connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
queue.push(msg);
|
||||
}
|
||||
},
|
||||
subscribe: function(topic,qos,callback) {
|
||||
subscriptions.push({topic:topic,qos:qos,callback:callback});
|
||||
client.on('message',function(mtopic,mpayload,mqos,mretain) {
|
||||
if (matchTopic(topic,mtopic)) {
|
||||
callback(mtopic,mpayload,mqos,mretain);
|
||||
}
|
||||
});
|
||||
if (client.isConnected()) {
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
},
|
||||
on: function(a,b){
|
||||
client.on(a,b);
|
||||
},
|
||||
once: function(a,b){
|
||||
client.once(a,b);
|
||||
},
|
||||
connect: function() {
|
||||
if (!client.isConnected() && !connecting) {
|
||||
connecting = true;
|
||||
client.connect(options);
|
||||
}
|
||||
},
|
||||
disconnect: function() {
|
||||
this._instances -= 1;
|
||||
if (this._instances == 0) {
|
||||
client.disconnect();
|
||||
client = null;
|
||||
delete connections[id];
|
||||
}
|
||||
}
|
||||
};
|
||||
client.on('connect',function() {
|
||||
|
||||
util.log('[mqtt] connected to broker tcp://'+broker+':'+port);
|
||||
|
||||
connecting = false;
|
||||
for (var s in subscriptions) {
|
||||
var topic = subscriptions[s].topic;
|
||||
var qos = subscriptions[s].qos;
|
||||
var callback = subscriptions[s].callback;
|
||||
client.subscribe(topic,qos);
|
||||
}
|
||||
//console.log("connected - publishing",queue.length,"messages");
|
||||
while(queue.length) {
|
||||
var msg = queue.shift();
|
||||
//console.log(msg);
|
||||
client.publish(msg.topic,msg.payload,msg.qos,msg.retain);
|
||||
}
|
||||
});
|
||||
client.on('connectionlost', function(err) {
|
||||
util.log('[mqtt] connection lost to broker tcp://'+broker+':'+port);
|
||||
setTimeout(function() {
|
||||
if (client) {
|
||||
client.connect(options);
|
||||
}
|
||||
}, settings.mqttReconnectTime||5000);
|
||||
});
|
||||
client.on('disconnect', function() {
|
||||
util.log('[mqtt] disconnected from broker tcp://'+broker+':'+port);
|
||||
});
|
||||
|
||||
return obj
|
||||
}();
|
||||
}
|
||||
connections[id]._instances += 1;
|
||||
return connections[id];
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user