Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/jest/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global.crypto = {
randomUUID: () => 'mocked-uuid',
};
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "reactivexcomponent.js",
"version": "7.0.4",
"version": "7.0.6",
"description": "Javascript reactive client API for XComponent",
"main": "dist/index.js",
"module": "dist/index.js",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
"import": "./dist/index.js",
Expand All @@ -14,6 +14,7 @@
"lib": "./lib"
},
"scripts": {
"build:browser": "rollup -c",
"build": "node scripts/clean.js && tsc",
"watch": "node scripts/clean.js && tsc -w",
"test": "node scripts/test.js --env=jsdom",
Expand Down Expand Up @@ -80,15 +81,16 @@
"@types/xml2js": "0.4.8",
"@types/xmldom": "^0.1.28",
"atob": "^2.0.3",
"log4ts": "^0.4.2",
"pako": "^1.0.3",
"rxjs": "^6.0.0",
"rxjs-compat": "^6",
"uuid": "^7.0.0",
"websocket": "^1.0.25",
"xml2js": "^0.4.17"
"tslib": "^2.8.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-typescript": "^12.1.2",
"clean-webpack-plugin": "^1.0.0",
"compression": "^1.6.2",
"husky": "^6.0.0",
Expand All @@ -98,6 +100,7 @@
"mock-socket": "^9.0.0",
"prettier": "^1.14.0",
"pretty-quick": "^2.0.0",
"rollup": "^4.39.0",
"source-map-loader": "^0.2.0",
"ts-jest": "^25.0.0",
"ts-loader": "^5.0.0",
Expand Down
22 changes: 22 additions & 0 deletions rollup.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const resolve = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('@rollup/plugin-typescript');
const json = require('@rollup/plugin-json');


module.exports = {
input: 'src/index.ts',
output: [
{ file: 'dist/index.js', format: 'esm' },
{ file: 'dist/index.umd.js', format: 'umd', name: 'ReactiveXComponent' }
],
plugins: [
resolve(),
commonjs(),
json(),
typescript({
tsconfig: './tsconfig.json',
tslib: require.resolve('tslib')
})
]
};
108 changes: 47 additions & 61 deletions src/XComponent.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,66 @@
import { WebSocketConnection } from "./communication/WebSocketConnection";
import { Connection } from "./interfaces/Connection";
import { ErrorListener } from "./interfaces/ErrorListener";
import { Logger, LoggerConfig } from "log4ts";
import BasicLayout from "log4ts/build/layouts/BasicLayout";
import ConsoleAppender from "log4ts/build/appenders/ConsoleAppender";
import { LogLevel } from "log4ts/build/LogLevel";
import { WebSocketBridgeCommunication } from "./communication/WebSocketBridgeCommunication";
import { w3cwebsocket as WebSocketLib } from "websocket";
import { WebSocketConnection } from './communication/WebSocketConnection';
import { Connection } from './interfaces/Connection';
import { ErrorListener } from './interfaces/ErrorListener';
import { Logger } from './utils/Logger';
import { WebSocketBridgeCommunication } from './communication/WebSocketBridgeCommunication';

export class XComponent {
private logger: Logger = Logger.getLogger("XComponent");
private loggerconfig: LoggerConfig;
private logger = Logger.getLogger('XComponent');
private initialized: boolean = false;

public connect(serverUrl: string, errorListener?: ErrorListener, heartbeatIntervalSeconds: number = 10): Promise<Connection> {
public connect(
serverUrl: string,
errorListener?: ErrorListener,
heartbeatIntervalSeconds: number = 10
): Promise<Connection> {
this.ensureInitialized();
return new Promise((resolve, reject): void => {
let webSocket;
if (this.isNodeApplication()) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
webSocket = new WebSocketLib(serverUrl);
} else {
webSocket = new WebSocket(serverUrl);
}
let webSocketBridgeCommunication = new WebSocketBridgeCommunication(webSocket);
let connection = new WebSocketConnection(webSocket, webSocketBridgeCommunication);

webSocket.onopen = ((e: Event) => {
connection.closedByUser = false;
webSocketBridgeCommunication.startHeartbeat(heartbeatIntervalSeconds);
this.logger.info("connection started on " + serverUrl + ".");
resolve(connection);
}).bind(this);

webSocket.onerror = ((error: Event) => {
if (errorListener) {
errorListener.onError(new Error(error.toString()));
reject(error);
return new Promise(
(resolve, reject): void => {
let webSocket;
if (this.isNodeApplication()) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
webSocket = new WebSocket(serverUrl);
} else {
webSocket = new WebSocket(serverUrl);
}
this.logger.error("Error on " + serverUrl + ".", error);
}).bind(this);
let webSocketBridgeCommunication = new WebSocketBridgeCommunication(webSocket);
let connection = new WebSocketConnection(webSocket, webSocketBridgeCommunication);

webSocket.onclose = ((closeEvent: CloseEvent) => {
this.logger.info("connection on " + serverUrl + " closed.", closeEvent);
if (!connection.closedByUser && errorListener) {
errorListener.onError(new Error("Unxecpected connection close on " + serverUrl));
reject(closeEvent);
}
webSocketBridgeCommunication.dispose();
connection.dispose();
}).bind(this);
});
}
webSocket.onopen = ((e: Event) => {
connection.closedByUser = false;
webSocketBridgeCommunication.startHeartbeat(heartbeatIntervalSeconds);
this.logger.info('connection started on ' + serverUrl + '.');
resolve(connection);
}).bind(this);

public setLogLevel(logLevel: LogLevel): void {
this.ensureInitialized();
this.loggerconfig.setLevel(logLevel);
}
webSocket.onerror = ((error: Event) => {
if (errorListener) {
errorListener.onError(new Error(error.toString()));
reject(error);
}
this.logger.error('Error on ' + serverUrl + '.', error);
}).bind(this);

public getLogLevel(): LogLevel {
this.ensureInitialized();
return this.loggerconfig.getLevel();
webSocket.onclose = ((closeEvent: CloseEvent) => {
this.logger.info('connection on ' + serverUrl + ' closed.', closeEvent);
if (!connection.closedByUser && errorListener) {
errorListener.onError(new Error('Unxecpected connection close on ' + serverUrl));
reject(closeEvent);
}
webSocketBridgeCommunication.dispose();
connection.dispose();
}).bind(this);
}
);
}

private ensureInitialized() {
if (!this.initialized) {
let consoleAppender = new ConsoleAppender();
consoleAppender.setLayout(new BasicLayout());
this.loggerconfig = new LoggerConfig(consoleAppender, LogLevel.INFO);
Logger.setConfig(this.loggerconfig);
this.initialized = true;
}
}

private isNodeApplication() {
return typeof process === "object" &&
process + "" === "[object process]" && typeof window === "undefined";
return typeof process === 'object' && process + '' === '[object process]' && typeof window === 'undefined';
}
}
}
8 changes: 4 additions & 4 deletions src/communication/WebSocketBridgeCommunication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { filter, first, map, takeWhile } from 'rxjs/operators';
import { Commands } from '../configuration/xcWebSocketBridgeConfiguration';
import { CompositionModel, DeserializedData, Serializer, Deserializer } from './xcomponentMessages';
import 'rxjs/add/observable/fromEvent';
import { Logger } from 'log4ts';
import { Logger } from '../utils/Logger';
import { DefaultApiConfigurationParser } from '../configuration/apiConfigurationParser';
import { ApiConfiguration } from '../configuration/apiConfiguration';

