|
1 | | -## ToolSocket |
2 | | -#### For socket.io API compatibility scroll down! |
3 | | -ToolSocket is a WebSocket server (nodejs only) and client for nodejs and browsers and a minimal but strict JSON Schema validator. The goal is to simplify real-time data communication. |
4 | | - |
5 | | -+ It supports Req/Res, messages without acknowledgment, and in future Pub/Sub all via a single Websocket. |
6 | | -+ The API for browser and nodejs is identical. |
7 | | -+ Build-in data package validator uses JSON schema. |
8 | | -+ The minified library file size is only 7 kb. |
9 | | -+ The communication protocol is standard conform WebSocket with a JSON based message package: |
10 | | - |
11 | | -````javascript |
12 | | -// code snipets from line 51 |
13 | | -this.DataPackage = function (origin, network, method, route, body, id = null) { |
14 | | - this.i = id; // Package id for response otherwise null |
15 | | - this.o = origin; // Package origin [client, web, server] |
16 | | - this.n = network; // NetworkID (think about it as room) |
17 | | - this.m = method; // Method such as post, get, action, ... |
18 | | - this.r = route; // Package route. Example "/boston/seaport/ptc" |
19 | | - this.b = body; // Message body (object, array, number, string) |
20 | | - this.s = null // (optional) Secret used to manage write access. |
21 | | - this.f = null // (optional) amount of binary buffers in array attached to a message |
22 | | -}; |
23 | | -```` |
24 | | - |
25 | | -### install |
26 | | -add the following to your package.json |
27 | | -```json |
28 | | -"dependencies":{ |
29 | | - "toolsocket": "ptcrealitylab/toolsocket#main" |
30 | | -} |
31 | | - ``` |
32 | | -`npm install` |
| 1 | +# ToolSocket |
| 2 | + |
| 3 | +## Setup |
| 4 | + |
| 5 | +### Installing for Production (Node.js) |
| 6 | +Run `npm i toolsocket` in your project directory. |
| 7 | + |
| 8 | +### Installing for Development (Node.js) |
| 9 | +Run `npm link` in your `toolsocket` repository, then `npm link toolsocket` in your projects |
| 10 | +that use `toolsocket`. They should now be linked to your local `toolsocket` repository. |
| 11 | + |
| 12 | +### Building ToolSocket (Web) |
| 13 | +Run `npm run build`, then copy `dist/toolsocket.js` to your server and load it in a script tag. |
| 14 | +The build script automatically minifies `dist/toolsocket.js` for you. |
| 15 | + |
| 16 | +### Testing |
| 17 | +Run the included jest test suite via `npm run test`. |
| 18 | + |
| 19 | +Run tests with coverage analysis via `npm run coverage`. |
| 20 | + |
| 21 | +## Usage |
33 | 22 |
|
34 | | -### Initialize Server |
| 23 | +### Server |
35 | 24 | ```javascript |
36 | 25 | const ToolSocket = require('toolsocket'); |
37 | | -let serverPort= 12345; |
38 | | -let webSocketServer = new ToolSocket.Server({port: serverPort, origin: 'proxy'}); |
| 26 | +const webSocketServer = new ToolSocket.Server({/* WS server options go here */}); |
39 | 27 |
|
40 | 28 | webSocketServer.on('connection', function connection(socket) { |
41 | | - // place your socket code here |
| 29 | + // Method-style request handling |
| 30 | + socket.on('post', (route, body, res, binaryData) => { |
| 31 | + if (route === "/") { |
| 32 | + console.log(body); // "hello" |
| 33 | + if (res) { // res object is available only if sender registered a callback |
| 34 | + if (binaryData) { |
| 35 | + res.send('hi', binaryData); // res.send can optionally send binaryData (Uint8Array) as well |
| 36 | + } else { |
| 37 | + res.send('hi'); |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | + }); |
| 42 | + |
| 43 | + // Event-style request handling (Cannot send responses) |
| 44 | + socket.on('/', (body, binary) => { |
| 45 | + console.log(body); // "hello" |
| 46 | + if (binaryData) { |
| 47 | + console.log('hi', binaryData); |
| 48 | + } else { |
| 49 | + console.log('hi'); |
| 50 | + } |
| 51 | + }); |
42 | 52 | }); |
43 | 53 | ``` |
44 | 54 |
|
45 | | -### Initialize Server with HTTP |
46 | | -```javascript |
47 | | -let webSocketServer = new ToolSocket.Server({Server: http}); |
| 55 | +### Client |
| 56 | +In your html file: |
| 57 | +```html |
| 58 | +<script src="dist/toolsocket.js"></script> |
48 | 59 | ``` |
49 | 60 |
|
50 | | -### Initialize Client in Nodejs |
51 | | - |
| 61 | +In your js code: |
52 | 62 | ```javascript |
53 | | -const ToolSocket = require("toolsocket"); |
54 | | -let socket = new ToolSocket('ws://localhost:12345', 'networkID', 'client'); |
55 | | -``` |
| 63 | +const socket = new ToolSocket('ws://localhost:12345', 'networkID', 'client'); |
56 | 64 |
|
57 | | -### Initialize Client in Web-Browser |
| 65 | +const route = "/"; |
| 66 | +const body = "hello"; |
| 67 | +const binaryData = new TextEncoder().encode("binary"); |
58 | 68 |
|
59 | | -```html |
60 | | -<script src="node_modules/toolsocket/index.js"></script> |
61 | | -<script> |
62 | | - let socket = new ToolSocket('ws://localhost:12345', 'networkID', 'web'); |
63 | | -</script> |
64 | | -``` |
| 69 | +// Method-style request without acknowledgement |
| 70 | +socket.post(route, body, null, binaryData); |
65 | 71 |
|
66 | | -Network ID is like a Room that allows you to group messages by a specific Network. |
| 72 | +// Method-style request with callback |
| 73 | +socket.post(route, body, (responseMsg, _responseBinary) => { |
| 74 | + console.log(responseMsg); // "hi" |
| 75 | +}, binaryData); // binaryData is optional and must be a Uint8Array |
67 | 76 |
|
68 | | -### Send a Message via the Socket |
69 | | -#### with req/res style callback |
70 | | -```javascript |
71 | | -// with req/res call back |
72 | | -let route = "/"; let msg = "hello"; let binaryData = {data: new TextEncoder().encode("binary")}; |
73 | | -socket.post(route, msg, function (msg) { |
74 | | - console.log(msg); // "hi" |
75 | | - }, |
76 | | - binaryData // (optional) A single binary buffer or multiple binary buffers in an array. |
77 | | -); |
| 77 | +// Event-style request (cannot be used with callbacks) |
| 78 | +socket.emit(route, body, binaryData); |
78 | 79 | ``` |
79 | | -#### message without acknowledgment |
80 | | -```javascript |
81 | | -let route = "/"; let msg = "hello"; let binaryData = {data: new TextEncoder().encode("binary")}; |
82 | | -socket.post(route, msg, null, binaryData); // (optional) binaryData: A single binary buffer or multiple binary buffers in an array. |
83 | | -``` |
84 | | - |
85 | | -### Receive a Message via the Socket |
86 | | -#### with req/res style callback |
87 | | -```javascript |
88 | | -socket.on('post', function (route, msg, res, binary) { |
89 | | - if(route === "/") { |
90 | | - console.log(msg) // "hello" |
91 | | - if(binary.data) |
92 | | - res.send('hi', binary); // (optional) binary: A single binary buffer or multiple binary buffers in an array. |
93 | | - else |
94 | | - res.send('hi'); |
95 | | - } |
96 | | -}) |
97 | | -``` |
98 | | -#### message without acknowledgment |
99 | | -```javascript |
100 | | -socket.on('post', function (route, msg, res, binary) { |
101 | | - if(route === "/") |
102 | | - console.log(msg) // "hello" |
103 | | -}) |
104 | | -``` |
105 | 80 |
|
106 | | -Every ``post`` can be replaced with `"beat", "action", "get", "post", "put", "patch", "delete", "new", "message"` |
107 | | - |
108 | | -### Other Socket Events: |
| 81 | +### Additional Socket Events: |
109 | 82 |
|
110 | 83 | ```javascript |
111 | | -socket.on('network', function incoming(newNet, oldNet) { |
112 | | - console.log(newNet, oldNet) // new networkID, old networkID |
113 | | -}); |
114 | | - |
115 | | -socket.on('close', function connection() { |
116 | | - console.log('CONNECTION LOST'); // 'CONNECTION LOST' |
117 | | -}) |
118 | | - |
119 | | -socket.on('open', function open() { |
120 | | - // Place your socket event code here to call it at the right moment. |
| 84 | +// On network ID change, such as when connecting to an existing network |
| 85 | +socket.on('network', (newNet, oldNet) => { |
| 86 | + console.log(newNet, oldNet); |
121 | 87 | }); |
122 | 88 |
|
123 | | -socket.on("status", function(status){ |
124 | | - if(status === socket.OPEN){ |
125 | | - // test for socket open |
126 | | - } else if(status === socket.OPEN){ |
127 | | - // test for socket closed |
128 | | - } |
129 | | -}) |
130 | | - |
131 | | -socket.on('error', function open(e) { |
132 | | - console.log(e); // output error message |
133 | | -}); |
| 89 | +// On WebSocket message received (raw string) |
| 90 | +socket.on('rawMessage', (rawMessage) => {}); |
134 | 91 |
|
135 | | -socket.on('connected', function open() {}); |
| 92 | +// On WebSocket message dropped (could not be processed into a ToolSocketMessage) |
| 93 | +socket.on('droppedMessage', (droppedMessage) => {}); |
136 | 94 |
|
137 | | -``` |
138 | | -## socket.io Compatibility |
139 | | -ToolSocket.io is a socket.io API compatible server (nodejs only) and client for nodejs and browsers. |
| 95 | +// On WebSocket message sent (raw string) |
| 96 | +socket.on('rawSend', (rawSentMessage) => {}); |
140 | 97 |
|
| 98 | +// On ToolSocket message sent (see ToolSocketMessage) |
| 99 | +socket.on('send', (sentMessage) => {}); |
141 | 100 |
|
142 | | -### install |
143 | | -add the following to your package.json |
144 | | -```json |
145 | | -"dependencies":{ |
146 | | - "toolsocket": "ptcrealitylab/toolsocket#main" |
147 | | -} |
148 | | - ``` |
149 | | -`npm install` |
150 | | - |
151 | | -### Initialize Server |
152 | | -```javascript |
153 | | -const ToolSocket = require('toolsocket'); |
154 | | -let serverPort= 12345; |
155 | | -let ioServer = new ToolSocket.Io.Server({port: 12443}); |
156 | | - |
157 | | -ioServer.on('connection', function connection(socket) { |
158 | | - // place your socket code here |
159 | | -}); |
160 | | -``` |
161 | | -### Initialize Server with HTTP |
162 | | -```javascript |
163 | | -let ioServer = new ToolSocket.Io.Server({Server: http}); |
164 | | -ioServer.on('connection', (socket) => { |
165 | | - //socket code here |
| 101 | +// On connection open |
| 102 | +socket.on('open', () => { |
| 103 | + console.log('CONNECTION OPEN'); |
166 | 104 | }); |
167 | | -``` |
168 | 105 |
|
169 | | -### Initialize Client in Nodejs |
170 | | -```javascript |
171 | | -const ToolSocket = require('toolsocket'); |
172 | | -let io = new ToolSocket.Io(); |
173 | | -let socket = io.connect("ws://localhost:12443/n/networkName"); |
174 | | -``` |
| 106 | +// On connection close |
| 107 | +socket.on('close', () => { |
| 108 | + console.log('CONNECTION CLOSED'); |
| 109 | +}); |
175 | 110 |
|
176 | | -### Initialize Client in Web-Browser |
177 | | -```html |
178 | | -<script src="node_modules/toolsocket/index.js"></script> |
179 | | -<script> |
180 | | - let socket = io.connect("ws://localhost:12443/n/networkName"); |
181 | | -</script> |
182 | | -``` |
183 | | -Connecting to origin server works without any arguments: |
184 | | -```html |
185 | | -<script src="node_modules/toolsocket/index.js"></script> |
186 | | -<script> |
187 | | - let socket = io.connect(); |
188 | | -</script> |
189 | | -``` |
| 111 | +// Subscribe to underlying WebSocket connection events directly |
| 112 | +socket.on('status', (status) => { |
| 113 | + if (status === socket.CONNECTING) { |
| 114 | + console.log('CONNECTION CONNECTING'); |
| 115 | + } else if (status === socket.OPEN){ |
| 116 | + console.log('CONNECTION OPEN'); |
| 117 | + } else if (status === socket.CLOSING){ |
| 118 | + console.log('CONNECTION CLOSING'); |
| 119 | + } else if (status === socket.CLOSED){ |
| 120 | + console.log('CONNECTION CLOSED'); |
| 121 | + } |
| 122 | +}) |
190 | 123 |
|
191 | | -### Send a Message via the Socket |
192 | | -#### with req/res style callback |
193 | | -```javascript |
194 | | -// with req/res call back |
195 | | -let title = "/"; |
196 | | -let msg = "hello"; |
197 | | -let binaryData = {data: new TextEncoder().encode("binary")}; |
| 124 | +// On WebSocket error |
| 125 | +socket.on('error', (error) => { |
| 126 | + console.error(error); // output error message |
| 127 | +}); |
198 | 128 |
|
199 | | -socket.emit(title, msg,binaryData); // (optional) binary: A single binary buffer or multiple binary buffers in an array. |
| 129 | +// Same as 'open' |
| 130 | +socket.on('connected', () => {}); |
200 | 131 | ``` |
201 | 132 |
|
202 | | -### Receive a Message via the Socket |
203 | | -#### with req/res style callback |
204 | | -```javascript |
205 | | -let title = "/"; |
206 | | -socket.on(title , function (msg, binary) { |
207 | | - if(binary.data) |
208 | | - console.log('hi', binary); // (optional) binary: A single binary buffer or multiple binary buffers in an array. |
209 | | - else |
210 | | - console.log('hi'); |
211 | | -}) |
212 | | -``` |
213 | | -### Setter |
| 133 | +## Underlying Message Format |
| 134 | +ToolSocket's underlying WebSocket messages use the shorthand single-letter keys seen below, but ToolSocket exposes |
| 135 | +clearly named getters and setters for ease of use. See `src/ToolSocketMessage.js` for more details. |
214 | 136 |
|
215 | | -```javascript |
216 | | -socket.close(); |
217 | | -``` |
218 | | -### Getters |
219 | | -Get if the socked is connected |
220 | | -```javascript |
221 | | -socket.connected(); |
222 | 137 | ``` |
223 | | -Each socket on the **server** has an id: |
224 | | -```javascript |
225 | | -socket.id |
226 | | -``` |
227 | | -And the server has an object that stores all sockets. |
228 | | -```javascript |
229 | | -ioServer.sockets[socket.id] |
| 138 | +{ |
| 139 | + o/origin: (e.g. client, web, server), |
| 140 | + n/network: (can be thought of as a socket.io room), |
| 141 | + m/method: (e.g. get, post, delete), |
| 142 | + r/route: (e.g. /about, /home), |
| 143 | + b/body: (an arbitrary JS object to be stringified), |
| 144 | + i/id: (an ID for listening for responses), |
| 145 | + s/secret: (used to manage write access), |
| 146 | + f/frameCount: (number of binary buffers that will be sent following this message) |
| 147 | +} |
230 | 148 | ``` |
0 commit comments