├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── socketio.html
└── socketio.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 wperw
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-red-contrib-socketio
2 | Implementation for [Node-RED](https://nodered.org/) of the popular [Socket.IO](http://socket.io/).
3 |
4 | ## Installation
5 | To install node-red-contrib-socketio use this command
6 |
7 | `npm i node-red-contrib-socketio`
8 |
9 | ## Composition
10 | The Socket.IO implementation is made with
11 | * 1 configuration Node that holds the server definitions and the user can decide to bind the SocketIO server on the Node-RED port or bind it to another port
12 | * 1 input node where the user adds all the `topic`s in which they are interested
13 | * 1 output node that sends the data received into `msg.payload`
14 | * 1 node to join a Socket IO room
15 | * 1 node to leave a Socket IO room
16 |
17 | ## Usage
18 | To see an example usage go to [Example Chat App](https://flows.nodered.org/flow/71f7da3a14951acb67f94bac1f71812a)
19 |
20 | ## License
21 | MIT
22 |
23 | ## Thanks
24 | Thank to:
25 | * @nexflo for translating the comments in English and for pre-sending control data
26 | * @bimalyn-IBM for implementig rooms
27 | * @essuraj for implementig rooms listing node
28 | * @cazellap for pushong adding compatibility to socketIO 3.0
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-red-contrib-socketio",
3 | "version": "1.1.0",
4 | "description": "Implementation for Node-RED of a SocketIO Sever",
5 | "dependencies": {
6 | "socket.io": ">=3.1.0"
7 | },
8 | "node-red": {
9 | "nodes": {
10 | "socket-io": "socketio.js"
11 | }
12 | },
13 | "main": "socketio.js",
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/wperw/node-red-contrib-socketio.git"
20 | },
21 | "keywords": [
22 | "node-red"
23 | ],
24 | "author": "Telemaco Gallimberti",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/wperw/node-red-contrib-socketio/issues"
28 | },
29 | "homepage": "https://github.com/wperw/node-red-contrib-socketio#readme"
30 | }
31 |
--------------------------------------------------------------------------------
/socketio.html:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
52 |
53 |
57 |
58 |
59 |
60 |
61 |
110 |
111 |
124 |
125 |
139 |
140 |
141 |
157 |
158 |
168 |
169 |
187 |
188 |
189 |
205 |
206 |
216 |
217 |
226 |
227 |
228 |
244 |
245 |
255 |
256 |
265 |
266 |
282 |
283 |
284 |
285 |
296 |
297 |
301 |
--------------------------------------------------------------------------------
/socketio.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright Gallimberti Telemaco 02/02/2017
3 | **/
4 |
5 | module.exports = function(RED) {
6 | const { Server } = require("socket.io");
7 | var io;
8 | var customProperties = {};
9 |
10 | function socketIoConfig(n) {
11 | RED.nodes.createNode(this, n);
12 | var node = this;
13 | this.port = n.port || 80;
14 | this.sendClient = n.sendClient;
15 | this.path = n.path || "/socket.io";
16 | this.bindToNode = n.bindToNode || false;
17 |
18 | if (this.bindToNode) {
19 | io = new Server(RED.server);
20 | } else {
21 | io = new Server();
22 | io.serveClient(node.sendClient);
23 | io.path(node.path);
24 | io.listen(node.port);
25 | }
26 | var bindOn = this.bindToNode
27 | ? "bind to Node-red port"
28 | : "on port " + this.port;
29 | node.log("Created server " + bindOn);
30 |
31 | node.on("close", function() {
32 | io.close();
33 | });
34 | }
35 |
36 | function socketIoIn(n) {
37 | RED.nodes.createNode(this, n);
38 | var node = this;
39 | this.name = n.name;
40 | this.server = RED.nodes.getNode(n.server);
41 | this.rules = n.rules || [];
42 |
43 | this.specialIOEvent = [
44 | // Events emitted by the Manager:
45 | { v: "open" },
46 | { v: "error" },
47 | { v: "close" },
48 | { v: "ping" },
49 | { v: "packet" },
50 | { v: "reconnect_attempt" },
51 | { v: "reconnect" },
52 | { v: "reconnect_error" },
53 | { v: "reconnect_failed" },
54 |
55 | // Events emitted by the Socket:
56 | { v: "connect" },
57 | { v: "connect_error" },
58 | { v: "disconnect" }
59 | ];
60 |
61 | function addListener(socket, val, i) {
62 | socket.on(val.v, function(msgin) {
63 | var msg = {};
64 | RED.util.setMessageProperty(msg, "payload", msgin, true);
65 | RED.util.setMessageProperty(msg, "socketIOEvent", val.v, true);
66 | RED.util.setMessageProperty(msg, "socketIOId", socket.id, true);
67 | if (
68 | customProperties[RED.util.getMessageProperty(msg, "socketIOId")] !=
69 | null
70 | ) {
71 | RED.util.setMessageProperty(
72 | msg,
73 | "socketIOStaticProperties",
74 | customProperties[RED.util.getMessageProperty(msg, "socketIOId")],
75 | true
76 | );
77 | }
78 | node.send(msg);
79 | });
80 | }
81 |
82 | io.on("connection", function(socket) {
83 | node.rules.forEach(function(val, i) {
84 | addListener(socket, val, i);
85 | });
86 | //Adding support for all other special messages
87 | node.specialIOEvent.forEach(function(val, i) {
88 | addListener(socket, val, i);
89 | });
90 | });
91 | }
92 |
93 | function socketIoOut(n) {
94 | RED.nodes.createNode(this, n);
95 | var node = this;
96 | this.name = n.name;
97 | this.server = RED.nodes.getNode(n.server);
98 |
99 | node.on("input", function(msg) {
100 | //check if we need to add properties
101 | if (RED.util.getMessageProperty(msg, "socketIOAddStaticProperties")) {
102 | //check if we have already added some properties for this socket
103 | if (
104 | customProperties[RED.util.getMessageProperty(msg, "socketIOId")] !=
105 | null
106 | ) {
107 | //check if object as property
108 | var keys = Object.getOwnPropertyNames(
109 | RED.util.getMessageProperty(msg, "socketIOAddStaticProperties")
110 | );
111 | var tmp =
112 | customProperties[RED.util.getMessageProperty(msg, "socketIOId")];
113 | for (var i = 0; i < keys.length; i++) {
114 | tmp[keys[i]] = RED.util.getMessageProperty(
115 | msg,
116 | "socketIOAddStaticProperties"
117 | )[keys[i]];
118 | }
119 | } else {
120 | //add new properties
121 | customProperties[
122 | RED.util.getMessageProperty(msg, "socketIOId")
123 | ] = RED.util.getMessageProperty(msg, "socketIOAddStaticProperties");
124 | }
125 | }
126 |
127 |
128 | switch (RED.util.getMessageProperty(msg, "socketIOEmit")) {
129 | case "broadcast.emit":
130 | //Return to all but the caller
131 | if (
132 | io.sockets.sockets.get(RED.util.getMessageProperty(msg, "socketIOId"))
133 | ) {
134 | io.sockets.sockets.get(
135 | RED.util.getMessageProperty(msg, "socketIOId")
136 | ).broadcast.emit(msg.socketIOEvent, msg.payload);
137 | }
138 | break;
139 | case "emit":
140 | //Return only to the caller
141 | if (
142 | io.sockets.sockets.get(RED.util.getMessageProperty(msg, "socketIOId"))
143 | ) {
144 | io.sockets.sockets.get(
145 | RED.util.getMessageProperty(msg, "socketIOId")
146 | ).emit(msg.socketIOEvent, msg.payload);
147 | }
148 | break;
149 | case "room":
150 | //emit to all
151 | if (msg.room) {
152 | io.to(msg.room).emit(msg.socketIOEvent, msg.payload);
153 | }
154 | break;
155 | default:
156 | //emit to all
157 | io.emit(msg.socketIOEvent, msg.payload);
158 | }
159 | });
160 | }
161 |
162 | function socketIoJoin(n) {
163 | RED.nodes.createNode(this, n);
164 | var node = this;
165 | this.name = n.name;
166 | this.server = RED.nodes.getNode(n.server);
167 |
168 | node.on("input", function(msg) {
169 | if (io.sockets.sockets.get(RED.util.getMessageProperty(msg, "socketIOId"))) {
170 | io.sockets.sockets.get(RED.util.getMessageProperty(msg, "socketIOId")).join(
171 | msg.payload.room
172 | );
173 | node.send(msg);
174 | }
175 | });
176 | }
177 |
178 | function socketIoRooms(n) {
179 | RED.nodes.createNode(this, n);
180 | var node = this;
181 | this.name = n.name;
182 | this.server = RED.nodes.getNode(n.server);
183 |
184 | node.on("input", function(msg) {
185 | node.send({ payload: io.sockets.adapter.rooms });
186 | });
187 | }
188 |
189 | function socketIoLeave(n) {
190 | RED.nodes.createNode(this, n);
191 | var node = this;
192 | this.name = n.name;
193 | this.server = RED.nodes.getNode(n.server);
194 |
195 | node.on("input", function(msg) {
196 | if (io.sockets.sockets.get(RED.util.getMessageProperty(msg, "socketIOId"))) {
197 | io.sockets.sockets.get(
198 | RED.util.getMessageProperty(msg, "socketIOId")
199 | ).leave(msg.payload.room);
200 | }
201 | });
202 | }
203 |
204 | RED.nodes.registerType("socketio-config", socketIoConfig);
205 | RED.nodes.registerType("socketio-in", socketIoIn);
206 | RED.nodes.registerType("socketio-out", socketIoOut);
207 | RED.nodes.registerType("socketio-join", socketIoJoin);
208 | RED.nodes.registerType("socketio-rooms", socketIoRooms);
209 | RED.nodes.registerType("socketio-leave", socketIoLeave);
210 | };
211 |
--------------------------------------------------------------------------------