Skip to content

Commit e83ca44

Browse files
authored
Merge pull request #9 from ptcrealitylab/parallelSockets
Add support for creation of parallel sockets for large messages
2 parents 5fd4f7b + 878803e commit e83ca44

6 files changed

Lines changed: 91 additions & 12 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "toolsocket",
3-
"version": "2.0.1",
3+
"version": "2.1.0",
44
"description": "A communication layer built on top of WebSocket for Node.js and browsers.",
55
"main": "src/index.js",
66
"scripts": {

src/IncomingToolSocket.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const ToolSocket = require("./ToolSocket");
2+
3+
class IncomingToolSocket extends ToolSocket {
4+
/**
5+
* Creates an IncomingToolSocket from an incoming WebSocket connection. Used by ToolSocketServer.
6+
* @param {WebSocket} websocket - The incoming WebSocket connection.
7+
* @param {ToolSocketServer} server - The ToolSocketServer this is attached to.
8+
*/
9+
constructor(websocket, server) {
10+
super();
11+
this.socket = websocket;
12+
this.networkId = 'toolbox'; // Or 'io'?
13+
this.origin = server.origin;
14+
this.server = server;
15+
this.configureSocket();
16+
}
17+
18+
/**
19+
* Requests the source to create another ToolSocket connection for parallel data transfer.
20+
* @return {Promise<ToolSocket>} - The parallel socket we just created.
21+
*/
22+
requestParallelSocket() {
23+
return this.server.requestParallelSocket(this);
24+
}
25+
}
26+
27+
module.exports = IncomingToolSocket;

src/ToolSocket.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,20 @@ class ToolSocket {
152152
}
153153
});
154154

155+
this.addEventListener('meta', (route, body, _response, _binaryData, _messageBundle) => {
156+
if (route === 'requestParallel') {
157+
this.triggerEvent('requestParallel', body); // body = id
158+
} else if (route === 'confirmParallel') {
159+
this.triggerEvent('confirmParallel', body); // body = id
160+
} else {
161+
console.warn(`Received unknown meta route: "${route}"`);
162+
}
163+
});
164+
155165
// We're receiving an event, trigger it
156166
this.addEventListener('io', (route, body, _responseObject, binaryData) => {
157167
if (VALID_METHODS.includes(route)) {
158-
console.warn(`Received IO message with route, ${route}, which cannot be distinguished from the request method with the same name. Please pick a different route.`);
168+
console.warn(`Received IO message with route: "${route}", which cannot be distinguished from the request method with the same name. Please pick a different route.`);
159169
}
160170
this.triggerEvent(route, body, binaryData);
161171
});
@@ -557,6 +567,17 @@ class ToolSocket {
557567
this.sendMethod('unsub', route, body, callback, binaryData);
558568
}
559569

570+
/**
571+
* Sends a META message, used for ToolSocket internal messages (i.e. requestParallel)
572+
* @param {string} route - The route
573+
* @param {any} body - The message body
574+
* @param {function} [callback] - A callback function that is called if a response is required
575+
* @param {object} [binaryData] - Binary data
576+
*/
577+
meta(route, body, callback, binaryData) {
578+
this.sendMethod('meta', route, body, callback, binaryData);
579+
}
580+
560581
/**
561582
* Adds aliases for backwards compatibility
562583
*/
@@ -570,6 +591,15 @@ class ToolSocket {
570591
this.CLOSING = WebSocketWrapper.CLOSING;
571592
this.CLOSED = WebSocketWrapper.CLOSED;
572593
}
594+
595+
/**
596+
* Clones a ToolSocket, creating a parallel connection to the same endpoint.
597+
* @param {ToolSocket} toolsocket - The source ToolSocket.
598+
* @returns {ToolSocket} - A new ToolSocket created to the same endpoint as the original.
599+
*/
600+
static makeParallelSocket(toolsocket) {
601+
return new ToolSocket(toolsocket.url, toolsocket.networkId, 'parallel');
602+
}
573603
}
574604

575605
module.exports = ToolSocket;

src/ToolSocketServer.js

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
const ToolSocket = require('./ToolSocket.js');
2-
31
const { WebSocketWrapper } = require('./utilities.js');
42
const { URL_SCHEMA, MESSAGE_BUNDLE_SCHEMA } = require('./schemas.js');
3+
const IncomingToolSocket = require('./IncomingToolSocket');
4+
const {generateUniqueId} = require("./utilities");
55

