Skip to content

Commit

Permalink
Merge pull request #7 from ptcrealitylab/refactor
Browse files Browse the repository at this point in the history
Major ToolSocket Refactor
  • Loading branch information
dangond-ptc authored Apr 11, 2024
2 parents 1a9e0ca + 062888b commit bf8e2be
Show file tree
Hide file tree
Showing 26 changed files with 3,181 additions and 1,651 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
node-version: [16.x, 18.x, 20.x]
# Steps represent a sequence of tasks that will be executed as part of the job

steps:
Expand Down
308 changes: 113 additions & 195 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,230 +1,148 @@
## ToolSocket
#### For socket.io API compatibility scroll down!
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.

+ It supports Req/Res, messages without acknowledgment, and in future Pub/Sub all via a single Websocket.
+ The API for browser and nodejs is identical.
+ Build-in data package validator uses JSON schema.
+ The minified library file size is only 7 kb.
+ The communication protocol is standard conform WebSocket with a JSON based message package:

````javascript
// code snipets from line 51
this.DataPackage = function (origin, network, method, route, body, id = null) {
this.i = id; // Package id for response otherwise null
this.o = origin; // Package origin [client, web, server]
this.n = network; // NetworkID (think about it as room)
this.m = method; // Method such as post, get, action, ...
this.r = route; // Package route. Example "/boston/seaport/ptc"
this.b = body; // Message body (object, array, number, string)
this.s = null // (optional) Secret used to manage write access.
this.f = null // (optional) amount of binary buffers in array attached to a message
};
````

### install
add the following to your package.json
```json
"dependencies":{
"toolsocket": "ptcrealitylab/toolsocket#main"
}
```
`npm install`
# ToolSocket

## Setup

### Installing for Production (Node.js)
Run `npm i toolsocket` in your project directory.

### Installing for Development (Node.js)
Run `npm link` in your `toolsocket` repository, then `npm link toolsocket` in your projects
that use `toolsocket`. They should now be linked to your local `toolsocket` repository.

### Building ToolSocket (Web)
Run `npm run build`, then copy `dist/toolsocket.js` to your server and load it in a script tag.
The build script automatically minifies `dist/toolsocket.js` for you.

### Testing
Run the included jest test suite via `npm run test`.

Run tests with coverage analysis via `npm run coverage`.

## Usage

### Initialize Server
### Server
```javascript
const ToolSocket = require('toolsocket');
let serverPort= 12345;
let webSocketServer = new ToolSocket.Server({port: serverPort, origin: 'proxy'});
const webSocketServer = new ToolSocket.Server({/* WS server options go here */});

webSocketServer.on('connection', function connection(socket) {
// place your socket code here
// Method-style request handling
socket.on('post', (route, body, res, binaryData) => {
if (route === "/") {
console.log(body); // "hello"
if (res) { // res object is available only if sender registered a callback
if (binaryData) {
res.send('hi', binaryData); // res.send can optionally send binaryData (Uint8Array) as well
} else {
res.send('hi');
}
}
}
});

// Event-style request handling (Cannot send responses)
socket.on('/', (body, binary) => {
console.log(body); // "hello"
if (binaryData) {
console.log('hi', binaryData);
} else {
console.log('hi');
}
});
});
```

### Initialize Server with HTTP
```javascript
let webSocketServer = new ToolSocket.Server({Server: http});
### Client
In your html file:
```html
<script src="dist/toolsocket.js"></script>
```

### Initialize Client in Nodejs

In your js code:
```javascript
const ToolSocket = require("toolsocket");
let socket = new ToolSocket('ws://localhost:12345', 'networkID', 'client');
```
const socket = new ToolSocket('ws://localhost:12345', 'networkID', 'client');

### Initialize Client in Web-Browser
const route = "/";
const body = "hello";
const binaryData = new TextEncoder().encode("binary");

```html
<script src="node_modules/toolsocket/index.js"></script>
<script>
let socket = new ToolSocket('ws://localhost:12345', 'networkID', 'web');
</script>
```
// Method-style request without acknowledgement
socket.post(route, body, null, binaryData);

Network ID is like a Room that allows you to group messages by a specific Network.
// Method-style request with callback
socket.post(route, body, (responseMsg, _responseBinary) => {
console.log(responseMsg); // "hi"
}, binaryData); // binaryData is optional and must be a Uint8Array

### Send a Message via the Socket
#### with req/res style callback
```javascript
// with req/res call back
let route = "/"; let msg = "hello"; let binaryData = {data: new TextEncoder().encode("binary")};
socket.post(route, msg, function (msg) {
console.log(msg); // "hi"
},
binaryData // (optional) A single binary buffer or multiple binary buffers in an array.
);
// Event-style request (cannot be used with callbacks)
socket.emit(route, body, binaryData);
```
#### message without acknowledgment
```javascript
let route = "/"; let msg = "hello"; let binaryData = {data: new TextEncoder().encode("binary")};
socket.post(route, msg, null, binaryData); // (optional) binaryData: A single binary buffer or multiple binary buffers in an array.
```

### Receive a Message via the Socket
#### with req/res style callback
```javascript
socket.on('post', function (route, msg, res, binary) {
if(route === "/") {
console.log(msg) // "hello"
if(binary.data)
res.send('hi', binary); // (optional) binary: A single binary buffer or multiple binary buffers in an array.
else
res.send('hi');
}
})
```
#### message without acknowledgment
```javascript
socket.on('post', function (route, msg, res, binary) {
if(route === "/")
console.log(msg) // "hello"
})
```

Every ``post`` can be replaced with `"beat", "action", "get", "post", "put", "patch", "delete", "new", "message"`

### Other Socket Events:
### Additional Socket Events:

```javascript
socket.on('network', function incoming(newNet, oldNet) {
console.log(newNet, oldNet) // new networkID, old networkID
});