export class WebSocketBridgeCommunication {
private logger: Logger = Logger.getLogger('HeartbeatManager');
private logger = Logger.getLogger('HeartbeatManager');
private updates$: Observable<DeserializedData>;
private deserializer: Deserializer;
private serializer: Serializer;
Expand All @@ -33,7 +33,7 @@ export class WebSocketBridgeCommunication {
this.updates$
.pipe(filter((data: DeserializedData) => data.command === command))
.subscribe((data: DeserializedData) => {
this.logger.trace('Heartbeat received successfully');
this.logger.debug('Heartbeat received successfully');
});
let commandData = {
Command: command,
Expand All @@ -42,7 +42,7 @@ export class WebSocketBridgeCommunication {
let input = thisWebSocketBridgeCommunication.serializer.convertCommandDataToWebsocketInputFormat(commandData);
this.heartbeatTimer = setInterval(() => {
thisWebSocketBridgeCommunication.webSocket.send(input);
this.logger.trace('Heartbeat sent');
this.logger.debug('Heartbeat sent');
}, heartbeatIntervalSeconds * 1000);
}

Expand Down
20 changes: 10 additions & 10 deletions src/communication/WebSocketConnection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { WebSocket, Server } from 'mock-socket';
import { ErrorListener } from '../../src/interfaces/ErrorListener';
import Mock from '../utils/mockSubscriberDependencies';
import pako = require('pako');
import * as uuid from 'uuid/v4';
import { generateUUID } from '../utils/uuid';

const encodeServerMessage = (strData: string) => {
let binaryString = pako.deflate(strData, { to: 'string' });
Expand All @@ -12,7 +12,7 @@ const encodeServerMessage = (strData: string) => {
};

describe('Test Connection module', function() {
let mockServer: Server;
let mockServer: Server | undefined;

beforeEach(function() {
// tslint:disable-next-line:no-any
Expand All @@ -21,12 +21,12 @@ describe('Test Connection module', function() {
(<any>window).isTestEnvironnement = true;
});

afterEach(() => {
afterEach((done) => {
if (mockServer) {
mockServer.stop(() => {
/**/
});
mockServer.close(); // Utiliser close() et non stop()
mockServer = undefined;
}
done(); // Pour Jest : signaler la fin du teardown
});

describe('Test createSession method', function() {
Expand All @@ -41,7 +41,7 @@ describe('Test Connection module', function() {
})
.then(session => {
expect(session).not.toBe(null);
mockServer.stop(done);
mockServer?.stop(done);
})
.catch(err => {
console.log(err);
Expand Down Expand Up @@ -72,7 +72,7 @@ describe('Test Connection module', function() {
connection.createSession(xcApiFileName).catch(error => {
// it refers explicitly to the unknown Api on the error message, not to some random crash
expect(error.message).toMatch(xcApiFileName);
mockServer.stop(done);
mockServer?.stop(done);
});
});

Expand All @@ -90,7 +90,7 @@ describe('Test Connection module', function() {
mockServer = new Server(serverUrl);
const xcApiFileName = 'api.xcApi';
mockServer.on('connection', server => {
mockServer.close(undefined);
mockServer?.close(undefined);
});
new XComponent()
.connect(serverUrl, new FakeErrorHandler(err => done()))
Expand All @@ -114,7 +114,7 @@ describe('Test Connection module', function() {
describe('Test getModel method', function() {
let serverMock: Server, serverUrl: string;
beforeEach(function() {
serverUrl = 'wss://' + uuid();
serverUrl = 'wss://' + generateUUID();
serverMock = new Server(serverUrl);
});

Expand Down
27 changes: 18 additions & 9 deletions src/communication/WebSocketSubscriber.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,31 @@ import { Deserializer } from '../../src/communication/xcomponentMessages';
import Mock from '../utils/mockSubscriberDependencies';
import { EventEmitter } from 'events';
import { PrivateTopics } from '../../src/interfaces/PrivateTopics';
import * as uuid from 'uuid/v4';
import { generateUUID } from '../utils/uuid';
import { verify, instance, mock, anything } from '../../node_modules/ts-mockito/lib/ts-mockito';
import { WebSocketWrapper } from '../../src/communication/WebSocketWrapper';

describe('Test xcWebSocketSubscriber module', function() {
let mockServer: Server | undefined;
beforeEach(function() {
// tslint:disable-next-line:no-any
(<any>window).WebSocket = WebSocket;
// tslint:disable-next-line:no-any
(<any>window).isTestEnvironnement = true;
});


afterEach(() => {
if (mockServer) {
mockServer.close();
mockServer = undefined;
}
});

describe('Test subscribe method', function() {
let subscriber, mockServer: Server, mockWebSocket;
let subscriber, mockWebSocket;
beforeEach(function() {
let serverUrl = 'wss://' + uuid();
let serverUrl = 'wss://' + generateUUID();
mockServer = new Server(serverUrl);
mockWebSocket = new WebSocket(serverUrl);
subscriber = new WebSocketSubscriber(new WebSocketWrapper(mockWebSocket), Mock.configuration);
Expand All @@ -38,14 +47,14 @@ describe('Test xcWebSocketSubscriber module', function() {
expect(data.stateMachineRef.StateName).toEqual(Mock.correctReceivedData.stateMachineRef.StateName);
expect(data.stateMachineRef.send).toEqual(expect.any(Function));
expect(data.jsonMessage).toEqual(Mock.correctReceivedData.jsonMessage);
mockServer.stop(done);
mockServer?.stop(done);
};
// subscribe send a message (subscribe request)
subscriber.subscribe('component', 'stateMachine', { onStateMachineUpdate: stateMachineUpdateListener });
};

// tslint:disable-next-line:no-any
mockServer.on('connection', function(server: any) {
mockServer?.on('connection', function(server: any) {
// when subscribe request is received, we send send jsonData
// tslint:disable-next-line:no-any
server.on('message', function(subscribeRequest: any) {
Expand Down Expand Up @@ -103,9 +112,9 @@ describe('Test xcWebSocketSubscriber module', function() {
});

describe('Test getSnapshot method', function() {
let subscriber, mockServer: Server, mockWebSocket, privateTopics;
let subscriber, mockWebSocket, privateTopics;
beforeEach(function() {
let serverUrl = 'wss://' + uuid();
let serverUrl = 'wss://' + generateUUID();
mockServer = new Server(serverUrl);
mockWebSocket = new WebSocket(serverUrl);
subscriber = new WebSocketSubscriber(new WebSocketWrapper(mockWebSocket), Mock.configuration);
Expand All @@ -117,7 +126,7 @@ describe('Test xcWebSocketSubscriber module', function() {
let deserializer = new Deserializer();

// tslint:disable-next-line:no-any
mockServer.on('connection', function(server: any) {
mockServer?.on('connection', function(server: any) {
let n = -3;
let topic: string = '';

Expand Down Expand Up @@ -164,7 +173,7 @@ describe('Test xcWebSocketSubscriber module', function() {
mockWebSocket.onopen = function() {
subscriber
.getSnapshot('component', 'stateMachine', privateTopics)
.then(items => mockServer.stop(done))
.then(items => mockServer?.stop(done))
.catch(err => {
console.error(err);
});
Expand Down
Loading