diff --git a/.gitignore b/.gitignore index fd4f2b0..2fc85d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .DS_Store +.vscode diff --git a/README.md b/README.md index a47a04a..1e9da9e 100644 --- a/README.md +++ b/README.md @@ -42,15 +42,31 @@ conn.on('eventName', data => { console.log('Received event: ', data.eventName, 'with payload: ', data.payload) }) ``` + +**Listener for all events** + +```javascript + +All events will be sent to `message` listener even if there is another listener sent for those events. + +conn.on('message', event => { + console.log("onMessage received event: ",event) + }) +``` + **Send Events** -Only supports sending serialisable objects and strings now. -Binary data support is in progress. ```javascript conn.send('eventName',{x:0,y:0}) ``` +**Send Data** + +```javascript +conn.sendData('eventName',new Uint8Array()) +``` + Client for browser is build on top of WebSocket javascript object. TFPSocketsClient provides access to base socket object via `ws` property and can also be initialised with a pre initialised WebSocket instance using: ```javascript var cleint = new TFPSocketsClient(null, null,initilisedWS) diff --git a/TFPSocketsClient-Browser.js b/TFPSocketsClient-Browser.js index c029bbf..eb818e0 100644 --- a/TFPSocketsClient-Browser.js +++ b/TFPSocketsClient-Browser.js @@ -1,5 +1,24 @@ const isString = s => typeof (s) === 'string' || s instanceof String; +const TFPUtils_packData = (data, eventName) => { + if(eventName.length > 255) { + throw "Event name length should be < 255" + return + } + let enc = new TextEncoder("utf-8"); + eventName = enc.encode(eventName) + let header = new Uint8Array([eventName.length, ...eventName]) + return new Uint8Array([...header,...data]) +} + +const TFPUtils_unpackData = unpacked => { + let headerSize = new Uint8Array(unpacked.slice(0,1))[0] + let header = new Uint8Array(unpacked.slice(1,headerSize+1)) + let data = new Uint8Array(unpacked.slice(headerSize+1)) + let eventName = new TextDecoder('utf-8').decode(header) + return {eventName,payload:data} +} + class TFPSocketsClient { constructor(url, protocols,cutomws = null) { @@ -42,17 +61,18 @@ class TFPSocketsClient { } this.ws.binaryType = "arraybuffer" this.ws.onmessage = (data) => { + var processedEvent; if (isString(data.data)) { - //handle incomming message try { - let obj = JSON.parse(data.data); - this.EventStream.emit(obj.eventName, obj) + processedEvent = JSON.parse(data.data); } catch (e) { console.log("Message doesn't repect protocol with exception: ", e) } } else { - //binary data wip + processedEvent = TFPUtils_unpackData(data.data) } + this.EventStream.emit(processedEvent.eventName, processedEvent) + this.EventStream.emit('message',processedEvent) } } @@ -69,6 +89,14 @@ class TFPSocketsClient { } } + sendData(event,payload) { + if (this.isOpen) { + this.ws.send(TFPUtils_packData(payload,event)) + } else { + console.log("Connection is not opened") + } + } + } if (typeof module !== 'undefined' && module.exports) { diff --git a/example.js b/example.js index a6e9c8c..59b9b2f 100644 --- a/example.js +++ b/example.js @@ -2,6 +2,8 @@ const express = require('express'); const http = require('http'); const url = require('url'); const TFPSockets = require('./index') +const TextEncoder = require('text-encoding').TextEncoder +const TextDecoder = require('text-encoding').TextDecoder const app = express(); @@ -9,12 +11,24 @@ const app = express(); const server = http.createServer(app); +const eventFilter = (event,f) => [event].filter(f); + const TFPServer = new TFPSockets.server(server,["chat"]) TFPServer.on('connection',client => { client.on('testEvent', data => { console.log("test event payload: ", data.payload) client.send('testEventBack',{x:1,y:100}) }) + + client.on('message',event => { + console.log("onMessage received event: ",event) + }) + + client.on('dataEvent', event => { + let text = new TextDecoder('utf-8').decode(event.payload) + console.log("received data event with payload ", text) + }) + }) @@ -22,6 +36,11 @@ const testClient = new TFPSockets.client("ws://localhost:1507",["chat"]) testClient.on('open', event => { console.log("test client open") testClient.send('testEvent',{x:10,y:89}) + testClient.send('event2',{}) + + let data = new TextEncoder('utf-8').encode("Hello world as Uint8Array") + testClient.sendData('dataEvent',data); + }) testClient.on('testEventBack', data => { diff --git a/lib/TFPSockets.js b/lib/TFPSockets.js index 2871eab..be93c2f 100644 --- a/lib/TFPSockets.js +++ b/lib/TFPSockets.js @@ -1,7 +1,28 @@ const WebSocket = require('ws') +const TextEncoder = require('text-encoding').TextEncoder +const TextDecoder = require('text-encoding').TextDecoder const isString = s => typeof (s) === 'string' || s instanceof String; +const TFPUtils_packData = (data, eventName) => { + if(eventName.length > 255) { + throw "Event name length should be < 255" + return + } + let enc = new TextEncoder("utf-8"); + eventName = enc.encode(eventName) + let header = new Uint8Array([eventName.length, ...eventName]) + return new Uint8Array([...header,...data]) +} + +const TFPUtils_unpackData = unpacked => { + let headerSize = new Uint8Array(unpacked.slice(0,1))[0] + let header = new Uint8Array(unpacked.slice(1,headerSize+1)) + let data = new Uint8Array(unpacked.slice(headerSize+1)) + let eventName = new TextDecoder('utf-8').decode(header) + return {eventName,payload:data} +} + class TFPBaseEventStream { constructor() { this.EventStream = (function () { @@ -49,17 +70,18 @@ class TFPSocketsClient extends TFPBaseEventStream { this.EventStream.emit('open',event) }) this.ws.on('message', (data) => { + var processedEvent; if (isString(data)) { - //handle incomming message try { - let obj = JSON.parse(data); - this.EventStream.emit(obj.eventName, obj) + processedEvent = JSON.parse(data); } catch (e) { console.log("Message doesn't repect protocol with exception: ", e) } } else { - //binary data wip + processedEvent = TFPUtils_unpackData(data) } + this.EventStream.emit(processedEvent.eventName, processedEvent) + this.EventStream.emit('message',processedEvent) }) this.ws.on('close', () => this.EventStream.emit('close') ) } @@ -73,6 +95,14 @@ class TFPSocketsClient extends TFPBaseEventStream { } } + sendData(event,payload) { + if (this.isOpen) { + this.ws.send(TFPUtils_packData(payload,event)) + } else { + console.log("Connection is not opened") + } + } + } class TFPSocketsServer extends TFPBaseEventStream { diff --git a/package.json b/package.json index 8a157fd..95180a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tfpsockets", - "version": "0.1.0", + "version": "0.2.0", "description": "Simple event based websockets wrapper", "main": "index.js", "scripts": { @@ -19,6 +19,7 @@ "license": "MIT", "dependencies": { "express": "^4.16.0", + "text-encoding": "^0.6.4", "ws": "^3.2.0" } }