socket.on('close', function connection() {
console.log('CONNECTION LOST'); // 'CONNECTION LOST'
})

socket.on('open', function open() {
// Place your socket event code here to call it at the right moment.
// On network ID change, such as when connecting to an existing network
socket.on('network', (newNet, oldNet) => {
console.log(newNet, oldNet);
});

socket.on("status", function(status){
if(status === socket.OPEN){
// test for socket open
} else if(status === socket.OPEN){
// test for socket closed
}
})

socket.on('error', function open(e) {
console.log(e); // output error message
});
// On WebSocket message received (raw string)
socket.on('rawMessage', (rawMessage) => {});

socket.on('connected', function open() {});
// On WebSocket message dropped (could not be processed into a ToolSocketMessage)
socket.on('droppedMessage', (droppedMessage) => {});

```
## socket.io Compatibility
ToolSocket.io is a socket.io API compatible server (nodejs only) and client for nodejs and browsers.
// On WebSocket message sent (raw string)
socket.on('rawSend', (rawSentMessage) => {});

// On ToolSocket message sent (see ToolSocketMessage)
socket.on('send', (sentMessage) => {});

### install
add the following to your package.json
```json
"dependencies":{
"toolsocket": "ptcrealitylab/toolsocket#main"
}
```
`npm install`

### Initialize Server
```javascript
const ToolSocket = require('toolsocket');
let serverPort= 12345;
let ioServer = new ToolSocket.Io.Server({port: 12443});

ioServer.on('connection', function connection(socket) {
// place your socket code here
});
```
### Initialize Server with HTTP
```javascript
let ioServer = new ToolSocket.Io.Server({Server: http});
ioServer.on('connection', (socket) => {
//socket code here
// On connection open
socket.on('open', () => {
console.log('CONNECTION OPEN');
});
```

### Initialize Client in Nodejs
```javascript
const ToolSocket = require('toolsocket');
let io = new ToolSocket.Io();
let socket = io.connect("ws://localhost:12443/n/networkName");
```
// On connection close
socket.on('close', () => {
console.log('CONNECTION CLOSED');
});

### Initialize Client in Web-Browser
```html
<script src="node_modules/toolsocket/index.js"></script>
<script>
let socket = io.connect("ws://localhost:12443/n/networkName");
</script>
```
Connecting to origin server works without any arguments:
```html
<script src="node_modules/toolsocket/index.js"></script>
<script>
let socket = io.connect();
</script>
```
// Subscribe to underlying WebSocket connection events directly
socket.on('status', (status) => {
if (status === socket.CONNECTING) {
console.log('CONNECTION CONNECTING');
} else if (status === socket.OPEN){
console.log('CONNECTION OPEN');
} else if (status === socket.CLOSING){
console.log('CONNECTION CLOSING');
} else if (status === socket.CLOSED){
console.log('CONNECTION CLOSED');
}
})

### Send a Message via the Socket
#### with req/res style callback
```javascript
// with req/res call back
let title = "/";
let msg = "hello";
let binaryData = {data: new TextEncoder().encode("binary")};
// On WebSocket error
socket.on('error', (error) => {
console.error(error); // output error message
});

socket.emit(title, msg,binaryData); // (optional) binary: A single binary buffer or multiple binary buffers in an array.
// Same as 'open'
socket.on('connected', () => {});
```

### Receive a Message via the Socket
#### with req/res style callback
```javascript
let title = "/";
socket.on(title , function (msg, binary) {
if(binary.data)
console.log('hi', binary); // (optional) binary: A single binary buffer or multiple binary buffers in an array.
else
console.log('hi');
})
```
### Setter
## Underlying Message Format
ToolSocket's underlying WebSocket messages use the shorthand single-letter keys seen below, but ToolSocket exposes
clearly named getters and setters for ease of use. See `src/ToolSocketMessage.js` for more details.

```javascript
socket.close();
```
### Getters
Get if the socked is connected
```javascript
socket.connected();
```
Each socket on the **server** has an id:
```javascript
socket.id
```
And the server has an object that stores all sockets.
```javascript
ioServer.sockets[socket.id]
{
o/origin: (e.g. client, web, server),
n/network: (can be thought of as a socket.io room),
m/method: (e.g. get, post, delete),
r/route: (e.g. /about, /home),
b/body: (an arbitrary JS object to be stringified),
i/id: (an ID for listening for responses),
s/secret: (used to manage write access),
f/frameCount: (number of binary buffers that will be sent following this message)
}
```
25 changes: 0 additions & 25 deletions example.html

This file was deleted.

Loading

0 comments on commit bf8e2be

Please sign in to comment.