diff --git a/.travis.yml b/.travis.yml index be22de7..76d0fe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: node_js node_js: - - "9" \ No newline at end of file + - "9" +before_install: + - npm install uws @types/uws \ No newline at end of file diff --git a/package.json b/package.json index 20f3fbc..72439c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@onixjs/core", - "version": "1.0.0-alpha.25", + "version": "1.0.0-alpha.27", "description": "An Enterprise Grade NodeJS Platform that implements Industry Standards and Patterns in order to provide Connectivity, Stability, High-Availability and High-Performance.", "main": "dist/src/index.js", "scripts": { @@ -52,8 +52,7 @@ "@onixjs/sdk": "^1.0.0-alpha.13.1", "finalhandler": "^1.1.1", "reflect-metadata": "^0.1.12", - "router": "^1.3.2", - "uws": "^9.148.0" + "router": "^1.3.2" }, "devDependencies": { "@types/mongodb": "^3.0.5", @@ -61,6 +60,7 @@ "@types/node": "^9.4.6", "@types/send": "^0.14.4", "@types/uws": "^0.13.2", + "@types/ws": "^5.1.0", "ava": "^0.25.0", "coveralls": "^3.0.0", "dot": "^1.1.2", @@ -72,7 +72,9 @@ "tslint": "^5.9.1", "typedoc": "^0.10.0", "typeorm": "^0.1.12", - "typescript": "^2.6.2" + "typescript": "^2.6.2", + "uws": "^9.148.0", + "ws": "^5.1.1" }, "ava": { "files": [ diff --git a/src/adapters/uws.adapter.ts b/src/adapters/uws.adapter.ts new file mode 100644 index 0000000..2837c44 --- /dev/null +++ b/src/adapters/uws.adapter.ts @@ -0,0 +1,15 @@ +import * as DepWebSocket from 'uws'; +import * as http from 'http'; +import * as https from 'https'; +import {WebSocketAdapter} from '../interfaces'; +/** + * @class UWSAdapter + * @author Jonathan Casarrubias + * @license MIT + * @description This adapter will use the uws dependency + */ +export class UWSAdapter implements WebSocketAdapter { + WebSocket(server: http.Server | https.Server): DepWebSocket.Server { + return new DepWebSocket.Server({server}); + } +} diff --git a/src/adapters/ws.adapter.ts b/src/adapters/ws.adapter.ts new file mode 100644 index 0000000..25673ac --- /dev/null +++ b/src/adapters/ws.adapter.ts @@ -0,0 +1,15 @@ +import * as DepWebSocket from 'ws'; +import * as http from 'http'; +import * as https from 'https'; +import {WebSocketAdapter} from '../interfaces'; +/** + * @class WSAdapter + * @author Jonathan Casarrubias + * @license MIT + * @description This adapter will use the ws dependency + */ +export class WSAdapter implements WebSocketAdapter { + WebSocket(server: http.Server | https.Server): DepWebSocket.Server { + return new DepWebSocket.Server({server}); + } +} diff --git a/src/core/host.boot.ts b/src/core/host.boot.ts index a80d39b..db35de6 100644 --- a/src/core/host.boot.ts +++ b/src/core/host.boot.ts @@ -1,6 +1,7 @@ import {OnixJS, promiseSeries} from '../index'; import * as path from 'path'; import {OnixConfig, BootConfig} from '../interfaces'; +import {WSAdapter} from '../adapters/ws.adapter'; /** * @class HostBoot * @author Jonathan Casarrubias @@ -40,6 +41,7 @@ export class HostBoot { private hc: OnixConfig = { // Default working directory points to ./dist cwd: path.join(process.cwd(), 'dist'), + adapters: {websocket: WSAdapter}, }, ) { // Make sure we got the right configuration before diff --git a/src/core/host.broker.ts b/src/core/host.broker.ts index d4caddc..a0f8e9f 100644 --- a/src/core/host.broker.ts +++ b/src/core/host.broker.ts @@ -1,7 +1,6 @@ import * as http from 'http'; import * as https from 'https'; -import * as WebSocket from 'uws'; -import {IAppOperation, IAppDirectory} from '../interfaces'; +import {IAppOperation, IAppDirectory, WebSocketAdapter} from '../interfaces'; /** * @class HostBroker * @author Jonathan Casarrubias @@ -20,8 +19,12 @@ export class HostBroker { * @description The constructor will create a new websocket server from the * incoming http server created within the OnixJS Host. */ - constructor(server: http.Server | https.Server, private apps: IAppDirectory) { - new WebSocket.Server({server}).on('connection', (ws: WebSocket) => { + constructor( + private server: http.Server | https.Server, + private websocket: WebSocketAdapter, + private apps: IAppDirectory, + ) { + this.websocket.WebSocket(this.server).on('connection', ws => { ws.on('message', (data: string) => this.handle(ws, JSON.parse(data))); }); } diff --git a/src/index.ts b/src/index.ts index 0c4ded3..9c63a72 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import * as finalhandler from 'finalhandler'; import {Utils} from '@onixjs/sdk/dist/utils'; import {HostBroker} from './core/host.broker'; import {promisify} from 'util'; +import {WSAdapter} from './adapters/ws.adapter'; /** * @class OnixJS * @author Jonathan Casarrubias @@ -40,7 +41,7 @@ export class OnixJS { * @description Current Onix Version. */ get version(): string { - return '1.0.0-alpha.25'; + return '1.0.0-alpha.27'; } /** * @property router @@ -65,7 +66,13 @@ export class OnixJS { * @description Internally exposes a given configuration. * It logs to the terminal the current Onix version. */ - constructor(public config: OnixConfig = {cwd: process.cwd(), port: 3000}) { + constructor( + public config: OnixConfig = { + cwd: process.cwd(), + port: 3000, + adapters: {websocket: WSAdapter}, + }, + ) { this.config = Object.assign({cwd: process.cwd(), port: 3000}, config); // Listener for closing process process.on('exit', async () => { @@ -351,7 +358,7 @@ export class OnixJS { * @description This method will start the systemm level server. */ private async startSystemServer() { - return new Promise(resolve => { + return new Promise((resolve, reject) => { // Setup server this.server = this.createServer(); // Verify if there is an SSL Activation File @@ -371,8 +378,10 @@ export class OnixJS { new SchemaProvider(this.router, this._apps); // Listen Server Port this.server.listen(this.config.port); - // Create schema provider route - new HostBroker(this.server, this._apps); + // Create WebSocket Adapter Instance + const adapter = new this.config.adapters.websocket(); + // Create Onix Host Instance + new HostBroker(this.server, adapter, this._apps); // Indicate the ONIX SERVER is now listening on the given port console.log(`ONIXJS HOST LOADED: Listening on port ${this.config.port}`); // Resolve Server diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 9435286..815c4a8 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -1,5 +1,6 @@ import {ChildProcess} from 'child_process'; import * as http from 'http'; +import * as https from 'https'; import {AppNotifier} from '..'; /** * @interface IAppConfig @@ -7,7 +8,15 @@ import {AppNotifier} from '..'; * @description This interface will provida configuration for * a given application. */ -export interface IAppConfig extends OnixConfig { +export interface IAppConfig { + cwd?: string; + // Port if network enabled + port?: number; + // If network enabled, a HTTP server will be created + network?: { + disabled: boolean; + ssl?: ISSlConfig; + }; // Modules to be loaded for this application modules: Constructor[]; } @@ -330,9 +339,16 @@ export interface OnixConfig extends DomainConfig { cwd?: string; // If network enabled, a HTTP server will be created network?: { - disabled: boolean; ssl?: ISSlConfig; }; + // WebSocket Adapter + adapters: { + websocket: new () => WebSocketAdapter; + }; +} + +export interface WebSocketAdapter { + WebSocket(server: http.Server | https.Server); } export interface BootConfig { diff --git a/test/onixjs.acceptance.ts b/test/onixjs.acceptance.ts index 405ec32..4ba7d8b 100644 --- a/test/onixjs.acceptance.ts +++ b/test/onixjs.acceptance.ts @@ -15,15 +15,24 @@ import {IAppConfig} from '../src/interfaces'; import {Utils} from '@onixjs/sdk/dist/utils'; import {OnixClient, AppReference, ComponentReference} from '@onixjs/sdk'; import {NodeJS} from '@onixjs/sdk/dist/adapters/node.adapters'; +import {WSAdapter} from '../src/adapters/ws.adapter'; // Test Onix Version test('Onix version', t => { - const onix: OnixJS = new OnixJS({cwd, port: 8085}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8085, + adapters: {websocket: WSAdapter}, + }); t.is(onix.version, pkg.version); }); //Test Onix App Starter test('Onix app starter', async t => { - const onix: OnixJS = new OnixJS({cwd, port: 8083}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8083, + adapters: {websocket: WSAdapter}, + }); await onix.load('TodoApp@todo.app:disabled'); const results: OperationType.APP_START_RESPONSE[] = await onix.start(); t.deepEqual(results, [ @@ -35,14 +44,18 @@ test('Onix app starter', async t => { //Test Onix App Pinger test('Onix app pinger', async t => { - const onix: OnixJS = new OnixJS({cwd, port: 8084}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8084, + adapters: {websocket: WSAdapter}, + }); await onix.load('TodoApp@todo.app:disabled'); const config: IAppConfig = await onix.ping('TodoApp'); t.true(config.network!.disabled); }); //Test Onix Apps Say Hello test('Onix app greeter', async t => { - const onix: OnixJS = new OnixJS({cwd}); + const onix: OnixJS = new OnixJS({cwd, adapters: {websocket: WSAdapter}}); await onix.load('BobApp@bob.app'); await onix.load('AliceApp@alice.app'); // Bidimentional array, each app call multiple apps, each @@ -56,7 +69,11 @@ test('Onix app greeter', async t => { //Test Onix RPC component methods test('Onix rpc component methods from server', async t => { - const onix: OnixJS = new OnixJS({cwd, port: 8085}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8085, + adapters: {websocket: WSAdapter}, + }); await onix.load('TodoApp@todo.app:disabled'); await onix.start(); const todo: TodoModel = new TodoModel(); @@ -78,7 +95,11 @@ test('Onix rpc component methods from server', async t => { //Test Onix RPC component methods test('Onix rpc component methods from client', async t => { - const onix: OnixJS = new OnixJS({cwd, port: 8086}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8086, + adapters: {websocket: WSAdapter}, + }); await onix.load('TodoApp@todo.app'); await onix.start(); // Websocket should be available now @@ -117,7 +138,11 @@ test('Onix rpc component methods from client', async t => { test('Onix rpc component stream', async t => { const text: string = 'Hello SDK World'; // Host Port 8087 - const onix: OnixJS = new OnixJS({cwd, port: 8087}); + const onix: OnixJS = new OnixJS({ + cwd, + port: 8087, + adapters: {websocket: WSAdapter}, + }); // SOA Service Port 8078 await onix.load('TodoApp@todo.app:8078'); await onix.start(); @@ -148,5 +173,7 @@ test('Onix rpc component stream', async t => { const result = await componentRef.Method('addTodo').call({text}); t.is(result.text, text); } - await onix.stop(); + onix + .stop() + .then(() => console.log('STOPPED'), e => console.log('SOME ERROR', e)); }); diff --git a/test/onixjs.core.unit.ts b/test/onixjs.core.unit.ts index 41a330d..c497f09 100644 --- a/test/onixjs.core.unit.ts +++ b/test/onixjs.core.unit.ts @@ -42,6 +42,7 @@ import {Utils} from '@onixjs/sdk/dist/utils'; import {Mongoose, Schema} from 'mongoose'; import {GroupMatch} from '../src/core/acl.group.match'; import {AllowEveryone} from '../src/core/acl.everyone'; +import {WSAdapter} from '../src/adapters/ws.adapter'; const cwd = path.join(process.cwd(), 'dist', 'test'); // Test AppFactory @@ -76,6 +77,7 @@ test('Core: OnixJS loads creates duplicated Application.', async t => { const onix: OnixJS = new OnixJS({ cwd: path.join(process.cwd(), 'dist', 'test'), port: 8086, + adapters: {websocket: WSAdapter}, }); await onix.load('TodoApp@todo.app:disabled'); const error = await t.throws(onix.load('TodoApp@todo.app:disabled')); @@ -87,6 +89,7 @@ test('Core: OnixJS pings missing Application.', async t => { const onix: OnixJS = new OnixJS({ cwd: path.join(process.cwd(), 'dist', 'test'), port: 9091, + adapters: {websocket: WSAdapter}, }); const error = await t.throws(onix.ping('MissingApp')); t.is( @@ -100,6 +103,7 @@ test('Core: OnixJS fails on coordinating invalid callee.', async t => { const onix: OnixJS = new OnixJS({ cwd: path.join(process.cwd(), 'dist', 'test'), port: 8088, + adapters: {websocket: WSAdapter}, }); const error = await t.throws( onix.coordinate('Dummy.call', {metadata: {}, payload: {}}), @@ -112,6 +116,7 @@ test('Core: OnixJS gets list of apps.', async t => { const onix: OnixJS = new OnixJS({ cwd: path.join(process.cwd(), 'dist', 'test'), port: 8089, + adapters: {websocket: WSAdapter}, }); await onix.load('TodoApp@todo.app:disabled'); const apps = onix.apps(); @@ -539,7 +544,10 @@ test('Core: host boot.', async t => { { apps: ['TodoApp@todo.app:8076'], }, - {cwd}, + { + cwd, + adapters: {websocket: WSAdapter}, + }, ); await t.notThrows(instance.run()); await instance.host.stop(); @@ -553,8 +561,8 @@ test('Core: host boot ssl activation file.', async t => { { cwd, port: 5000, + adapters: {websocket: WSAdapter}, network: { - disabled: false, ssl: { activation: { endpoint: '/.well-known/activation.txt', @@ -583,7 +591,10 @@ test('Core: host boot throws.', async t => { { apps: [], }, - {cwd}, + { + cwd, + adapters: {websocket: WSAdapter}, + }, ); }), );