diff --git a/.gitignore b/.gitignore index 7f78ea9..00e8ee6 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,18 @@ packages/tcp/bin packages/udp/bin packages/ws/bin packages/webrtc/bin + +# publish-only files +packages/kalm/LICENSE +packages/ipc/LICENSE +packages/tcp/LICENSE +packages/udp/LICENSE +packages/ws/LICENSE +packages/webrtc/LICENSE + +packages/kalm/CHANGELOG.md +packages/ipc/CHANGELOG.md +packages/tcp/CHANGELOG.md +packages/udp/CHANGELOG.md +packages/ws/CHANGELOG.md +packages/webrtc/CHANGELOG.md \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7715330 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,127 @@ +# Changelog + +## [v3.3.0] - 2020-01-30 + +commit: [af46059](https://github.com/kalm/kalm.js/commit/af4605958c567b5243887f911850a3c0eb6c6659) + +### Added +- Adds webrtc package and examples +- Adds the getChannels method on Client + +### Removed +- Removed home implementation of EventEmitter in favor of Node's + +## [v3.2.3] - 2020-01-14 + +commit: [c188225](https://github.com/kalm/kalm.js/commit/c18822532a49f2026eddf44cfbe3cfc1521110f8) + +### Added +- Added pre-hook for lint on commit + +### Changed +- Cleaned up Types management and typings file accessibility +- Migrated test suite to Jest and centralized test tooling +- Removed output rollup, and using only tsc with none modules +- Fixed linting (was not targeting .ts files properly) +- Fixed stats events (were previously unreachable, now exposed through client emitter as .*) +- Fixed timeout behavior (only logged, now actually disconnects) + +## [v3.1.2] - 2019-07-01 + +commit: [fac8047](https://github.com/kalm/kalm.js/commit/fac8047d4b7048d56803505103159e16d8f518a8) + +### Changed +- Changed dev tooling from lerna to yarn workspaces +- Changed dev tooling from tslint to eslint + @typescript-eslint +- Housekeeping + +## [v3.0.0] - 2019-01-18 + +commit: [a4c687d](https://github.com/kalm/kalm.js/commit/a4c687dd5786a70723d9d0964a9d189220d58418) + +### Added +- New monorepo structure +- Massive new changes to the interface + +### Changed +- Serialization is now a toggle for json/binary +- Re-written the entire codebase in Typescript + +### Removed +- Transports are no longer bundled and must be installed separately and must be instantiated with options. + - [ipc](https://www.npmjs.com/package/@kalm/ipc) + - [tcp](https://www.npmjs.com/package/@kalm/tcp) + - [udp](https://www.npmjs.com/package/@kalm/udp) + - [ws](https://www.npmjs.com/package/@kalm/ws) +- Profiles become routines and must be instantiated with options. +- No more session stores +- No more encryption + +## [v2.6.1] - 2018-01-27 + +commit: [7393d17](https://github.com/kalm/kalm.js/commit/7393d17efb02088d7283ba83108fd7ab15e3d39e) + +### Added +- Added package-lock.json file +- Added server reference in the client object + +## [v2.5.0] - 2017-09-21 + +commit: [2c687f6](https://github.com/kalm/kalm.js/commit/2c687f6074787af6b39c10abe19669fe20e7b02d) + +### Added +- Added engines reqs + +### Changed +- Some minor performance tuning + +## [v2.4.0] - 2017-09-01 + +commit: [a7b8f95](https://github.com/kalm/kalm.js/commit/a7b8f950da56cbe35c538dc02e3dcc0e6d3a3db3) + +### Changed +- Tuned performances +- Added build targets for Node 8.x and 6.x +- UDP client cache (tied with socketTimeout) +- Bumped dependencies +- Proper callback on disconnect + +### Removed +- Dropped support for Node 4.x + +## [v2.3.0] - 2017-07-25 + +commit: [f323bcd](https://github.com/kalm/kalm.js/commit/f323bcdc163faa40b0f8515fd4a8759e5180f516) + +### Added +- Added realtime profile +- Added JSDoc +- Added parameter validation and error messages + +### Changed +- Better performances (3x with default congestion) + +## [v2.2.0] - 2017-06-21 + +commit: [b9f3bdd](https://github.com/kalm/kalm.js/commit/b9f3bdd50de8dae2b92a0866d234a0cb2e72f22b) + +### Added +- Added support for node 8 + +## [v2.1.0] - 2017-06-20 + +commit: [129146f](https://github.com/kalm/kalm.js/commit/129146feeab14e94a540a4d9c54e05a4614fdb39) + +### Changed +- Simplified and optimized queue system logic +- Now allowing 0 to be passed as tick value in profiles +- Added warning when non-serialized message are sent and serial config is `null` +- Fixed hanging packets on maxBytes just reached + +## [v2.0.0] - 2017-03-02 + +commit: [b5209ec](https://github.com/kalm/kalm.js/commit/b5209ec4d3ab86000b72b502d120f0a5b4da85af) + +### Added +- Migrated the codebase from the [original repo](https://github.com/fed135/kalm) +- Implemeted new interface diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index ebe914b..0000000 --- a/jest.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - globals: { - 'ts-jest': { - diagnostics: false, - }, - }, -}; diff --git a/package.json b/package.json index 3e39537..e32220d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "lint": "eslint **/*.ts **/*.spec.ts", "lint:fix": "yarn lint --fix", - "test": "jest ./packages && jest ./tests/integration --forceExit", + "test": "yarn workspaces run test && jest ./tests/integration --forceExit", "build": "yarn workspaces run build", "clean": "yarn workspaces run clean", "bench": "node ./scripts/benchmarks" @@ -39,23 +39,29 @@ "pre-commit": "yarn lint" } }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } + }, "devDependencies": { - "@types/jest": "^24.0.17", - "@types/node": "^13.1.0", - "@typescript-eslint/eslint-plugin": "^2.14.0", - "@typescript-eslint/parser": "^2.14.0", + "@types/jest": "^25.1.0", + "@types/node": "^13.9.0", + "@typescript-eslint/eslint-plugin": "^2.24.0", + "@typescript-eslint/parser": "^2.24.0", "eslint": "^6.8.0", - "eslint-config-airbnb-base": "^14.0.0", - "eslint-plugin-import": "^2.19.0", - "husky": "^3.1.0", - "jest": "^24.9.0", + "eslint-config-airbnb-base": "^14.1.0", + "eslint-plugin-import": "^2.20.0", + "husky": "^4.2.0", + "jest": "^25.1.0", "socket.io": "^2.3.0", "socket.io-client": "^2.3.0", - "ts-jest": "^24.2.0", - "typescript": "^3.7.4" - }, - "dependencies": { - "webpack": "^4.41.5", - "webpack-cli": "^3.3.10" + "ts-jest": "^25.2.0", + "typescript": "^3.8.0" } } diff --git a/packages/ipc/README.md b/packages/ipc/README.md index 3b36d4b..2877d21 100644 --- a/packages/ipc/README.md +++ b/packages/ipc/README.md @@ -1,4 +1,22 @@ -# Kalm IPC (Inter-process-communication) transport +

