From 32aa534771b285a8ce683aebc367afac81cdaac9 Mon Sep 17 00:00:00 2001 From: Josephus Paye II Date: Thu, 7 Feb 2019 15:25:49 +1100 Subject: [PATCH 1/5] Add support for sending messages from NUsight --- src/client/network/network.ts | 18 +++++++++++++++ src/client/network/nusight_network.ts | 5 ++++ .../web_socket_proxy_nuclearnet_client.ts | 4 +--- .../nuclearnet/fake_nuclearnet_server.ts | 11 +-------- .../web_socket_proxy_nuclearnet_server.ts | 10 ++++++-- .../nuclearnet/nuclearnet_proxy_parser.ts | 23 ++++++++++++++++++- 6 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/client/network/network.ts b/src/client/network/network.ts index e0982771..8c566146 100644 --- a/src/client/network/network.ts +++ b/src/client/network/network.ts @@ -2,6 +2,12 @@ import { NUsightNetwork } from './nusight_network' import { MessageType } from './nusight_network' import { MessageCallback } from './nusight_network' +export interface Message { + messageType: string + buffer: Uint8Array + reliable?: boolean +} + /** * A convenience helper class to be used at the component-level. * @@ -44,4 +50,16 @@ export class Network { } this.offNUClearMessages.clear() } + + /** + * Send the given message on the network + */ + send(message: Message, target?: string): void { + this.nusightNetwork.send({ + type: message.messageType, + payload: Buffer.from(message.buffer), + reliable: message.reliable, + target, + }) + } } diff --git a/src/client/network/nusight_network.ts b/src/client/network/nusight_network.ts index e51a3365..2df0c3a1 100644 --- a/src/client/network/nusight_network.ts +++ b/src/client/network/nusight_network.ts @@ -1,6 +1,7 @@ import { NUClearNetPacket } from 'nuclearnet.js' import { NUClearNetOptions } from 'nuclearnet.js' import { NUClearNetPeer } from 'nuclearnet.js' +import { NUClearNetSend } from 'nuclearnet.js' import { NUClearNetClient } from '../../shared/nuclearnet/nuclearnet_client' import { AppModel } from '../components/app/model' @@ -30,6 +31,10 @@ export class NUsightNetwork { return this.nuclearnetClient.connect(opts) } + send(opts: NUClearNetSend) { + this.nuclearnetClient.send(opts) + } + onNUClearMessage(messageType: MessageType, cb: MessageCallback) { const messageTypeName = this.messageTypePath.getPath(messageType) return this.nuclearnetClient.on(messageTypeName, (packet: NUClearNetPacket) => { diff --git a/src/client/nuclearnet/web_socket_proxy_nuclearnet_client.ts b/src/client/nuclearnet/web_socket_proxy_nuclearnet_client.ts index efa5b503..f038a6ab 100644 --- a/src/client/nuclearnet/web_socket_proxy_nuclearnet_client.ts +++ b/src/client/nuclearnet/web_socket_proxy_nuclearnet_client.ts @@ -119,9 +119,7 @@ export class WebSocketProxyNUClearNetClient implements NUClearNetClient { } send(options: NUClearNetSend): void { - if (typeof options.type === 'string') { - this.socket.send(options.type, options) - } + this.socket.send('packet', options) } private onReconnect = (options: NUClearNetOptions) => { diff --git a/src/server/nuclearnet/fake_nuclearnet_server.ts b/src/server/nuclearnet/fake_nuclearnet_server.ts index 1d8dc14b..d2e676f5 100644 --- a/src/server/nuclearnet/fake_nuclearnet_server.ts +++ b/src/server/nuclearnet/fake_nuclearnet_server.ts @@ -3,6 +3,7 @@ import { NUClearNetSend } from 'nuclearnet.js' import * as XXH from 'xxhashjs' import { createSingletonFactory } from '../../shared/base/create_singleton_factory' +import { hashType } from '../../shared/nuclearnet/nuclearnet_proxy_parser' import { FakeNUClearNetClient } from './fake_nuclearnet_client' @@ -85,13 +86,3 @@ export class FakeNUClearNetServer { } } } - -export function hashType(type: string): Buffer { - // Matches hashing implementation from NUClearNet - // See https://goo.gl/6NDPo2 - let hashString: string = XXH.h64(type, 0x4e55436c).toString(16) - // The hash string may truncate if it's smaller than 16 characters so we pad it with 0s - hashString = ('0'.repeat(16) + hashString).slice(-16) - - return Buffer.from((hashString.match(/../g) as string[]).reverse().join(''), 'hex') -} diff --git a/src/server/nuclearnet/web_socket_proxy_nuclearnet_server.ts b/src/server/nuclearnet/web_socket_proxy_nuclearnet_server.ts index 32272885..ded329ab 100644 --- a/src/server/nuclearnet/web_socket_proxy_nuclearnet_server.ts +++ b/src/server/nuclearnet/web_socket_proxy_nuclearnet_server.ts @@ -1,3 +1,4 @@ +import { NUClearNetSend } from 'nuclearnet.js' import { NUClearNetOptions } from 'nuclearnet.js' import { NUClearNetPeer } from 'nuclearnet.js' import { NUClearNetPacket } from 'nuclearnet.js' @@ -52,6 +53,7 @@ class WebSocketServerClient { this.offLeave = this.nuclearnetClient.onLeave(this.onLeave) this.offListenMap = new Map() + this.socket.on('packet', this.onClientPacket) this.socket.on('listen', this.onListen) this.socket.on('unlisten', this.onUnlisten) this.socket.on('nuclear_connect', this.onConnect) @@ -85,7 +87,7 @@ class WebSocketServerClient { } private onListen = (event: string, requestToken: string) => { - const off = this.nuclearnetClient.on(event, this.onPacket.bind(this, event)) + const off = this.nuclearnetClient.on(event, this.onServerPacket.bind(this, event)) this.offListenMap.set(requestToken, off) } @@ -101,9 +103,13 @@ class WebSocketServerClient { this.offLeave() } - private onPacket = (event: string, packet: NUClearNetPacket) => { + private onServerPacket = (event: string, packet: NUClearNetPacket) => { this.processor.onPacket(event, packet) } + + private onClientPacket = (options: NUClearNetSend) => { + this.nuclearnetClient.send(options) + } } class PacketProcessor { diff --git a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts index b74a1033..ae032ef0 100644 --- a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts +++ b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts @@ -1,6 +1,7 @@ import * as Emitter from 'component-emitter' import { NUClearNetPacket } from 'nuclearnet.js' import { NUClearNetPeer } from 'nuclearnet.js' +import * as XXH from 'xxhashjs' import { Packet } from './nuclearnet_proxy_parser_socketio' import { TYPES } from './nuclearnet_proxy_parser_socketio' @@ -35,8 +36,17 @@ export class Encoder { case 'unlisten': return callback([JSON.stringify(packet)]) + case 'packet': { + const { id, data: [key, { target, type, payload, reliable }] } = packet + return callback([ + JSON.stringify({ id, nsp, key, header: { target, type, reliable } }), + hashType(type), + payload, + ]) + } + // For NUClearNet packets, we send the payload separately to avoid array slicing later - default: + default: { const { id, data: [key, { peer, hash, payload, reliable }] } = packet // Send the header as a JSON and then the payload as binary @@ -45,6 +55,7 @@ export class Encoder { hash, payload, ]) + } } default: return callback([JSON.stringify(packet)]) @@ -110,3 +121,13 @@ export class Decoder extends Emitter { this.nuclearPacket = undefined } } + +export function hashType(type: string): Buffer { + // Matches hashing implementation from NUClearNet + // See https://goo.gl/6NDPo2 + let hashString: string = XXH.h64(type, 0x4e55436c).toString(16) + // The hash string may truncate if it's smaller than 16 characters so we pad it with 0s + hashString = ('0'.repeat(16) + hashString).slice(-16) + + return Buffer.from((hashString.match(/../g) as string[]).reverse().join(''), 'hex') +} From 8f509812b65b598130c56aa7328274402b8a3f09 Mon Sep 17 00:00:00 2001 From: Josephus Paye II Date: Thu, 7 Feb 2019 16:45:05 +1100 Subject: [PATCH 2/5] Move hashType back to fake_nuclearnet_server --- src/server/nuclearnet/fake_nuclearnet_server.ts | 11 ++++++++++- src/shared/nuclearnet/nuclearnet_proxy_parser.ts | 12 ------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/server/nuclearnet/fake_nuclearnet_server.ts b/src/server/nuclearnet/fake_nuclearnet_server.ts index d2e676f5..1d8dc14b 100644 --- a/src/server/nuclearnet/fake_nuclearnet_server.ts +++ b/src/server/nuclearnet/fake_nuclearnet_server.ts @@ -3,7 +3,6 @@ import { NUClearNetSend } from 'nuclearnet.js' import * as XXH from 'xxhashjs' import { createSingletonFactory } from '../../shared/base/create_singleton_factory' -import { hashType } from '../../shared/nuclearnet/nuclearnet_proxy_parser' import { FakeNUClearNetClient } from './fake_nuclearnet_client' @@ -86,3 +85,13 @@ export class FakeNUClearNetServer { } } } + +export function hashType(type: string): Buffer { + // Matches hashing implementation from NUClearNet + // See https://goo.gl/6NDPo2 + let hashString: string = XXH.h64(type, 0x4e55436c).toString(16) + // The hash string may truncate if it's smaller than 16 characters so we pad it with 0s + hashString = ('0'.repeat(16) + hashString).slice(-16) + + return Buffer.from((hashString.match(/../g) as string[]).reverse().join(''), 'hex') +} diff --git a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts index ae032ef0..87fd102a 100644 --- a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts +++ b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts @@ -1,7 +1,6 @@ import * as Emitter from 'component-emitter' import { NUClearNetPacket } from 'nuclearnet.js' import { NUClearNetPeer } from 'nuclearnet.js' -import * as XXH from 'xxhashjs' import { Packet } from './nuclearnet_proxy_parser_socketio' import { TYPES } from './nuclearnet_proxy_parser_socketio' @@ -40,7 +39,6 @@ export class Encoder { const { id, data: [key, { target, type, payload, reliable }] } = packet return callback([ JSON.stringify({ id, nsp, key, header: { target, type, reliable } }), - hashType(type), payload, ]) } @@ -121,13 +119,3 @@ export class Decoder extends Emitter { this.nuclearPacket = undefined } } - -export function hashType(type: string): Buffer { - // Matches hashing implementation from NUClearNet - // See https://goo.gl/6NDPo2 - let hashString: string = XXH.h64(type, 0x4e55436c).toString(16) - // The hash string may truncate if it's smaller than 16 characters so we pad it with 0s - hashString = ('0'.repeat(16) + hashString).slice(-16) - - return Buffer.from((hashString.match(/../g) as string[]).reverse().join(''), 'hex') -} From 0f7b274d750b727a7b36c4beaa63f602c7ca6dae Mon Sep 17 00:00:00 2001 From: Josephus Paye II Date: Thu, 7 Feb 2019 16:45:19 +1100 Subject: [PATCH 3/5] Update parser, fix failing test --- ...web_socket_proxy_nuclearnet_client.tests.ts | 2 +- .../nuclearnet/nuclearnet_proxy_parser.ts | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/client/nuclearnet/tests/web_socket_proxy_nuclearnet_client.tests.ts b/src/client/nuclearnet/tests/web_socket_proxy_nuclearnet_client.tests.ts index 4d55529e..c6c9c690 100644 --- a/src/client/nuclearnet/tests/web_socket_proxy_nuclearnet_client.tests.ts +++ b/src/client/nuclearnet/tests/web_socket_proxy_nuclearnet_client.tests.ts @@ -88,7 +88,7 @@ describe('WebSocketProxyNUClearNetClient', () => { payload: Buffer.alloc(8), } client.send(opts) - expect(mockWebSocket.send).toHaveBeenCalledWith('foo', opts) + expect(mockWebSocket.send).toHaveBeenCalledWith('packet', opts) }) }) }) diff --git a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts index 87fd102a..f5287a76 100644 --- a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts +++ b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts @@ -1,6 +1,7 @@ import * as Emitter from 'component-emitter' import { NUClearNetPacket } from 'nuclearnet.js' import { NUClearNetPeer } from 'nuclearnet.js' +import { NUClearNetSend } from 'nuclearnet.js' import { Packet } from './nuclearnet_proxy_parser_socketio' import { TYPES } from './nuclearnet_proxy_parser_socketio' @@ -67,7 +68,7 @@ export class Decoder extends Emitter { private nuclearPacket?: { nsp: string, type: TYPES.EVENT, - data: [string, Partial], + data: [string, Partial | Partial], id: number } @@ -94,10 +95,19 @@ export class Decoder extends Emitter { } } else { switch (this.state) { - // State 1 means we are getting a hash + // State 1 means we are getting a payload or hash case 1: - this.nuclearPacket!.data[1].hash = obj - this.state = 2 + // 'packet' messages are sent using NUClearNetSend which doesn't have a hash + if (this.nuclearPacket!.data[0] === 'packet') { + this.nuclearPacket!.data[1].payload = obj + this.emit('decoded', this.nuclearPacket) + this.state = 0 + } + // For NUClearNetPackets we get a hash in state 1 and move to state 2 for the payload + else { + (this.nuclearPacket!.data[1] as NUClearNetPacket).hash = obj + this.state = 2 + } break // State 2 means we are getting a packet From bdd978e80729780a4e21aa50d36c47c47855e938 Mon Sep 17 00:00:00 2001 From: Josephus Paye II Date: Thu, 7 Feb 2019 16:48:00 +1100 Subject: [PATCH 4/5] Fix lint --- src/shared/nuclearnet/nuclearnet_proxy_parser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts index f5287a76..b620753a 100644 --- a/src/shared/nuclearnet/nuclearnet_proxy_parser.ts +++ b/src/shared/nuclearnet/nuclearnet_proxy_parser.ts @@ -97,14 +97,14 @@ export class Decoder extends Emitter { switch (this.state) { // State 1 means we are getting a payload or hash case 1: - // 'packet' messages are sent using NUClearNetSend which doesn't have a hash if (this.nuclearPacket!.data[0] === 'packet') { + // 'packet' messages are sent using NUClearNetSend which doesn't have a hash, + // so here we get the payload and emit this.nuclearPacket!.data[1].payload = obj this.emit('decoded', this.nuclearPacket) this.state = 0 - } - // For NUClearNetPackets we get a hash in state 1 and move to state 2 for the payload - else { + } else { + // For NUClearNetPackets we get a hash in state 1 and move to state 2 for the payload (this.nuclearPacket!.data[1] as NUClearNetPacket).hash = obj this.state = 2 } From f74dd184fba56d0249c7f07890214d08d63c9a1a Mon Sep 17 00:00:00 2001 From: Josephus Paye II Date: Thu, 7 Feb 2019 17:06:02 +1100 Subject: [PATCH 5/5] Make network.send() accept a NUClearNetSend --- src/client/network/network.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/client/network/network.ts b/src/client/network/network.ts index 8c566146..8ef7a0b6 100644 --- a/src/client/network/network.ts +++ b/src/client/network/network.ts @@ -1,13 +1,9 @@ +import { NUClearNetSend } from 'nuclearnet.js' + import { NUsightNetwork } from './nusight_network' import { MessageType } from './nusight_network' import { MessageCallback } from './nusight_network' -export interface Message { - messageType: string - buffer: Uint8Array - reliable?: boolean -} - /** * A convenience helper class to be used at the component-level. * @@ -54,12 +50,7 @@ export class Network { /** * Send the given message on the network */ - send(message: Message, target?: string): void { - this.nusightNetwork.send({ - type: message.messageType, - payload: Buffer.from(message.buffer), - reliable: message.reliable, - target, - }) + send(opts: NUClearNetSend): void { + this.nusightNetwork.send(opts) } }