├── twilio
├── icons
│ └── twilio.png
├── 56-twilio-cf.js
└── 56-twilio-cf.html
├── mqlight
├── icons
│ ├── mqlight.png
│ └── mqlightin.png
├── mqlight.js
└── mqlight.html
├── weather
├── icons
│ └── weather.png
├── weather_insights.js
└── weather_insights.html
├── .jshintrc
├── package.json
├── README.md
├── io
├── 32-udp-cf.js
├── 32-udp-cf.html
├── 31-tcpin-cf.html
└── 31-tcpin-cf.js
├── LICENSE
└── mongo
├── 66-mongodb-cf.js
└── 66-mongodb-cf.html
/twilio/icons/twilio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnwalicki/node-red-bluemix-nodes/master/twilio/icons/twilio.png
--------------------------------------------------------------------------------
/mqlight/icons/mqlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnwalicki/node-red-bluemix-nodes/master/mqlight/icons/mqlight.png
--------------------------------------------------------------------------------
/weather/icons/weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnwalicki/node-red-bluemix-nodes/master/weather/icons/weather.png
--------------------------------------------------------------------------------
/mqlight/icons/mqlightin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnwalicki/node-red-bluemix-nodes/master/mqlight/icons/mqlightin.png
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "asi": true, // allow missing semicolons
3 | "curly": true, // require braces
4 | "eqnull": true, // ignore ==null
5 | "forin": true, // require property filtering in "for in" loops
6 | "immed": true, // require immediate functions to be wrapped in ( )
7 | "nonbsp": true, // warn on unexpected whitespace breaking chars
8 | //"strict": true, // commented out for now as it causes 100s of warnings, but want to get there eventually
9 | //"unused": true, // Check for unused functions and variables
10 | "loopfunc": true, // allow functions to be defined in loops
11 | //"expr": true, // allow ternery operator syntax...
12 | "sub": true // don't warn that foo['bar'] should be written as foo.bar
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-red-bluemix-nodes",
3 | "version": "1.0.3",
4 | "description": "A collection of extra Node-RED nodes for IBM Bluemix.",
5 | "dependencies": {
6 | "cfenv": "~1.0.0",
7 | "mongodb": "~1.4.x",
8 | "mqlight": ">=1.0.2014091000",
9 | "request": "~2.53.0",
10 | "twilio": "~1.6.0",
11 | "when": "~3.x"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/node-red/node-red-bluemix-nodes"
16 | },
17 | "license": "Apache-2.0",
18 | "keywords": [
19 | "node-red",
20 | "bluemix",
21 | "io",
22 | "tcp",
23 | "udp",
24 | "mongodb",
25 | "twilio",
26 | "mqlight"
27 | ],
28 | "node-red": {
29 | "nodes": {
30 | "tcp": "io/31-tcpin-cf.js",
31 | "udp": "io/32-udp-cf.js",
32 | "mqlight": "mqlight/mqlight.js",
33 | "mongodb": "mongo/66-mongodb-cf.js",
34 | "twilio": "twilio/56-twilio-cf.js",
35 | "weather": "weather/weather_insights.js"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Node-RED Nodes for IBM Bluemix
2 | ==============================
3 |
4 | A collection of nodes to be used with Node-RED in [IBM Bluemix](http://bluemix.net/).
5 |
6 | # Nodes
7 |
8 | The current release contains the following nodes:
9 |
10 | - TCP
11 | - Provides TCP input and output clients
12 | - Connects to remote TCP port and replies to messages from an input client
13 | - UDP
14 | - Sends a message to the designated UDP host and port
15 | - MQ Light
16 | - Provides MQ Light receive and send clients
17 | - Publishes and subscribes to chosen topics
18 | - MongoDB
19 | - Perform save, insert, update or remove operations
20 | - Perform find, count and aggregate operations
21 | - Twilio
22 | - Sends an SMS message using the Twilio service
23 | - Weather
24 | - Access historical and real-time weather data from The Weather Company
25 |
26 | Prior to version 1.0.1, this module also included nodes for the IBM Watson and Alchemy
27 | services. They have now been moved to [node-red-node-watson](http://flows.nodered.org/node/node-red-node-watson).
28 |
29 | ### Contributing
30 |
31 | For simple typos and single line fixes please just raise an issue pointing out
32 | our mistakes. If you need to raise a pull request please read our
33 | [contribution guidelines](https://github.com/node-red/node-red/blob/master/CONTRIBUTING.md)
34 | before doing so.
35 |
36 | ### Copyright and license
37 |
38 | Copyright 2014, 2016 IBM Corp. under [the Apache 2.0 license](LICENSE).
39 |
--------------------------------------------------------------------------------
/weather/weather_insights.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015 IBM Corp.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | module.exports = function(RED) {
18 | var cfenv = require('cfenv');
19 | var services = cfenv.getAppEnv().services;
20 | var username, password, host = 'https://twcservice.mybluemix.net';
21 | var service;
22 | for (var i in services) {
23 | if (i.match(/^(weatherinsights)/i)) {
24 | service = services[i][0];
25 | }
26 | }
27 |
28 | if (service) {
29 | username = service.credentials.username;
30 | password = service.credentials.password;
31 | host = 'https://' + service.credentials.host;
32 | }
33 |
34 | RED.httpAdmin.get('/weather_insights/vcap', function(req, res) {
35 | res.json(service ? {bound_service: true} : null);
36 | });
37 |
38 | function Node(config) {
39 | RED.nodes.createNode(this,config);
40 | var node = this;
41 |
42 | this.on('input', function(msg) {
43 | username = username || this.credentials.username;
44 | password = password || this.credentials.password;
45 |
46 | if (!username || !password) {
47 | var message = 'Missing Weather Insights service credentials';
48 | node.error(message, msg);
49 | return;
50 | }
51 |
52 | var lat_long_regex = /^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/;
53 | var geocode;
54 |
55 | if (typeof msg.payload === 'string' && msg.payload.match(lat_long_regex)) {
56 | geocode = msg.payload;
57 | } else if (typeof msg.location === 'object') {
58 | geocode = [msg.location.lat, msg.location.lon].join(',');
59 | } else if (config.geocode.match(lat_long_regex)) {
60 | geocode = config.geocode;
61 | } else {
62 | var message2 = 'Missing valid latlong parameters on either msg.payload, msg.location or node config.';
63 | node.error(message2, msg);
64 | return;
65 | }
66 |
67 | var request = require('request');
68 |
69 | node.status({fill:"blue", shape:"dot", text:"requesting"});
70 | request({url: host + config.service, auth: {username: username, password: password}, qs: {geocode: geocode, units: config.units, language: config.language}}, function(error, response, body) {
71 | node.status({});
72 | if (!error && response.statusCode == 200) {
73 | var results = JSON.parse(body);
74 | msg.forecasts = results.forecasts;
75 | msg.observation = results.observation;
76 | msg.observations = results.observations;
77 | node.send(msg);
78 | } else {
79 | var message3 = 'Weather Insights service call failed with error HTTP response.';
80 | node.error(message3, msg);
81 | }
82 | });
83 | });
84 | }
85 |
86 | RED.nodes.registerType("weather_insights",Node, {
87 | credentials: {
88 | username: {type:"text"},
89 | password: {type:"password"}
90 | }
91 | });
92 | };
93 |
--------------------------------------------------------------------------------
/io/32-udp-cf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 IBM Corp.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | module.exports = function(RED) {
18 | "use strict";
19 | var dgram = require('dgram');
20 |
21 | // The Output Node
22 | function UDPout(n) {
23 | RED.nodes.createNode(this,n);
24 | //this.group = n.group;
25 | this.port = n.port;
26 | this.outport = n.outport||"";
27 | this.base64 = n.base64;
28 | this.addr = n.addr;
29 | this.iface = n.iface || null;
30 | this.multicast = n.multicast;
31 | var node = this;
32 |
33 | var sock = dgram.createSocket('udp4'); // only use ipv4 for now
34 |
35 | if (node.multicast != "false") {
36 | if (node.outport == "") { node.outport = node.port; }
37 | sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
38 | sock.setBroadcast(true); // turn on broadcast
39 | if (node.multicast == "multi") {
40 | try {
41 | sock.setMulticastTTL(128);
42 | sock.addMembership(node.addr,node.iface); // Add to the multicast group
43 | node.log('udp multicast ready : '+node.outport+' -> '+node.addr+":"+node.port);
44 | } catch (e) {
45 | if (e.errno == "EINVAL") {
46 | node.error("Bad Multicast Address");
47 | } else if (e.errno == "ENODEV") {
48 | node.error("Must be ip address of the required interface");
49 | } else {
50 | node.error("Error :"+e.errno);
51 | }
52 | }
53 | } else {
54 | node.log('udp broadcast ready : '+node.outport+' -> '+node.addr+":"+node.port);
55 | }
56 | });
57 | } else if (node.outport != "") {
58 | sock.bind(node.outport);
59 | node.log('udp ready : '+node.outport+' -> '+node.addr+":"+node.port);
60 | } else {
61 | node.log('udp ready : '+node.addr+":"+node.port);
62 | }
63 |
64 | node.on("input", function(msg) {
65 | if (msg.payload != null) {
66 | var add = node.addr || msg.ip || "";
67 | var por = node.port || msg.port || 0;
68 | if (add == "") {
69 | node.warn("udp: ip address not set");
70 | } else if (por == 0) {
71 | node.warn("udp: port not set");
72 | } else if (isNaN(por) || (por < 1) || (por > 65535)) {
73 | node.warn("udp: port number not valid");
74 | } else {
75 | var message;
76 | if (node.base64) {
77 | message = new Buffer(msg.payload, 'base64');
78 | } else if (msg.payload instanceof Buffer) {
79 | message = msg.payload;
80 | } else {
81 | message = new Buffer(""+msg.payload);
82 | }
83 | sock.send(message, 0, message.length, por, add, function(err, bytes) {
84 | if (err) {
85 | node.error("udp : "+err);
86 | }
87 | message = null;
88 | });
89 | }
90 | }
91 | });
92 |
93 | node.on("close", function() {
94 | try {
95 | sock.close();
96 | node.log('udp output stopped');
97 | } catch (err) {
98 | node.error(err);
99 | }
100 | });
101 | }
102 | RED.nodes.registerType("udp out",UDPout);
103 | }
104 |
--------------------------------------------------------------------------------
/twilio/56-twilio-cf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Andrew D Lindsay @AndrewDLindsay
3 | * http://blog.thiseldo.co.uk
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | **/
17 |
18 | module.exports = function(RED) {
19 |
20 | var cfenv = require("cfenv");
21 | var appEnv = cfenv.getAppEnv();
22 |
23 | var services = [];
24 | if (appEnv.services['user-provided']) {
25 | services = services.concat(appEnv.services['user-provided'].filter(function(v) {
26 | return v.credentials.url == "https://api.twilio.com" && v.credentials.accountSID && v.credentials.authToken;
27 | }).map(function(v) {
28 | return {name:v.name,label:v.label};
29 | }));
30 | }
31 |
32 | var util = require('util');
33 | var twilio = require('twilio');
34 |
35 | var querystring = require('querystring');
36 |
37 | RED.httpAdmin.get('/twilio-api/vcap',function(req,res) {
38 | res.send(JSON.stringify(services));
39 | });
40 |
41 | RED.httpAdmin.get('/twilio-api/:id',function(req,res) {
42 | var credentials = RED.nodes.getCredentials(req.params.id);
43 | if (credentials) {
44 | res.send(JSON.stringify({hasToken:(credentials.token&&credentials.token!="")}));
45 | } else {
46 | res.send(JSON.stringify({}));
47 | }
48 | });
49 |
50 | RED.httpAdmin.delete('/twilio-api/:id',function(req,res) {
51 | RED.nodes.deleteCredentials(req.params.id);
52 | res.send(200);
53 | });
54 |
55 | RED.httpAdmin.post('/twilio-api/:id',function(req,res) {
56 | var newCreds = req.body;
57 | var credentials = RED.nodes.getCredentials(req.params.id)||{};
58 | if (newCreds.token == "") {
59 | delete credentials.token;
60 | } else {
61 | credentials.token = newCreds.token;
62 | }
63 | RED.nodes.addCredentials(req.params.id,credentials);
64 | res.send(200);
65 | });
66 |
67 | function TwilioAPINode(n) {
68 | RED.nodes.createNode(this,n);
69 | this.sid = n.sid;
70 | this.from = n.from;
71 | this.name = n.name;
72 | var credentials = RED.nodes.getCredentials(n.id);
73 | if (credentials) {
74 | this.token = credentials.token;
75 | }
76 | }
77 | RED.nodes.registerType("twilio-api",TwilioAPINode);
78 |
79 |
80 | function TwilioOutNode(n) {
81 | RED.nodes.createNode(this,n);
82 | this.number = n.number;
83 |
84 | if (n.service == "_ext_") {
85 | this.api = RED.nodes.getNode(n.twilio);
86 | this.twilioClient = twilio(this.api.sid,this.api.token);
87 | this.fromNumber = this.api.from;
88 | } else if (n.service != "") {
89 | var twiliokey = appEnv.getService(n.service);
90 | if (twiliokey) {
91 | this.twilioClient = twilio(twiliokey.credentials.accountSID, twiliokey.credentials.authToken);
92 | this.fromNumber = n.from;
93 | }
94 | }
95 | if (!this.twilioClient) {
96 | this.error("missing twilio credentials");
97 | return;
98 | }
99 |
100 | var node = this;
101 | this.on("input",function(msg) {
102 | if (typeof(msg.payload) == 'object') {
103 | msg.payload = JSON.stringify(msg.payload);
104 | }
105 | try {
106 | // Send SMS
107 | var tonum = node.number || msg.topic;
108 | node.twilioClient.sendMessage( {to: tonum, from: node.fromNumber, body: msg.payload}, function(err, response) {
109 | if (err) {
110 | node.error(err);
111 | }
112 | //console.log(response);
113 | });
114 | } catch (err) {
115 | node.error(err);
116 | }
117 | });
118 | }
119 | RED.nodes.registerType("twilio out",TwilioOutNode);
120 | }
121 |
--------------------------------------------------------------------------------
/weather/weather_insights.html:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
62 |
63 |
74 |
75 |
115 |
--------------------------------------------------------------------------------
/mqlight/mqlight.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013,2014 IBM Corp.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | module.exports = function(RED) {
18 | "use strict";
19 |
20 | var cfenv = require("cfenv");
21 | var appEnv = cfenv.getAppEnv();
22 |
23 | var services = appEnv.services.mqlight || [];
24 | var serviceList = services.map(function(s) { return s.name; });
25 |
26 | RED.httpAdmin.get('/mqlight/vcap', function(req, res) {
27 | res.json(serviceList);
28 | });
29 |
30 | var mqlight = require('mqlight');
31 |
32 | function MQLightIn(n) {
33 | RED.nodes.createNode(this, n);
34 | this.service = n.service || "";
35 | this.topic = n.topic || "";
36 | this.share = n.share || null;
37 |
38 | var node = this;
39 |
40 | if (node.service === "") {
41 | node.error("No MQ Light services bound");
42 | } else {
43 | if (node.topic === "") {
44 | node.warn("No topic set in MQ Light in node");
45 | return;
46 | }
47 |
48 | var serv = services.filter(function(s) {
49 | return s.name === node.service;
50 | })[0];
51 |
52 | var cred = serv.credentials;
53 | var opts = {
54 | service: cred.connectionLookupURI,
55 | user: cred.username,
56 | password: cred.password
57 | };
58 |
59 | var recvClient = mqlight.createClient(opts, function(err) {
60 | if (err) {
61 | node.error('Connection to ' + opts.service + ' using client-id ' + recvClient.id + ' failed: ' + err);
62 | } else {
63 | recvClient.on('message', function(data, delivery) {
64 | var msg = {
65 | topic: delivery.message.topic,
66 | payload: data,
67 | _session: {
68 | type: "mqlight",
69 | id: recvClient.id
70 | }
71 | };
72 | if (delivery.destination.share) {
73 | msg.share = delivery.destination.share;
74 | }
75 | node.send(msg);
76 | });
77 | recvClient.on("error", function(err) {
78 | if (err) {
79 | node.error(err.toString());
80 | }
81 | });
82 | node.log("Subscribing to "+node.topic+(node.share ? " ["+node.share+"]" : ""));
83 | var subscribeCallback = function(err) {
84 | if (err) {
85 | node.error("Failed to subscribe: " + err);
86 | } else {
87 | node.log("Subscribed to "+node.topic+(node.share ? " ["+node.share+"]" : ""));
88 | }
89 | };
90 |
91 | if (node.share) {
92 | recvClient.subscribe(node.topic, node.share,subscribeCallback);
93 | } else {
94 | recvClient.subscribe(node.topic,subscribeCallback);
95 | }
96 | }
97 | });
98 | node.on("close", function (done) {
99 | recvClient.stop(done);
100 | });
101 | }
102 | }
103 | RED.nodes.registerType("mqlight in", MQLightIn);
104 |
105 | function MQLightOut(n) {
106 | RED.nodes.createNode(this, n);
107 | this.service = n.service || "";
108 | this.topic = n.topic || "";
109 | var node = this;
110 |
111 | if (node.service === "") {
112 | node.error("No MQ Light services bound");
113 | } else {
114 | var serv = services.filter(function(s) {
115 | return s.name === node.service;
116 | })[0];
117 |
118 | var cred = serv.credentials;
119 | var opts = {
120 | service: cred.connectionLookupURI,
121 | user: cred.username,
122 | password: cred.password
123 | };
124 |
125 | var sendClient = mqlight.createClient(opts, function(err) {
126 | if (err) {
127 | node.error('Connection to ' + opts.service + ' using client-id ' + sendClient.id + ' failed: ' + err);
128 | } else {
129 | node.on("input", function(msg) {
130 | var topic = node.topic;
131 | if (topic === "") {
132 | if (msg.topic) {
133 | topic = msg.topic;
134 | } else {
135 | node.warn("No topic set in MQ Light out node");
136 | return;
137 | }
138 | }
139 | sendClient.send(topic, msg.payload, function(err) {
140 | if (err) {
141 | node.error(err, msg);
142 | }
143 | });
144 | });
145 | }
146 | });
147 |
148 | sendClient.on("error", function(err) {
149 | if (err) {
150 | node.error(err.toString());
151 | }
152 | });
153 |
154 | node.on("close", function (done) {
155 | sendClient.stop(done);
156 | });
157 | }
158 | }
159 | RED.nodes.registerType("mqlight out", MQLightOut);
160 | }
161 |
--------------------------------------------------------------------------------
/io/32-udp-cf.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
72 |
73 |
74 |
82 |
83 |
136 |
--------------------------------------------------------------------------------
/mqlight/mqlight.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
37 |
38 |
48 |
49 |
90 |
91 |
107 |
108 |
114 |
115 |
152 |
--------------------------------------------------------------------------------
/twilio/56-twilio-cf.html:
--------------------------------------------------------------------------------
1 |
17 |
18 |
43 |
44 |
51 |
52 |
70 |
71 |
180 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
--------------------------------------------------------------------------------
/io/31-tcpin-cf.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
51 |
52 |
55 |
56 |
103 |
104 |
105 |
128 |
129 |
136 |
137 |
179 |
180 |
181 |
224 |
225 |
233 |
234 |
256 |
--------------------------------------------------------------------------------
/mongo/66-mongodb-cf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013, 2014 IBM Corp.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | module.exports = function(RED) {
18 | var when = require("when");
19 |
20 | var cfenv = require("cfenv");
21 | var appEnv = cfenv.getAppEnv();
22 |
23 | var services = [];
24 |
25 | for (var i in appEnv.services) {
26 | if (i.match(/^(TimeSeriesDatabase|JSONDB|mongodb|mongolab)/i)) {
27 | services = services.concat(appEnv.services[i].map(function(v) {
28 | return {name:v.name,label:v.label};
29 | }));
30 | }
31 | }
32 |
33 | function ensureValidSelectorObject(selector) {
34 | if (selector != null && (typeof selector != 'object' || Buffer.isBuffer(selector))) {
35 | return {};
36 | }
37 | return selector;
38 | }
39 |
40 | var mongo = require('mongodb');
41 | var MongoClient = mongo.MongoClient;
42 |
43 | function MongoNode(n) {
44 | RED.nodes.createNode(this,n);
45 | this.hostname = n.hostname;
46 | this.port = n.port;
47 | this.db = n.db;
48 | this.name = n.name;
49 | var credentials = RED.nodes.getCredentials(n.id);
50 | if (credentials) {
51 | this.username = credentials.user;
52 | this.password = credentials.password;
53 | }
54 |
55 | var url = "mongodb://";
56 | if (this.username && this.password) {
57 | url += this.username+":"+this.password+"@";
58 | }
59 | url += this.hostname+":"+this.port+"/"+this.db;
60 |
61 | this.url = url;
62 | }
63 |
64 | RED.nodes.registerType("mongodb",MongoNode);
65 |
66 | RED.httpAdmin.get('/mongodb/vcap', function(req,res) {
67 | res.send(JSON.stringify(services));
68 | });
69 |
70 |
71 | RED.httpAdmin.get('/mongodb/:id',function(req,res) {
72 | var credentials = RED.nodes.getCredentials(req.params.id);
73 | if (credentials) {
74 | res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
75 | } else {
76 | res.send(JSON.stringify({}));
77 | }
78 | });
79 |
80 | RED.httpAdmin.delete('/mongodb/:id',function(req,res) {
81 | RED.nodes.deleteCredentials(req.params.id);
82 | res.send(200);
83 | });
84 |
85 | RED.httpAdmin.post('/mongodb/:id',function(req,res) {
86 | var newCreds = req.body;
87 | var credentials = RED.nodes.getCredentials(req.params.id)||{};
88 | if (newCreds.user == null || newCreds.user == "") {
89 | delete credentials.user;
90 | } else {
91 | credentials.user = newCreds.user;
92 | }
93 | if (newCreds.password == "") {
94 | delete credentials.password;
95 | } else {
96 | credentials.password = newCreds.password||credentials.password;
97 | }
98 | RED.nodes.addCredentials(req.params.id,credentials);
99 | res.send(200);
100 | });
101 |
102 |
103 | var ConnectionPool = function() {
104 | var clients = {};
105 |
106 | return {
107 | get: function(url) {
108 | if (!clients[url]) {
109 | clients[url] = {
110 | instances:0,
111 | promise: when.promise(function(resolve,reject) {
112 | MongoClient.connect(url, {
113 | db:{
114 | retryMiliSeconds:1000,
115 | numberOfRetries:3
116 | },
117 | server:{
118 | poolSize:1,
119 | auto_reconnect:true,
120 | socketOptions:{
121 | socketTimeoutMS:10000,
122 | keepAlive:1
123 | }
124 | }
125 | },function(err,db) {
126 | if (err) {
127 | reject(err);
128 | } else {
129 | resolve(db);
130 | }
131 | });
132 | })
133 | }
134 | }
135 | clients[url].instances++;
136 | return clients[url].promise;
137 | },
138 | close: function(url) {
139 | if (clients[url]) {
140 | clients[url].instances--;
141 | if (clients[url].instances == 0) {
142 | try {
143 | clients[url].close();
144 | } catch(err) {
145 | }
146 | delete clients[url];
147 | }
148 | }
149 | }
150 |
151 | }
152 |
153 | }();
154 |
155 |
156 | function MongoOutNode(n) {
157 | RED.nodes.createNode(this,n);
158 | this.collection = n.collection;
159 | this.mongodb = n.mongodb;
160 | this.payonly = n.payonly || false;
161 | this.upsert = n.upsert || false;
162 | this.multi = n.multi || false;
163 | this.operation = n.operation;
164 |
165 | if (n.service === "_ext_") {
166 | var mongoConfig = RED.nodes.getNode(this.mongodb);
167 | if (mongoConfig) {
168 | this.url = mongoConfig.url;
169 | }
170 | } else if (n.service !== "") {
171 | var mongoConfig = appEnv.getService(n.service);
172 | if (mongoConfig) {
173 | this.url = mongoConfig.credentials.url || mongoConfig.credentials.uri || mongoConfig.credentials.json_url;
174 | }
175 | }
176 |
177 | if (this.url) {
178 | var node = this;
179 | ConnectionPool.get(this.url).then(function(db) {
180 | var coll;
181 | if (node.collection) {
182 | coll = db.collection(node.collection);
183 | }
184 | node.on("input", function(msg) {
185 | if (!node.collection) {
186 | if (msg.collection) {
187 | coll = db.collection(msg.collection);
188 | } else {
189 | node.error("No collection defined");
190 | return;
191 | }
192 | }
193 | delete msg._topic;
194 | delete msg.collection;
195 | if (node.operation === "store") {
196 | if (node.payonly) {
197 | if (typeof msg.payload !== "object") {
198 | msg.payload = {"payload":msg.payload};
199 | }
200 | coll.save(msg.payload, function(err,item){
201 | if (err) {
202 | node.error(err);
203 | }
204 | });
205 | } else {
206 | coll.save(msg, function(err, item) {
207 | if (err) {
208 | node.error(err);
209 | }
210 | });
211 | }
212 | } else if (node.operation === "insert") {
213 | if (node.payonly) {
214 | if (typeof msg.payload !== "object") {
215 | msg.payload = {"payload": msg.payload};
216 | }
217 | coll.insert(msg.payload, function(err,item) {
218 | if (err) {
219 | node.error(err);
220 | }
221 | });
222 | } else {
223 | coll.insert(msg, function(err, item) {
224 | if (err) {
225 | node.error(err);
226 | }
227 | });
228 | }
229 | } else if (node.operation === "update") {
230 | if (typeof msg.payload !== "object") {
231 | msg.payload = {"payload": msg.payload};
232 | }
233 | var query = msg.query || {};
234 | var payload = msg.payload || {};
235 | var options = {
236 | upsert: node.upsert,
237 | multi: node.multi
238 | };
239 |
240 | coll.update(query, payload, options, function(err, item) {
241 | if (err) {
242 | node.error(err);
243 | }
244 | });
245 | } else if (node.operation === "delete") {
246 | coll.remove(msg.payload, function(err, items) {
247 | if (err) {
248 | node.error(err);
249 | }
250 | });
251 | }
252 | });
253 | }).otherwise(function(err) {
254 | node.error(err);
255 | });
256 | this.on("close", function() {
257 | if (this.url) {
258 | ConnectionPool.close(this.url);
259 | }
260 | });
261 | } else {
262 | this.error("missing mongodb configuration");
263 | }
264 |
265 | }
266 | RED.nodes.registerType("mongodb out",MongoOutNode);
267 |
268 |
269 | function MongoInNode(n) {
270 | RED.nodes.createNode(this,n);
271 | this.collection = n.collection;
272 | this.mongodb = n.mongodb;
273 | this.operation = n.operation || "find";
274 |
275 | if (n.service === "_ext_") {
276 | var mongoConfig = RED.nodes.getNode(this.mongodb);
277 | if (mongoConfig) {
278 | this.url = mongoConfig.url;
279 | }
280 | } else if (n.service !== "") {
281 | var mongoConfig = appEnv.getService(n.service);
282 | if (mongoConfig) {
283 | this.url = mongoConfig.credentials.url || mongoConfig.credentials.uri || mongoConfig.credentials.json_url;
284 | }
285 | }
286 |
287 | if (this.url) {
288 | var node = this;
289 | ConnectionPool.get(this.url).then(function(db) {
290 | var coll;
291 | if (node.collection) {
292 | coll = db.collection(node.collection);
293 | }
294 | node.on("input", function(msg) {
295 | if (!node.collection) {
296 | if (msg.collection) {
297 | coll = db.collection(msg.collection);
298 | } else {
299 | node.error("No collection defined");
300 | return;
301 | }
302 | }
303 | if (node.operation === "find") {
304 | msg.projection = msg.projection || {};
305 | var selector = ensureValidSelectorObject(msg.payload);
306 | coll.find(selector, msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) {
307 | if (err) {
308 | node.error(err);
309 | } else {
310 | msg.payload = items;
311 | delete msg.projection;
312 | delete msg.sort;
313 | delete msg.limit;
314 | node.send(msg);
315 | }
316 | });
317 | } else if (node.operation === "count") {
318 | var selector = ensureValidSelectorObject(msg.payload);
319 | coll.count(selector, function(err, count) {
320 | if (err) {
321 | node.error(err);
322 | } else {
323 | msg.payload = count;
324 | node.send(msg);
325 | }
326 | });
327 | } else if (node.operation === "aggregate") {
328 | msg.payload = (Array.isArray(msg.payload)) ? msg.payload : [];
329 | coll.aggregate(msg.payload, function(err, result) {
330 | if (err) {
331 | node.error(err);
332 | } else {
333 | msg.payload = result;
334 | node.send(msg);
335 | }
336 | });
337 | }
338 | });
339 | }).otherwise(function(err) {
340 | node.error(err);
341 | });
342 | this.on("close", function() {
343 | if (this.url) {
344 | ConnectionPool.close(this.url);
345 | }
346 | });
347 | } else {
348 | this.error("missing mongodb configuration");
349 | }
350 | }
351 | RED.nodes.registerType("mongodb in",MongoInNode);
352 | }
353 |
--------------------------------------------------------------------------------
/mongo/66-mongodb-cf.html:
--------------------------------------------------------------------------------
1 |
16 |
17 |
41 |
42 |
95 |
96 |
97 |
144 |
145 |
159 |
160 |
191 |
192 |
204 |
205 |
320 |
--------------------------------------------------------------------------------
/io/31-tcpin-cf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013,2016 IBM Corp.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | module.exports = function(RED) {
18 | "use strict";
19 | var reconnectTime = RED.settings.socketReconnectTime||10000;
20 | var socketTimeout = RED.settings.socketTimeout||null;
21 | var net = require('net');
22 |
23 | var connectionPool = {};
24 |
25 | function TcpIn(n) {
26 | RED.nodes.createNode(this,n);
27 | this.host = n.host;
28 | this.port = n.port * 1;
29 | this.topic = n.topic;
30 | this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
31 | this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
32 | this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
33 | this.base64 = n.base64;
34 | this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
35 | this.closing = false;
36 | var node = this;
37 |
38 | if (!node.server) {
39 | var buffer = null;
40 | var client;
41 | var reconnectTimeout;
42 | var setupTcpClient = function() {
43 | node.log("connecting to "+node.host+":"+node.port);
44 | node.status({fill:"grey",shape:"dot",text:"connecting"},true);
45 | var id = (1+Math.random()*4294967295).toString(16);
46 | client = net.connect(node.port, node.host, function() {
47 | buffer = (node.datatype == 'buffer')? new Buffer(0):"";
48 | node.log("connected to "+node.host+":"+node.port);
49 | node.status({fill:"green",shape:"dot",text:"connected"},true);
50 | });
51 | connectionPool[id] = client;
52 |
53 | client.on('data', function (data) {
54 | if (node.datatype != 'buffer') {
55 | data = data.toString(node.datatype);
56 | }
57 | if (node.stream) {
58 | if ((node.datatype) === "utf8" && node.newline != "") {
59 | buffer = buffer+data;
60 | var parts = buffer.split(node.newline);
61 | for (var i = 0;i 0)) {
82 | var msg = {topic:node.topic,payload:buffer};
83 | msg._session = {type:"tcp",id:id};
84 | node.send(msg);
85 | buffer = null;
86 | }
87 | });
88 | client.on('close', function() {
89 | delete connectionPool[id];
90 | node.log("connection lost to "+node.host+":"+node.port);
91 | node.status({fill:"red",shape:"ring",text:"disconnected"});
92 | if (!node.closing) {
93 | reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
94 | }
95 | });
96 | client.on('error', function(err) {
97 | node.log(err);
98 | });
99 | }
100 | setupTcpClient();
101 |
102 | this.on('close', function() {
103 | this.closing = true;
104 | client.end();
105 | clearTimeout(reconnectTimeout);
106 | });
107 | } else {
108 | var server = net.createServer(function (socket) {
109 | if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
110 | var id = (1+Math.random()*4294967295).toString(16);
111 | connectionPool[id] = socket;
112 |
113 | var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
114 | socket.on('data', function (data) {
115 | if (node.datatype != 'buffer') {
116 | data = data.toString(node.datatype);
117 | }
118 |
119 | if (node.stream) {
120 | if ((typeof data) === "string" && node.newline != "") {
121 | buffer = buffer+data;
122 | var parts = buffer.split(node.newline);
123 | for (var i = 0;i 0)) {
144 | var msg = {topic:node.topic,payload:buffer};
145 | msg._session = {type:"tcp",id:id};
146 | node.send(msg);
147 | buffer = null;
148 | }
149 | });
150 | socket.on('timeout', function() {
151 | node.log('timeout closed socket port '+node.port);
152 | socket.end();
153 | });
154 | socket.on('close', function() {
155 | delete connectionPool[id];
156 | });
157 | socket.on('error',function(err) {
158 | node.log(err);
159 | });
160 | });
161 | server.on('error', function(err) {
162 | if (err) {
163 | node.error('unable to listen on port '+node.port+' : '+err);
164 | }
165 | });
166 | server.listen(node.port, function(err) {
167 | if (err) {
168 | node.error('unable to listen on port '+node.port+' : '+err);
169 | } else {
170 | node.log('listening on port '+node.port);
171 |
172 | node.on('close', function() {
173 | node.closing = true;
174 | server.close();
175 | node.log('stopped listening on port '+node.port);
176 | });
177 | }
178 | });
179 | }
180 | }
181 | RED.nodes.registerType("tcp in",TcpIn);
182 |
183 | function TcpOut(n) {
184 | RED.nodes.createNode(this,n);
185 | this.host = n.host;
186 | this.port = n.port * 1;
187 | this.base64 = n.base64;
188 | this.beserver = n.beserver;
189 | this.name = n.name;
190 | this.closing = false;
191 | var node = this;
192 |
193 | if (!node.beserver||node.beserver=="client") {
194 | var reconnectTimeout;
195 | var client = null;
196 | var connected = false;
197 |
198 | var setupTcpClient = function() {
199 | node.log("connecting to "+node.host+":"+node.port);
200 | node.status({fill:"grey",shape:"dot",text:"connecting"},true);
201 | client = net.connect(node.port, node.host, function() {
202 | connected = true;
203 | node.log("connected to "+node.host+":"+node.port);
204 | node.status({fill:"green",shape:"dot",text:"connected"},true);
205 | });
206 | client.on('error', function (err) {
207 | node.log('error : '+err);
208 | });
209 | client.on('end', function (err) {
210 | });
211 | client.on('close', function() {
212 | node.log("connection lost to "+node.host+":"+node.port);
213 | node.status({fill:"red",shape:"ring",text:"disconnected"},true);
214 | connected = false;
215 | client.destroy();
216 | if (!node.closing) {
217 | reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
218 | }
219 | });
220 | }
221 | setupTcpClient();
222 |
223 | node.on("input", function(msg) {
224 | if (connected && msg.payload != null) {
225 | if (Buffer.isBuffer(msg.payload)) {
226 | client.write(msg.payload);
227 | } else if (typeof msg.payload === "string" && node.base64) {
228 | client.write(new Buffer(msg.payload,'base64'));
229 | } else {
230 | client.write(new Buffer(""+msg.payload));
231 | }
232 | }
233 | });
234 |
235 | node.on("close", function() {
236 | this.closing = true;
237 | client.end();
238 | clearTimeout(reconnectTimeout);
239 | });
240 |
241 | } else if (node.beserver == "reply") {
242 | node.on("input",function(msg) {
243 | if (msg._session && msg._session.type == "tcp") {
244 | var client = connectionPool[msg._session.id];
245 | if (client) {
246 | if (Buffer.isBuffer(msg.payload)) {
247 | client.write(msg.payload);
248 | } else if (typeof msg.payload === "string" && node.base64) {
249 | client.write(new Buffer(msg.payload,'base64'));
250 | } else {
251 | client.write(new Buffer(""+msg.payload));
252 | }
253 | }
254 | }
255 | });
256 | } else {
257 | var connectedSockets = [];
258 | var server = net.createServer(function (socket) {
259 | if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
260 | var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
261 | node.log("connection from "+remoteDetails);
262 | connectedSockets.push(socket);
263 | socket.on('timeout', function() {
264 | node.log('timeout closed socket port '+node.port);
265 | socket.end();
266 | });
267 | socket.on('close',function() {
268 | node.log("connection closed from "+remoteDetails);
269 | connectedSockets.splice(connectedSockets.indexOf(socket),1);
270 | });
271 | socket.on('error',function() {
272 | node.log("socket error from "+remoteDetails);
273 | connectedSockets.splice(connectedSockets.indexOf(socket),1);
274 | });
275 | });
276 | node.on("input", function(msg) {
277 | if (msg.payload != null) {
278 | var buffer;
279 | if (Buffer.isBuffer(msg.payload)) {
280 | buffer = msg.payload;
281 | } else if (typeof msg.payload === "string" && node.base64) {
282 | buffer = new Buffer(msg.payload,'base64');
283 | } else {
284 | buffer = new Buffer(""+msg.payload);
285 | }
286 | for (var i = 0; i= node.splitc) {
388 | msg.payload = new Buffer(i);
389 | buf.copy(msg.payload,0,0,i);
390 | node.send(msg);
391 | if (client) { node.status({}); client.destroy(); }
392 | i = 0;
393 | }
394 | }
395 | // look for a char
396 | else {
397 | buf[i] = data[j];
398 | i += 1;
399 | if (data[j] == node.splitc) {
400 | msg.payload = new Buffer(i);
401 | buf.copy(msg.payload,0,0,i);
402 | node.send(msg);
403 | if (client) { node.status({}); client.destroy(); }
404 | i = 0;
405 | }
406 | }
407 | }
408 | }
409 | });
410 |
411 | client.on('end', function() {
412 | //console.log("END");
413 | node.connected = false;
414 | node.status({fill:"grey",shape:"ring",text:"disconnected"});
415 | client = null;
416 | });
417 |
418 | client.on('close', function() {
419 | //console.log("CLOSE");
420 | node.connected = false;
421 | if (node.done) { node.done(); }
422 | });
423 |
424 | client.on('error', function() {
425 | //console.log("ERROR");
426 | node.connected = false;
427 | node.status({fill:"red",shape:"ring",text:"error"});
428 | node.error("connect failed",msg);
429 | if (client) { client.destroy(); }
430 | });
431 |
432 | client.on('timeout',function() {
433 | //console.log("TIMEOUT");
434 | node.connected = false;
435 | node.status({fill:"grey",shape:"dot",text:"connect timeout"});
436 | if (client) {
437 | client.connect(port, host, function() {
438 | node.connected = true;
439 | node.status({fill:"green",shape:"dot",text:"connected"});
440 | });
441 | }
442 | });
443 | }
444 | else { client.write(msg.payload); }
445 | });
446 |
447 | this.on("close", function(done) {
448 | node.done = done;
449 | if (client) {
450 | buf = null;
451 | client.destroy();
452 | }
453 | node.status({});
454 | if (!node.connected) { done(); }
455 | });
456 | }
457 | RED.nodes.registerType("tcp request",TcpGet);
458 | }
459 |
--------------------------------------------------------------------------------