66
/**
77
* A server for ToolSocket
@@ -21,19 +21,25 @@ class ToolSocketServer {
2121

2222
this.eventCallbacks = {}; // For internal events
2323

24+
this.pendingParallelRequests = new Map();
25+
2426
this.server.on('listening', (...args) => {
2527
this.triggerEvent('listening', ...args);
2628
});
2729

2830
this.server.on('connection', socket => {
29-
const toolSocket = new ToolSocket();
30-
toolSocket.socket = socket;
31-
toolSocket.networkId = 'toolbox'; // Or 'io'?
32-
toolSocket.origin = this.origin;
33-
toolSocket.configureSocket();
31+
const toolSocket = new IncomingToolSocket(socket, this);
3432
this.sockets.push(toolSocket);
3533
this.triggerEvent('connection', toolSocket);
3634

35+
toolSocket.on('confirmParallel', id => {
36+
if (this.pendingParallelRequests.has(id)) {
37+
const resolve = this.pendingParallelRequests.get(id);
38+
resolve(toolSocket);
39+
this.pendingParallelRequests.delete(id);
40+
}
41+
});
42+
3743
socket.on('close', () => {
3844
this.sockets.splice(this.sockets.indexOf(toolSocket), 1);
3945
});
@@ -88,6 +94,22 @@ class ToolSocketServer {
8894
this.server.server = this.server;
8995
}
9096

97+
/**
98+
* Requests the source to create another ToolSocket connection for parallel data transfer.
99+
* @param {ToolSocket} toolSocket - The toolSocket requesting a parallel connection.
100+
* @return {Promise<ToolSocket>} - The parallel socket we just created.
101+
*/
102+
requestParallelSocket(toolSocket) {
103+
const id = generateUniqueId(8);
104+
toolSocket.meta('requestParallel', id, null, null);
105+
let resolve;
106+
const promise = new Promise((res) => {
107+
resolve = res;
108+
});
109+
this.pendingParallelRequests.set(id, resolve);
110+
return promise;
111+
}
112+
91113
close() {
92114
this.server.close();
93115
}

src/constants.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
const MAX_MESSAGE_SIZE = 300 * 1024 * 1024;
22
const VALID_FILETYPES = ['css', 'csv', 'dat', 'fbx', 'gif', 'glb', 'htm', 'html', 'jpg', 'jpeg', 'js', 'json', 'map', 'mp4', 'obj', 'otf', 'pdf', 'ply', 'png', 'splat', 'svg', 'ttf', 'wasm', 'webm', 'webp', 'woff', 'xml', 'zip', '3dt'];
33
/**
4-
* @typedef {'action' | 'beat' | 'delete' | 'get' | 'io' | 'keys' | 'message' | 'new' | 'patch' | 'ping' | 'post' | 'pub' | 'put' | 'res' | 'sub' | 'unsub'} MethodString
4+
* @typedef {'action' | 'beat' | 'delete' | 'get' | 'io' | 'keys' | 'message' | 'new' | 'patch' | 'ping' | 'post' | 'pub' | 'put' | 'res' | 'sub' | 'unsub' | 'meta'} MethodString
55
*/
66
/** @type MethodString[] */
7-
const VALID_METHODS = ['action', 'beat', 'delete', 'get', 'io', 'keys', 'message', 'new', 'patch', 'ping', 'post', 'pub', 'put', 'res', 'sub', 'unsub'];
7+
const VALID_METHODS = ['action', 'beat', 'delete', 'get', 'io', 'keys', 'message', 'new', 'patch', 'ping', 'post', 'pub', 'put', 'res', 'sub', 'unsub', 'meta'];
88

99
module.exports = {
1010
MAX_MESSAGE_SIZE,

src/schemas.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const MESSAGE_BUNDLE_SCHEMA = new Schema([
5959
]),
6060
// Origin
6161
new Schema.StringValidator('o', {
62-
enum: ['server', 'client', 'web', 'edge', 'proxy'],
62+
enum: ['server', 'client', 'web', 'edge', 'proxy', 'parallel'],
6363
required: true
6464
}),
6565
// Network

0 commit comments

Comments
 (0)