+ + Kalm +
+
+ Kalm +

+

+ The Socket Optimizer +

+

+
+ +[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/@kalm/ipc) +[![Build Status](https://github.com/kalm/kalm.js/workflows/master-status/badge.svg)](https://github.com/kalm/kalm.js/actions?query=workflow%3A+master-status) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/kalm/kalm.js) +[![Financial Contributors on Open Collective](https://opencollective.com/kalm/all/badge.svg?label=financial+contributors)](https://opencollective.com/kalm) +[![Join the chat at https://gitter.im/KALM/home](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KALM/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + ## Installing @@ -8,8 +26,8 @@ ``` { - socketTimeout = 30000, - path = '/tmp/app.socket-' + socketTimeout: 30000, + path: '/tmp/app.socket' } ``` diff --git a/packages/ipc/package.json b/packages/ipc/package.json index fc87114..380555c 100644 --- a/packages/ipc/package.json +++ b/packages/ipc/package.json @@ -5,7 +5,9 @@ "main": "bin/ipc.js", "scripts": { "build": "../../scripts/build.sh ipc", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,23 +18,11 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", "ipc" ], "files": ["bin", "types.d.ts"], @@ -49,5 +39,15 @@ "browser": { "net": false, "fs": false + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } diff --git a/packages/ipc/src/ipc.ts b/packages/ipc/src/ipc.ts index d408963..1d1f6db 100644 --- a/packages/ipc/src/ipc.ts +++ b/packages/ipc/src/ipc.ts @@ -13,7 +13,7 @@ interface IPCSocket extends net.Socket { } } -export function ipc({ socketTimeout = 30000, path = '/tmp/app.socket-' }: IPCConfig = {}): KalmTransport { +function ipc({ socketTimeout = 30000, path = '/tmp/app.socket-' }: IPCConfig = {}): KalmTransport { return function socket(params: ClientConfig, emitter: NodeJS.EventEmitter): Socket { let listener: net.Server; @@ -25,8 +25,8 @@ export function ipc({ socketTimeout = 30000, path = '/tmp/app.socket-' }: IPCCon function remote(handle: IPCSocket): Remote { return { - host: handle._server._pipeName, - port: handle._handle.fd, + host: handle && handle._server && handle._server._pipeName || null, + port: handle && handle._handle && handle._handle.fd || null, }; } diff --git a/packages/ipc/tests/unit/ipc.spec.ts b/packages/ipc/tests/unit/ipc.spec.ts index 392b854..b543f77 100644 --- a/packages/ipc/tests/unit/ipc.spec.ts +++ b/packages/ipc/tests/unit/ipc.spec.ts @@ -1,5 +1,40 @@ +import { EventEmitter } from 'events'; import * as ipc from '../../src/ipc'; describe('IPC transport', () => { - it('TODO', () => { expect(ipc).not.toBeUndefined(); }); + it('basic setup', () => { + expect(typeof ipc.default).toBe('function'); + const transport = ipc.default(); + expect(typeof transport).toBe('function'); + const socket = transport({}, new EventEmitter()); + + expect(socket).toHaveProperty('bind', expect.any(Function)); + expect(socket).toHaveProperty('connect', expect.any(Function)); + expect(socket).toHaveProperty('disconnect', expect.any(Function)); + expect(socket).toHaveProperty('remote', expect.any(Function)); + expect(socket).toHaveProperty('stop', expect.any(Function)); + expect(socket).toHaveProperty('send', expect.any(Function)); + }); + + describe('Given an empty handle reference and no configs', () => { + const transport = ipc.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return null values', () => { + expect(socket.remote()).toEqual({ host: null, port: null }); + }); + }); + }); + + describe('Given a handle reference and no configs', () => { + const transport = ipc.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return handle\'s values', () => { + expect(socket.remote({ _server: { _pipeName: '/foo' }, _handle: { fd: 12345 } })).toEqual({ host: '/foo', port: 12345 }); + }); + }); + }); }); diff --git a/packages/kalm/README.md b/packages/kalm/README.md index 88d9191..6eb67ed 100644 --- a/packages/kalm/README.md +++ b/packages/kalm/README.md @@ -47,12 +47,20 @@ Install the transport layer ('tcp' for example) const kalm = require('kalm'); const ws = require('@kalm/ws'); -const Server = kalm.listen({ +const server = kalm.listen({ port: 8800, transport: ws(), routine: kalm.routines.tick({ hz: 5 }), // Sends packets at a frequency of 5 Hz (200ms) host: '0.0.0.0', }); + +server.on('connection', (client) => { + client.subscribe('my-channel', (body, frame) => { + // Handle messages here + }); + + server.broadcast('my-other-channel', 'some message'); +}); ``` **Client** @@ -61,12 +69,21 @@ const Server = kalm.listen({ const kalm = require('kalm'); const ws = require('@kalm/ws'); -const Client = kalm.connect({ +const client = kalm.connect({ host: '0.0.0.0', port: 8800, transport: ws(), routine: kalm.routines.realtime(), }); + +client.on('connect', () => { + client.subscribe('my-other-channel', (body, frame) => { + // Handle messages here + }); + + client.write('my-channel', 'hello world'); +}); + ``` To see working implementations, check out our [examples](https://github.com/kalm/kalm.js/tree/master/examples) folder. diff --git a/packages/kalm/package.json b/packages/kalm/package.json index ad4432a..7088706 100644 --- a/packages/kalm/package.json +++ b/packages/kalm/package.json @@ -5,7 +5,9 @@ "main": "bin/kalm.js", "scripts": { "build": "../../scripts/build.sh kalm", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,28 +18,17 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", "ipc", "tcp", "udp", - "ws", - "core" + "websocket", + "webrtc", + "peer" ], "files": [ "bin", @@ -53,7 +44,14 @@ "contributors": [ "frederic charette " ], - "devDependencies": { - "webpack-cli": "^3.3.10" + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } diff --git a/packages/kalm/src/components/client.ts b/packages/kalm/src/components/client.ts index e8ab5e5..37de64c 100644 --- a/packages/kalm/src/components/client.ts +++ b/packages/kalm/src/components/client.ts @@ -2,7 +2,7 @@ import { EventEmitter } from 'events'; import { log } from '../utils/logger'; -import { serialize, deserialize } from '../utils/parser'; +import { serializeLegacy, deserializeLegacy, indiceBuffer } from '../utils/parser'; /* Methods -------------------------------------------------------------------*/ @@ -11,17 +11,30 @@ export function Client(params: ClientConfig, emitter: NodeJS.EventEmitter, handl const channels: ChannelList = {}; const socket: Socket = params.transport(params, emitter); + if (!socket.connect) { + throw new Error('Transport is not valid, it may not have been invoked, see: https://github.com/kalm/kalm.js#documentation'); + } + function _createChannel(channel: string): Channel { const channelEmitter: NodeJS.EventEmitter = new EventEmitter(); return { + name: channel, emitter: channelEmitter, queue: params.routine(channel, params, channelEmitter, emitter), + channelBuffer: Buffer.concat([indiceBuffer(channel.length), Buffer.from(channel)]), }; } function _wrap(event: RawFrame): void { - const payload: number[] = serialize(event.frameId, event.channel, event.packets); + const payload: Buffer = params.framing === 'kalm' + ? serializeLegacy(event.frameId, channels[event.channel], event.packets) + : Buffer.from(JSON.stringify({ + frameId: event.frameId, + channel: event.channel, + packets: event.packets.map(packet => packet.toString()), + })); + socket.send(handle, payload); } @@ -35,8 +48,16 @@ export function Client(params: ClientConfig, emitter: NodeJS.EventEmitter, handl function _handlePackets(frame: RawFrame, packet: Buffer, index: number): Promise { if (packet.length === 0) return; - const decodedPacket = (params.json === true) ? JSON.parse(packet.toString()) : packet; - if (channels[frame.channel]) { + + let decodedPacket; + + try { + decodedPacket = (params.json === true) ? JSON.parse(packet.toString()) : packet; + } catch (e) { + emitter.emit('error', `Error decoding packet: ${e}`); + } + + if (decodedPacket && channels[frame.channel]) { channels[frame.channel].emitter.emit( 'message', decodedPacket, @@ -68,9 +89,14 @@ export function Client(params: ClientConfig, emitter: NodeJS.EventEmitter, handl } function _handleRequest(payload: Buffer): void { - const frame: RawFrame = deserialize(payload); - emitter.emit('frame', frame); - frame.packets.forEach((packet, i) => _handlePackets(frame, packet, i)); + let frame: RawFrame; + try { + frame = params.framing === 'kalm' ? deserializeLegacy(payload) : JSON.parse(payload.toString()); + } catch (e) { + emitter.emit(`Error decoding frame: ${e}`); + } + emitter.emit('frame', frame || payload.toString()); + if (frame && frame.packets) frame.packets.forEach((packet, i) => _handlePackets(frame, Buffer.from(packet), i)); } function _handleDisconnect() { @@ -79,6 +105,9 @@ export function Client(params: ClientConfig, emitter: NodeJS.EventEmitter, handl } function write(channel: string, message: Serializable): void { + if (params.json !== true && !Buffer.isBuffer(message)) { + throw new Error(`Unable to serialize message: ${message}, expected type Buffer`); + } return _resolveChannel(channel) .queue.add(params.json === true ? Buffer.from(JSON.stringify(message)) : message as Buffer); } diff --git a/packages/kalm/src/components/provider.ts b/packages/kalm/src/components/provider.ts index bcc9107..9df3683 100644 --- a/packages/kalm/src/components/provider.ts +++ b/packages/kalm/src/components/provider.ts @@ -10,6 +10,10 @@ export function Provider(params: ClientConfig, emitter: NodeJS.EventEmitter): Pr const connections = []; const socket: Socket = params.transport(params, emitter); + if (!socket.bind) { + throw new Error('Transport is not valid, it may not have been invoked, see: https://github.com/kalm/kalm.js#documentation'); + } + function broadcast(channel: string, payload: Serializable): void { connections.forEach(c => c.write(channel, payload)); } diff --git a/packages/kalm/src/kalm.ts b/packages/kalm/src/kalm.ts index 5af994f..d29c73a 100644 --- a/packages/kalm/src/kalm.ts +++ b/packages/kalm/src/kalm.ts @@ -10,12 +10,13 @@ import { tick } from './routines/tick'; /* Local variables -----------------------------------------------------------*/ -const defaults = { +const defaults: ProviderConfig = { host: '0.0.0.0', json: true, port: 3000, routine: realtime(), transport: null, + framing: 'kalm', }; /* Methods -------------------------------------------------------------------*/ @@ -27,6 +28,20 @@ function validateOptions(options: ProviderConfig): void { throw new Error(`Unable to create Kalm client, missing "transport" parameter. You may need to install one. ex: @kalm/tcp`); } + + if (typeof options.transport !== 'function') { + throw new Error(`Transport is not a function (${options.transport}), see: https://github.com/kalm/kalm.js#documentation`); + } + + if (options.routine) { + if (typeof options.transport !== 'function') { + throw new Error(`Routine is not a function (${options.routine}), see: https://github.com/kalm/kalm.js#documentation`); + } + const testChannel = options.routine('test', {}, {}, {}); + if (!testChannel.add) { + throw new Error('Routine is not valid, it may not have been invoked, see: https://github.com/kalm/kalm.js#documentation'); + } + } } export function listen(options: ProviderConfig): Provider { diff --git a/packages/kalm/src/routines/dynamic.ts b/packages/kalm/src/routines/dynamic.ts index 98d804b..66fd98d 100644 --- a/packages/kalm/src/routines/dynamic.ts +++ b/packages/kalm/src/routines/dynamic.ts @@ -1,6 +1,10 @@ /* Methods -------------------------------------------------------------------*/ -export function dynamic({ hz, maxPackets = Infinity }: { hz: number, maxPackets?: number }): KalmRoutine { +export function dynamic({ + hz, + maxPackets = Infinity, + maxBytes = 60000, +}: { hz: number, maxPackets?: number, maxBytes?: number }): KalmRoutine { if (hz <= 0 || hz > 1000) { throw new Error(`Unable to set Hertz value of ${hz}. Must be between 0.1e13 and 1000`); } @@ -8,6 +12,7 @@ export function dynamic({ hz, maxPackets = Infinity }: { hz: number, maxPackets? return function queue(channel: string, params: object, channelEmitter: NodeJS.EventEmitter, clientEmitter: NodeJS.EventEmitter): Queue { let timer: NodeJS.Timer = null; const packets: Buffer[] = []; + let totalBytes = 0; let i: number = 0; function _step(): void { @@ -16,21 +21,38 @@ export function dynamic({ hz, maxPackets = Infinity }: { hz: number, maxPackets? channelEmitter.emit('runQueue', { frameId: i++, channel, packets }); if (i > 255) i = 0; packets.length = 0; + totalBytes = 0; clientEmitter.emit(`${channel}.queueRun`, { frameId: i, packets: packets.length }); } - function add(packet: Buffer): void { + function _add(packet: Buffer) { + packets.push(packet); + totalBytes += packet.length; + clientEmitter.emit(`${channel}.queueAdd`, { frameId: i, packet: packets.length }); + } + + function add(packet: Buffer) { + if (packet.length > maxBytes) { + throw new Error(`Cannot send packet of size ${packet.length} while maximum bytes per frame is ${maxBytes}`); + } + + if (packet.length + totalBytes >= maxBytes) { + _step(); + _add(packet); + return; + } + if (packets.length >= maxPackets - 1) { - packets.push(packet); + _add(packet); _step(); - clientEmitter.emit(`${channel}.queueAdd`, { frameId: i, packet: packets.length }); return; } + if (timer === null) { timer = setTimeout(_step, Math.round(1000 / hz)); } - packets.push(packet); - clientEmitter.emit(`${channel}.queueAdd`, { frameId: i, packet: packets.length }); + + _add(packet); } function size(): number { return packets.length; } diff --git a/packages/kalm/src/utils/parser.ts b/packages/kalm/src/utils/parser.ts index f180052..3c1577f 100644 --- a/packages/kalm/src/utils/parser.ts +++ b/packages/kalm/src/utils/parser.ts @@ -1,32 +1,46 @@ +/* Local variables -----------------------------------------------------------*/ + +const singleIndiceCache = {}; +const doubleIndiceCache = {}; + /* Methods -------------------------------------------------------------------*/ -function _uint16Size(value: number): number[] { - return [value >>> 8, value & 0xff]; +export function indiceBuffer(num): Buffer { + if (singleIndiceCache[`${num}`]) return singleIndiceCache[`${num}`]; + const buf = Buffer.allocUnsafe(1); + buf.writeUInt8(num, 0); + singleIndiceCache[`${num}`] = buf; + return buf; +} + +export function doubleIndiceBuffer(num): Buffer { + if (doubleIndiceCache[`${num}`]) return doubleIndiceCache[`${num}`]; + const buf = Buffer.allocUnsafe(2); + buf.writeUInt16BE(num, 0); + doubleIndiceCache[`${num}`] = buf; + return buf; } function _numericSize(bytes: Buffer, index: number): number { return (bytes[index] << 8) | bytes[index + 1]; } -export function serialize(frameId: number, channel: string, packets: Buffer[]): number[] { - const channelLen: number = channel.length; - const result: number[] = [frameId % 255, channelLen]; +export function serializeLegacy(frameId: number, channel: Channel, packets: Buffer[]): Buffer { + const serializedPackets = packets.reduce((acc, curr) => { + acc.push(doubleIndiceBuffer(curr.length)); + acc.push(curr); + return acc; + }, []); - for (let letter = 0; letter < channelLen; letter++) { - result.push(channel.charCodeAt(letter)); - } - - result.push(..._uint16Size(packets.length)); - - packets.forEach((packet: Buffer) => { - if (!(packet instanceof Buffer)) throw new Error(`Cannot send packet ${packet}. Must be of type Buffer`); - result.push(..._uint16Size(packet.length), ...packet); - }); - - return result; + return Buffer.concat([ + indiceBuffer(frameId % 255), + channel.channelBuffer, + doubleIndiceBuffer(packets.length), + ...serializedPackets, + ]); } -export function deserialize(payload: Buffer): RawFrame { +export function deserializeLegacy(payload: Buffer): RawFrame { const channelLength = payload[1]; let caret = 4 + channelLength; const totalPackets = _numericSize(payload, 2 + channelLength); @@ -34,7 +48,7 @@ export function deserialize(payload: Buffer): RawFrame { function _parseFramePacket(): Buffer[] { const packets: Buffer[] = []; for (let p = 0; p < totalPackets; p++) { - if (caret >= payload.length) continue; + if (caret >= payload.length) break; const packetLength = _numericSize(payload, caret); packets.push(payload.slice(2 + caret, 2 + packetLength + caret)); caret = 2 + caret + packetLength; diff --git a/packages/kalm/types.d.ts b/packages/kalm/types.d.ts index 936af4a..59d8983 100644 --- a/packages/kalm/types.d.ts +++ b/packages/kalm/types.d.ts @@ -8,6 +8,7 @@ declare module 'kalm' { host?: string isServer?: boolean provider?: any + framing?: 'kalm' } interface ProviderConfig { @@ -17,6 +18,7 @@ declare module 'kalm' { transport?: KalmTransport port?: number host?: string + framing?: 'kalm' } type Remote = { @@ -134,7 +136,7 @@ declare module 'kalm' { export const connect: (config: ClientConfig) => Client; export const routines: { tick: (config: { hz: number, seed?: number }) => KalmRoutine - dynamic: (config: { hz: number, maxPackets?: number }) => KalmRoutine + dynamic: (config: { hz: number, maxPackets?: number, maxBytes?: number }) => KalmRoutine realtime: () => KalmRoutine }; } diff --git a/packages/tcp/README.md b/packages/tcp/README.md index bc51a34..269fb35 100644 --- a/packages/tcp/README.md +++ b/packages/tcp/README.md @@ -1,4 +1,21 @@ -# Kalm TCP transport +

+ + Kalm +
+
+ Kalm +

+

+ The Socket Optimizer +

+

+
+ +[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/@kalm/tcp) +[![Build Status](https://github.com/kalm/kalm.js/workflows/master-status/badge.svg)](https://github.com/kalm/kalm.js/actions?query=workflow%3A+master-status) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/kalm/kalm.js) +[![Financial Contributors on Open Collective](https://opencollective.com/kalm/all/badge.svg?label=financial+contributors)](https://opencollective.com/kalm) +[![Join the chat at https://gitter.im/KALM/home](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KALM/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Installing @@ -8,7 +25,7 @@ ``` { - socketTimeout = 30000 + socketTimeout: 30000 } ``` diff --git a/packages/tcp/package.json b/packages/tcp/package.json index b589416..3c4cb9c 100644 --- a/packages/tcp/package.json +++ b/packages/tcp/package.json @@ -5,7 +5,9 @@ "main": "bin/tcp.js", "scripts": { "build": "../../scripts/build.sh tcp", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,23 +18,11 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", "tcp" ], "files": ["bin", "types.d.ts"], @@ -48,5 +38,15 @@ ], "browser": { "net": false + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } \ No newline at end of file diff --git a/packages/tcp/src/tcp.ts b/packages/tcp/src/tcp.ts index b39e1ad..549a75d 100644 --- a/packages/tcp/src/tcp.ts +++ b/packages/tcp/src/tcp.ts @@ -4,7 +4,7 @@ import net from 'net'; /* Methods -------------------------------------------------------------------*/ -export function tcp({ socketTimeout = 30000 }: TCPConfig = {}): KalmTransport { +function tcp({ socketTimeout = 30000 }: TCPConfig = {}): KalmTransport { return function socket(params: ClientConfig, emitter: NodeJS.EventEmitter): Socket { let listener: net.Server; @@ -16,8 +16,8 @@ export function tcp({ socketTimeout = 30000 }: TCPConfig = {}): KalmTransport { function remote(handle: net.Socket): Remote { return { - host: handle.remoteAddress, - port: handle.remotePort, + host: handle && handle.remoteAddress || null, + port: handle && handle.remotePort || null, }; } diff --git a/packages/tcp/tests/unit/tcp.spec.ts b/packages/tcp/tests/unit/tcp.spec.ts index b024b76..d17e732 100644 --- a/packages/tcp/tests/unit/tcp.spec.ts +++ b/packages/tcp/tests/unit/tcp.spec.ts @@ -1,5 +1,40 @@ +import { EventEmitter } from 'events'; import * as tcp from '../../src/tcp'; describe('TCP transport', () => { - it('TODO', () => { expect(tcp).not.toBeUndefined(); }); + it('basic setup', () => { + expect(typeof tcp.default).toBe('function'); + const transport = tcp.default(); + expect(typeof transport).toBe('function'); + const socket = transport({}, new EventEmitter()); + + expect(socket).toHaveProperty('bind', expect.any(Function)); + expect(socket).toHaveProperty('connect', expect.any(Function)); + expect(socket).toHaveProperty('disconnect', expect.any(Function)); + expect(socket).toHaveProperty('remote', expect.any(Function)); + expect(socket).toHaveProperty('stop', expect.any(Function)); + expect(socket).toHaveProperty('send', expect.any(Function)); + }); + + describe('Given an empty handle reference and no configs', () => { + const transport = tcp.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return null values', () => { + expect(socket.remote()).toEqual({ host: null, port: null }); + }); + }); + }); + + describe('Given a handle reference and no configs', () => { + const transport = tcp.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return handle\'s values', () => { + expect(socket.remote({ remoteAddress: '127.0.0.1', remotePort: 3000 })).toEqual({ host: '127.0.0.1', port: 3000 }); + }); + }); + }); }); diff --git a/packages/udp/README.md b/packages/udp/README.md index 86e4baa..32155ed 100644 --- a/packages/udp/README.md +++ b/packages/udp/README.md @@ -1,4 +1,21 @@ -# Kalm UDP transport +

+ + Kalm +
+
+ Kalm +

+

+ The Socket Optimizer +

+

+
+ +[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/@kalm/udp) +[![Build Status](https://github.com/kalm/kalm.js/workflows/master-status/badge.svg)](https://github.com/kalm/kalm.js/actions?query=workflow%3A+master-status) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/kalm/kalm.js) +[![Financial Contributors on Open Collective](https://opencollective.com/kalm/all/badge.svg?label=financial+contributors)](https://opencollective.com/kalm) +[![Join the chat at https://gitter.im/KALM/home](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KALM/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Installing @@ -8,11 +25,11 @@ ``` { - type = 'udp4', - localAddr = '0.0.0.0', - reuseAddr = true, - socketTimeout = 30000, - connectTimeout = 1000, + type: 'udp4', + localAddr: '0.0.0.0', + reuseAddr: true, + socketTimeout: 30000, + connectTimeout: 1000, } ``` diff --git a/packages/udp/package.json b/packages/udp/package.json index 9c4b75f..6df222a 100644 --- a/packages/udp/package.json +++ b/packages/udp/package.json @@ -5,7 +5,9 @@ "main": "bin/udp.js", "scripts": { "build": "../../scripts/build.sh udp", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,23 +18,11 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", "udp" ], "files": ["bin", "types.d.ts"], @@ -48,5 +38,15 @@ ], "browser": { "dgram": false + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } \ No newline at end of file diff --git a/packages/udp/src/udp.ts b/packages/udp/src/udp.ts index fa898df..3bd43b6 100644 --- a/packages/udp/src/udp.ts +++ b/packages/udp/src/udp.ts @@ -26,7 +26,7 @@ function udp({ type = 'udp4', localAddr = '0.0.0.0', reuseAddr = true, socketTim } function remote(handle: SocketHandle): Remote { - return handle as Remote; + return handle || { host: null, port: null } as Remote; } function send(handle: UDPSocketHandle, payload: Buffer | number[]): void { diff --git a/packages/udp/tests/unit/udp.spec.ts b/packages/udp/tests/unit/udp.spec.ts index d43e569..8187a0f 100644 --- a/packages/udp/tests/unit/udp.spec.ts +++ b/packages/udp/tests/unit/udp.spec.ts @@ -1,5 +1,40 @@ +import { EventEmitter } from 'events'; import * as udp from '../../src/udp'; describe('UDP transport', () => { - it('TODO', () => { expect(udp).not.toBeUndefined(); }); + it('basic setup', () => { + expect(typeof udp.default).toBe('function'); + const transport = udp.default(); + expect(typeof transport).toBe('function'); + const socket = transport({}, new EventEmitter()); + + expect(socket).toHaveProperty('bind', expect.any(Function)); + expect(socket).toHaveProperty('connect', expect.any(Function)); + expect(socket).toHaveProperty('disconnect', expect.any(Function)); + expect(socket).toHaveProperty('remote', expect.any(Function)); + expect(socket).toHaveProperty('stop', expect.any(Function)); + expect(socket).toHaveProperty('send', expect.any(Function)); + }); + + describe('Given an empty handle reference and no configs', () => { + const transport = udp.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return null values', () => { + expect(socket.remote()).toEqual({ host: null, port: null }); + }); + }); + }); + + describe('Given a handle reference and no configs', () => { + const transport = udp.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return handle\'s values', () => { + expect(socket.remote({ host: '127.0.0.1', port: 3000 })).toEqual({ host: '127.0.0.1', port: 3000 }); + }); + }); + }); }); diff --git a/packages/webrtc/README.md b/packages/webrtc/README.md index 84631ab..6a799a2 100644 --- a/packages/webrtc/README.md +++ b/packages/webrtc/README.md @@ -1,4 +1,21 @@ -# Kalm Webrtc data channel transport +

+ + Kalm +
+
+ Kalm +

+

+ The Socket Optimizer +

+

+
+ +[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/@kalm/webrtc) +[![Build Status](https://github.com/kalm/kalm.js/workflows/master-status/badge.svg)](https://github.com/kalm/kalm.js/actions?query=workflow%3A+master-status) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/kalm/kalm.js) +[![Financial Contributors on Open Collective](https://opencollective.com/kalm/all/badge.svg?label=financial+contributors)](https://opencollective.com/kalm) +[![Join the chat at https://gitter.im/KALM/home](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KALM/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Installing diff --git a/packages/webrtc/package.json b/packages/webrtc/package.json index 5910a0d..703ea13 100644 --- a/packages/webrtc/package.json +++ b/packages/webrtc/package.json @@ -5,7 +5,9 @@ "main": "bin/webrtc.js", "scripts": { "build": "../../scripts/build.sh webrtc", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,24 +18,12 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", - "ws" + "webrtc" ], "files": ["bin", "types.d.ts"], "typings": "./types.d.ts", @@ -48,6 +38,16 @@ ], "dependencies": { "simple-peer": "^9.6.0" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } \ No newline at end of file diff --git a/packages/webrtc/src/webrtc.ts b/packages/webrtc/src/webrtc.ts index d66c636..d9468ff 100644 --- a/packages/webrtc/src/webrtc.ts +++ b/packages/webrtc/src/webrtc.ts @@ -2,7 +2,8 @@ import Peer from 'simple-peer'; -if (!Peer.WEBRTC_SUPPORT) throw new Error('Unsupported environement for WebRTC'); +const isNode = (typeof process !== 'undefined'); +if (!Peer.WEBRTC_SUPPORT && !(isNode && process.env.JEST_WORKER_ID)) throw new Error('Unsupported environement for WebRTC'); /* Methods -------------------------------------------------------------------*/ @@ -64,10 +65,7 @@ function webrtc(config: WebRTCConfig = {}): KalmTransport { } function remote(handle: any): Remote { - return { - host: handle, - port: handle || 0, - }; + return handle || { host: null, port: null }; } function disconnect(handle) { diff --git a/packages/webrtc/tests/unit/webrtc.spec.ts b/packages/webrtc/tests/unit/webrtc.spec.ts new file mode 100644 index 0000000..ec609e4 --- /dev/null +++ b/packages/webrtc/tests/unit/webrtc.spec.ts @@ -0,0 +1,41 @@ +import { EventEmitter } from 'events'; +import * as webrtc from '../../src/webrtc'; + +describe('webrtc transport', () => { + it('basic setup', () => { + expect(typeof webrtc.default).toBe('function'); + const transport = webrtc.default(); + expect(typeof transport).toBe('function'); + const socket = transport({}, new EventEmitter()); + + expect(socket).toHaveProperty('bind', expect.any(Function)); + expect(socket).toHaveProperty('connect', expect.any(Function)); + expect(socket).toHaveProperty('disconnect', expect.any(Function)); + expect(socket).toHaveProperty('remote', expect.any(Function)); + expect(socket).toHaveProperty('stop', expect.any(Function)); + expect(socket).toHaveProperty('send', expect.any(Function)); + expect(socket).toHaveProperty('negociate', expect.any(Function)); + }); + + describe('Given an empty handle reference and no configs', () => { + const transport = webrtc.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return null values', () => { + expect(socket.remote()).toEqual({ host: null, port: null }); + }); + }); + }); + + describe('Given a handle reference and no configs', () => { + const transport = webrtc.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return handle\'s values', () => { + expect(socket.remote({ host: '127.0.0.1', port: 3000 })).toEqual({ host: '127.0.0.1', port: 3000 }); + }); + }); + }); +}); diff --git a/packages/ws/README.md b/packages/ws/README.md index 613a038..fa86670 100644 --- a/packages/ws/README.md +++ b/packages/ws/README.md @@ -1,4 +1,21 @@ -# Kalm Websocket transport +

+ + Kalm +
+
+ Kalm +

+

+ The Socket Optimizer +

+

+
+ +[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/@kalm/ws) +[![Build Status](https://github.com/kalm/kalm.js/workflows/master-status/badge.svg)](https://github.com/kalm/kalm.js/actions?query=workflow%3A+master-status) +![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/kalm/kalm.js) +[![Financial Contributors on Open Collective](https://opencollective.com/kalm/all/badge.svg?label=financial+contributors)](https://opencollective.com/kalm) +[![Join the chat at https://gitter.im/KALM/home](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/KALM/?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## Installing @@ -8,9 +25,9 @@ ``` { - cert = null, - key = null, - secure = false + cert: null, + key: null, + secure: false } ``` diff --git a/packages/ws/package.json b/packages/ws/package.json index 7d8fe87..5488c9e 100644 --- a/packages/ws/package.json +++ b/packages/ws/package.json @@ -5,7 +5,9 @@ "main": "bin/ws.js", "scripts": { "build": "../../scripts/build.sh ws", - "clean": "../../scripts/cleanup.sh" + "clean": "../../scripts/cleanup.sh", + "test": "jest ./tests", + "prepublish": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md" }, "funding": { "type": "Open Collective", @@ -16,24 +18,12 @@ "url": "git+https://github.com/kalm/kalm-js.git" }, "keywords": [ - "multiplex", + "framework", "network", - "optimize", + "realtime", "socket", - "websocket", - "client", - "server", - "service", - "peer", - "micro", - "latency", - "messaging", - "queue", "nagle", - "buffer", - "protocol", - "web", - "ws" + "websocket" ], "files": ["bin", "types.d.ts"], "typings": "./types.d.ts", @@ -52,5 +42,15 @@ "browser": { "http": false, "https": false + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "globals": { + "ts-jest": { + "diagnostics": false, + "isolatedModules": true + } + } } } diff --git a/packages/ws/src/ws.ts b/packages/ws/src/ws.ts index 8322360..39e8db1 100644 --- a/packages/ws/src/ws.ts +++ b/packages/ws/src/ws.ts @@ -48,13 +48,13 @@ function ws({ cert, key, secure }: WSConfig = {}): KalmTransport { } function remote(handle: WebSocket & { headers: any, connection: any }): Remote { - const h = handle.headers; + const h = handle && handle.headers || {}; return { host: ( (h && h['x-forwarded-for'] && h['x-forwarded-for'].split(',')[0]) - || (handle.connection && handle.connection.remoteAddress || '0.0.0.0') + || (handle && handle.connection && handle.connection.remoteAddress || null) ), - port: handle.connection && handle.connection.remotePort || 0, + port: handle && handle.connection && handle.connection.remotePort || null, }; } diff --git a/packages/ws/tests/unit/ws.spec.ts b/packages/ws/tests/unit/ws.spec.ts index 6923313..fdd70b4 100644 --- a/packages/ws/tests/unit/ws.spec.ts +++ b/packages/ws/tests/unit/ws.spec.ts @@ -1,5 +1,47 @@ +import { EventEmitter } from 'events'; import * as ws from '../../src/ws'; -describe('WS transport', () => { - it('TODO', () => { expect(ws).not.toBeUndefined(); }); +describe('ws transport', () => { + it('basic setup', () => { + expect(typeof ws.default).toBe('function'); + const transport = ws.default(); + expect(typeof transport).toBe('function'); + const socket = transport({}, new EventEmitter()); + + expect(socket).toHaveProperty('bind', expect.any(Function)); + expect(socket).toHaveProperty('connect', expect.any(Function)); + expect(socket).toHaveProperty('disconnect', expect.any(Function)); + expect(socket).toHaveProperty('remote', expect.any(Function)); + expect(socket).toHaveProperty('stop', expect.any(Function)); + expect(socket).toHaveProperty('send', expect.any(Function)); + }); + + describe('Given an empty handle reference and no configs', () => { + const transport = ws.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return null values', () => { + expect(socket.remote()).toEqual({ host: null, port: null }); + }); + }); + }); + + describe('Given a handle reference and no configs', () => { + const transport = ws.default(); + const socket = transport({}, new EventEmitter()); + + describe('when fetching remote', () => { + it('should return handle\'s values from headers', () => { + expect(socket.remote({ + headers: { 'x-forwarded-for': '127.0.0.1' }, + connection: { remotePort: 3000 }, + })).toEqual({ host: '127.0.0.1', port: 3000 }); + }); + + it('should return handle\'s values from connection', () => { + expect(socket.remote({ connection: { remoteAddress: '127.0.0.1', remotePort: 3000 } })).toEqual({ host: '127.0.0.1', port: 3000 }); + }); + }); + }); }); diff --git a/scripts/benchmarks/index.js b/scripts/benchmarks/index.js index 033bdca..c10421a 100644 --- a/scripts/benchmarks/index.js +++ b/scripts/benchmarks/index.js @@ -98,6 +98,8 @@ adpts.forEach((i) => { tests.push(_postResults); +console.log(`Launching benchmarks for ${settings.testDuration/1000} second(s) -- MAKE SURE THAT YOU BUILD THE CODE FIRST --`) + tests.reduce( (c, n) => c.then((resolve) => new Promise(n).then(resolve, _errorHandler), _errorHandler), Promise.resolve(), diff --git a/scripts/benchmarks/settings.js b/scripts/benchmarks/settings.js index 9866ea7..c82cbbd 100644 --- a/scripts/benchmarks/settings.js +++ b/scripts/benchmarks/settings.js @@ -5,4 +5,5 @@ module.exports = { testDuration: 1000 * 10, testPayload: { foo: 'bar' }, testChannel: 'test', + framing: null, }; diff --git a/scripts/benchmarks/transports/kalm.js b/scripts/benchmarks/transports/kalm.js index 6b31008..48e6e2d 100644 --- a/scripts/benchmarks/transports/kalm.js +++ b/scripts/benchmarks/transports/kalm.js @@ -29,6 +29,7 @@ function setup(resolve) { server = Kalm.listen({ port: settings.port, json: true, + framing: settings.framing, transport: transports[settings.transport](), routine: Kalm.routines[settings.routine[0]](settings.routine[1]), }); @@ -37,6 +38,10 @@ function setup(resolve) { c.subscribe(settings.testChannel, (msg) => c.write(settings.testChannel, msg)); }); + server.on('error', (e) => { + console.error('Server error:', e); + }); + handbreak = false; setTimeout(resolve, 0); } @@ -59,10 +64,15 @@ function step(resolve) { client = Kalm.connect({ port: settings.port, json: true, + framing: settings.framing, transport: transports[settings.transport](), routine: Kalm.routines.realtime(), }); client.subscribe(settings.testChannel, () => count++); + + client.on('error', (e) => { + console.error('Client error:', e); + }); } client.write(settings.testChannel, settings.testPayload); diff --git a/scripts/build.sh b/scripts/build.sh index b99569d..4de4644 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -3,7 +3,7 @@ echo "Building" $1 ../../scripts/cleanup.sh cp ../../tsconfig.json ./tsconfig.json -../../node_modules/typescript/bin/tsc --outDir ./bin +../../node_modules/typescript/bin/tsc --outDir ./bin >/dev/null echo "Build completed, cleaning up" rm -rf ./tsconfig.json rm -rf ./dist \ No newline at end of file diff --git a/tests/integration/index.spec.ts b/tests/integration/index.spec.ts index a8fc485..a88840d 100644 --- a/tests/integration/index.spec.ts +++ b/tests/integration/index.spec.ts @@ -41,8 +41,33 @@ describe('Integration tests', () => { done(); }); }); + server.on('error', e => { + throw new Error(e); + }); const client = connect({ transport: soc }); + client.on('error', e => { + throw new Error(e); + }); + client.write('test', payload); + }); + + it(`should handle foreign characters with ${transport}`, done => { + const payload = { foo: '한자' }; + server.on('connection', c => { + c.subscribe('test', data => { + expect(data).toEqual(payload); + done(); + }); + }); + server.on('error', e => { + throw new Error(e); + }); + + const client = connect({ transport: soc }); + client.on('error', e => { + throw new Error(e); + }); client.write('test', payload); }); @@ -58,8 +83,14 @@ describe('Integration tests', () => { done(); }); }); + server.on('error', e => { + throw new Error(e); + }); const client = connect({ transport: soc }); + client.on('error', e => { + throw new Error(e); + }); client.write('test.large', largePayload); }); @@ -74,8 +105,14 @@ describe('Integration tests', () => { c.unsubscribe('test'); }); + server.on('error', e => { + throw new Error(e); + }); const client = connect({ transport: soc }); + client.on('error', e => { + throw new Error(e); + }); setTimeout(() => client.write('test', payload), 100); setTimeout(() => done(), 200); }); diff --git a/types.d.ts b/types.d.ts index 10ba88f..5b77086 100644 --- a/types.d.ts +++ b/types.d.ts @@ -9,6 +9,7 @@ interface ClientConfig { host?: string isServer?: boolean provider?: any + framing?: 'kalm' } interface ProviderConfig { @@ -18,6 +19,7 @@ interface ProviderConfig { transport?: KalmTransport port?: number host?: string + framing?: 'kalm' } type Remote = { @@ -42,8 +44,10 @@ interface Client extends NodeJS.EventEmitter { } type Channel = { + name: string queue: Queue emitter: NodeJS.EventEmitter + channelBuffer: Buffer } type ChannelList = { @@ -149,7 +153,7 @@ declare module 'kalm' { export const connect: (config: ClientConfig) => Client; export const routines: { tick: (config: { hz: number, seed?: number }) => KalmRoutine - dynamic: (config: { hz: number, maxPackets?: number }) => KalmRoutine + dynamic: (config: { hz: number, maxPackets?: number, maxBytes?: number }) => KalmRoutine realtime: () => KalmRoutine }; }