Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
c390881a4e | |||
5e64f4ca25 | |||
765bc73197 | |||
105acaf97b | |||
5139136af4 | |||
bcc4ce9a87 | |||
20e7584eb9 | |||
59cbc343cc | |||
75aa1f6f0d | |||
3f073ab9b3 | |||
08c1618ea8 | |||
eb181fa2f6 | |||
c901ab75d3 | |||
075c59ed2c |
765
package-lock.json
generated
765
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pushrocks/smartsocket",
|
"name": "@pushrocks/smartsocket",
|
||||||
"version": "1.1.49",
|
"version": "1.1.56",
|
||||||
"description": "easy and secure websocket communication",
|
"description": "easy and secure websocket communication",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
@ -21,25 +21,25 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apiglobal/typedrequest-interfaces": "^1.0.7",
|
"@apiglobal/typedrequest-interfaces": "^1.0.7",
|
||||||
"@pushrocks/lik": "^3.0.11",
|
"@pushrocks/lik": "^3.0.11",
|
||||||
"@pushrocks/smartdelay": "^2.0.3",
|
"@pushrocks/smartdelay": "^2.0.6",
|
||||||
"@pushrocks/smartexpress": "^3.0.40",
|
"@pushrocks/smartexpress": "^3.0.52",
|
||||||
"@pushrocks/smarthash": "^2.0.6",
|
"@pushrocks/smarthash": "^2.0.6",
|
||||||
"@pushrocks/smartlog": "^2.0.19",
|
"@pushrocks/smartlog": "^2.0.21",
|
||||||
"@pushrocks/smartpromise": "^3.0.2",
|
"@pushrocks/smartpromise": "^3.0.6",
|
||||||
"@types/shortid": "0.0.29",
|
"@pushrocks/smartrx": "^2.0.5",
|
||||||
"@types/socket.io": "^2.1.2",
|
"@pushrocks/smartunique": "^3.0.1",
|
||||||
|
"@types/socket.io": "^2.1.4",
|
||||||
"@types/socket.io-client": "^1.4.32",
|
"@types/socket.io-client": "^1.4.32",
|
||||||
"shortid": "^2.2.15",
|
"socket.io": "^2.3.0",
|
||||||
"socket.io": "^2.2.0",
|
"socket.io-client": "^2.3.0"
|
||||||
"socket.io-client": "^2.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.17",
|
"@gitzone/tsbuild": "^2.1.17",
|
||||||
"@gitzone/tsrun": "^1.2.8",
|
"@gitzone/tsrun": "^1.2.8",
|
||||||
"@gitzone/tstest": "^1.0.24",
|
"@gitzone/tstest": "^1.0.28",
|
||||||
"@pushrocks/tapbundle": "^3.0.13",
|
"@pushrocks/tapbundle": "^3.0.13",
|
||||||
"@types/node": "^12.7.4",
|
"@types/node": "^12.12.5",
|
||||||
"tslint": "^5.19.0",
|
"tslint": "^5.20.0",
|
||||||
"tslint-config-prettier": "^1.18.0"
|
"tslint-config-prettier": "^1.18.0"
|
||||||
},
|
},
|
||||||
"private": false,
|
"private": false,
|
||||||
|
@ -21,7 +21,7 @@ export interface IReqResClient {
|
|||||||
};
|
};
|
||||||
response: {
|
response: {
|
||||||
value1: string;
|
value1: string;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IReqResServer {
|
export interface IReqResServer {
|
||||||
|
5
ts/interfaces/connection.ts
Normal file
5
ts/interfaces/connection.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface IRequestAuthPayload {
|
||||||
|
serverShortId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TConnectionEvent = 'terminated' | 'error';
|
1
ts/interfaces/index.ts
Normal file
1
ts/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './connection';
|
@ -16,6 +16,10 @@ export interface ISmartsocketConstructorOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Smartsocket {
|
export class Smartsocket {
|
||||||
|
/**
|
||||||
|
* a unique id to detect server restarts
|
||||||
|
*/
|
||||||
|
public shortId = plugins.smartunique.shortId();
|
||||||
public options: ISmartsocketConstructorOptions;
|
public options: ISmartsocketConstructorOptions;
|
||||||
public io: SocketIO.Server;
|
public io: SocketIO.Server;
|
||||||
public socketConnections = new Objectmap<SocketConnection>();
|
public socketConnections = new Objectmap<SocketConnection>();
|
||||||
@ -80,7 +84,7 @@ export class Smartsocket {
|
|||||||
funcName: functionNameArg
|
funcName: functionNameArg
|
||||||
},
|
},
|
||||||
originSocketConnection: targetSocketConnectionArg,
|
originSocketConnection: targetSocketConnectionArg,
|
||||||
shortId: plugins.shortid.generate(),
|
shortId: plugins.smartunique.shortId(),
|
||||||
side: 'requesting'
|
side: 'requesting'
|
||||||
});
|
});
|
||||||
const response: ISocketFunctionCallDataResponse<T> = await socketRequest.dispatch();
|
const response: ISocketFunctionCallDataResponse<T> = await socketRequest.dispatch();
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import * as plugins from './smartsocket.plugins';
|
import * as plugins from './smartsocket.plugins';
|
||||||
|
import * as interfaces from './interfaces';
|
||||||
|
|
||||||
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
import { SocketConnection } from './smartsocket.classes.socketconnection';
|
||||||
import { ISocketFunctionCallDataRequest, SocketFunction } from './smartsocket.classes.socketfunction';
|
import { ISocketFunctionCallDataRequest, SocketFunction } from './smartsocket.classes.socketfunction';
|
||||||
import { ISocketRequestDataObject, SocketRequest } from './smartsocket.classes.socketrequest';
|
import { ISocketRequestDataObject, SocketRequest } from './smartsocket.classes.socketrequest';
|
||||||
import { SocketRole } from './smartsocket.classes.socketrole';
|
import { SocketRole } from './smartsocket.classes.socketrole';
|
||||||
|
import { defaultLogger } from '@pushrocks/smartlog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* interface for class SmartsocketClient
|
* interface for class SmartsocketClient
|
||||||
@ -14,14 +16,24 @@ export interface ISmartsocketClientOptions {
|
|||||||
alias: string; // an alias makes it easier to identify this client in a multo client environment
|
alias: string; // an alias makes it easier to identify this client in a multo client environment
|
||||||
role: string;
|
role: string;
|
||||||
password: string; // by setting a password access to functions can be limited
|
password: string; // by setting a password access to functions can be limited
|
||||||
|
autoReconnect?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SmartsocketClient {
|
export class SmartsocketClient {
|
||||||
|
// a unique id
|
||||||
|
public shortId = plugins.smartunique.shortId();
|
||||||
|
|
||||||
|
// the shortId of the remote we connect to
|
||||||
|
public remoteShortId: string = null;
|
||||||
|
|
||||||
public alias: string;
|
public alias: string;
|
||||||
public socketRole: SocketRole;
|
public socketRole: SocketRole;
|
||||||
public socketConnection: SocketConnection;
|
public socketConnection: SocketConnection;
|
||||||
public serverUrl: string;
|
public serverUrl: string;
|
||||||
public serverPort: number;
|
public serverPort: number;
|
||||||
|
public autoReconnect: boolean;
|
||||||
|
|
||||||
|
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionEvent>();
|
||||||
|
|
||||||
public socketFunctions = new plugins.lik.Objectmap<SocketFunction<any>>();
|
public socketFunctions = new plugins.lik.Objectmap<SocketFunction<any>>();
|
||||||
public socketRequests = new plugins.lik.Objectmap<SocketRequest<any>>();
|
public socketRequests = new plugins.lik.Objectmap<SocketRequest<any>>();
|
||||||
@ -35,6 +47,7 @@ export class SmartsocketClient {
|
|||||||
name: optionsArg.role,
|
name: optionsArg.role,
|
||||||
passwordHash: optionsArg.password
|
passwordHash: optionsArg.password
|
||||||
});
|
});
|
||||||
|
this.autoReconnect = optionsArg.autoReconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addSocketFunction(socketFunction: SocketFunction<any>) {
|
public addSocketFunction(socketFunction: SocketFunction<any>) {
|
||||||
@ -55,21 +68,58 @@ export class SmartsocketClient {
|
|||||||
role: this.socketRole,
|
role: this.socketRole,
|
||||||
side: 'client',
|
side: 'client',
|
||||||
smartsocketHost: this,
|
smartsocketHost: this,
|
||||||
socket: plugins.socketIoClient(socketUrl, { multiplex: false })
|
socket: plugins.socketIoClient(socketUrl, {
|
||||||
|
multiplex: false,
|
||||||
|
reconnectionAttempts: 5,
|
||||||
|
})
|
||||||
});
|
});
|
||||||
this.socketConnection.socket.on('requestAuth', () => {
|
|
||||||
|
const timer = new plugins.smarttime.Timer(5000);
|
||||||
|
timer.start();
|
||||||
|
timer.completed.then(() => {
|
||||||
|
defaultLogger.log('warn', 'connection to server timed out.');
|
||||||
|
this.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
// authentication flow
|
||||||
|
this.socketConnection.socket.on('requestAuth', (requestAuthPayload: interfaces.IRequestAuthPayload) => {
|
||||||
|
timer.reset();
|
||||||
plugins.smartlog.defaultLogger.log('info', 'server requested authentication');
|
plugins.smartlog.defaultLogger.log('info', 'server requested authentication');
|
||||||
this.socketConnection.socket.emit('dataAuth', {
|
|
||||||
role: this.socketRole.name,
|
// lets register the authenticated event
|
||||||
password: this.socketRole.passwordHash,
|
|
||||||
alias: this.alias
|
|
||||||
});
|
|
||||||
this.socketConnection.socket.on('authenticated', () => {
|
this.socketConnection.socket.on('authenticated', () => {
|
||||||
|
this.remoteShortId = requestAuthPayload.serverShortId;
|
||||||
plugins.smartlog.defaultLogger.log('info', 'client is authenticated');
|
plugins.smartlog.defaultLogger.log('info', 'client is authenticated');
|
||||||
this.socketConnection.authenticated = true;
|
this.socketConnection.authenticated = true;
|
||||||
this.socketConnection.listenToFunctionRequests();
|
this.socketConnection.listenToFunctionRequests();
|
||||||
done.resolve();
|
done.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// lets register the forbidden event
|
||||||
|
this.socketConnection.socket.on('forbidden', async () => {
|
||||||
|
defaultLogger.log('warn', `disconnecting due to being forbidden to use the ressource`);
|
||||||
|
await this.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
// lets provide the actual auth data
|
||||||
|
this.socketConnection.socket.emit('dataAuth', {
|
||||||
|
role: this.socketRole.name,
|
||||||
|
password: this.socketRole.passwordHash,
|
||||||
|
alias: this.alias
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// handle disconnection and errors
|
||||||
|
this.socketConnection.socket.on('disconnect', async () => {
|
||||||
|
await this.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socketConnection.socket.on('reconnect_failed', async () => {
|
||||||
|
await this.disconnect();
|
||||||
|
});
|
||||||
|
this.socketConnection.socket.on('connect_error', async () => {
|
||||||
|
await this.disconnect();
|
||||||
});
|
});
|
||||||
return done.promise;
|
return done.promise;
|
||||||
}
|
}
|
||||||
@ -78,9 +128,26 @@ export class SmartsocketClient {
|
|||||||
* disconnect from the server
|
* disconnect from the server
|
||||||
*/
|
*/
|
||||||
public async disconnect() {
|
public async disconnect() {
|
||||||
this.socketConnection.socket.disconnect(true);
|
if (this.socketConnection) {
|
||||||
this.socketConnection = undefined;
|
this.socketConnection.disconnect();
|
||||||
plugins.smartlog.defaultLogger.log('ok', 'disconnected!');
|
this.socketConnection = undefined;
|
||||||
|
plugins.smartlog.defaultLogger.log('ok', 'disconnected!');
|
||||||
|
}
|
||||||
|
defaultLogger.log('warn', `disconnected from server ${this.remoteShortId}`);
|
||||||
|
this.remoteShortId = null;
|
||||||
|
this.eventSubject.next('terminated');
|
||||||
|
|
||||||
|
if (this.autoReconnect) {
|
||||||
|
this.tryDebouncedReconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* try a reconnection
|
||||||
|
*/
|
||||||
|
public async tryDebouncedReconnect() {
|
||||||
|
await plugins.smartdelay.delayForRandom(10000, 60000);
|
||||||
|
await this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +160,7 @@ export class SmartsocketClient {
|
|||||||
const socketRequest = new SocketRequest<T>(this, {
|
const socketRequest = new SocketRequest<T>(this, {
|
||||||
side: 'requesting',
|
side: 'requesting',
|
||||||
originSocketConnection: this.socketConnection,
|
originSocketConnection: this.socketConnection,
|
||||||
shortId: plugins.shortid.generate(),
|
shortId: plugins.smartunique.shortId(),
|
||||||
funcCallData: {
|
funcCallData: {
|
||||||
funcName: functionNameArg,
|
funcName: functionNameArg,
|
||||||
funcDataArg: dataArg
|
funcDataArg: dataArg
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as plugins from './smartsocket.plugins';
|
import * as plugins from './smartsocket.plugins';
|
||||||
|
import * as interfaces from './interfaces';
|
||||||
|
|
||||||
import { Objectmap } from '@pushrocks/lik';
|
import { Objectmap } from '@pushrocks/lik';
|
||||||
|
|
||||||
@ -53,6 +54,9 @@ export class SocketConnection {
|
|||||||
public role: SocketRole;
|
public role: SocketRole;
|
||||||
public smartsocketRef: Smartsocket | SmartsocketClient;
|
public smartsocketRef: Smartsocket | SmartsocketClient;
|
||||||
public socket: SocketIO.Socket | SocketIOClient.Socket;
|
public socket: SocketIO.Socket | SocketIOClient.Socket;
|
||||||
|
|
||||||
|
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionEvent>();
|
||||||
|
|
||||||
constructor(optionsArg: ISocketConnectionConstructorOptions) {
|
constructor(optionsArg: ISocketConnectionConstructorOptions) {
|
||||||
this.alias = optionsArg.alias;
|
this.alias = optionsArg.alias;
|
||||||
this.authenticated = optionsArg.authenticated;
|
this.authenticated = optionsArg.authenticated;
|
||||||
@ -63,12 +67,12 @@ export class SocketConnection {
|
|||||||
|
|
||||||
// standard behaviour that is always true
|
// standard behaviour that is always true
|
||||||
allSocketConnections.add(this);
|
allSocketConnections.add(this);
|
||||||
this.socket.on('disconnect', () => {
|
this.socket.on('disconnect', async () => {
|
||||||
plugins.smartlog.defaultLogger.log(
|
plugins.smartlog.defaultLogger.log(
|
||||||
'info',
|
'info',
|
||||||
`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`
|
`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`
|
||||||
);
|
);
|
||||||
this.socket.disconnect();
|
await this.disconnect();
|
||||||
allSocketConnections.remove(this);
|
allSocketConnections.remove(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -80,7 +84,7 @@ export class SocketConnection {
|
|||||||
*/
|
*/
|
||||||
public authenticate() {
|
public authenticate() {
|
||||||
const done = plugins.smartpromise.defer();
|
const done = plugins.smartpromise.defer();
|
||||||
this.socket.on('dataAuth', (dataArg: ISocketConnectionAuthenticationObject) => {
|
this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => {
|
||||||
plugins.smartlog.defaultLogger.log(
|
plugins.smartlog.defaultLogger.log(
|
||||||
'info',
|
'info',
|
||||||
'received authentication data. now hashing and comparing...'
|
'received authentication data. now hashing and comparing...'
|
||||||
@ -99,11 +103,14 @@ export class SocketConnection {
|
|||||||
done.resolve(this);
|
done.resolve(this);
|
||||||
} else {
|
} else {
|
||||||
this.authenticated = false;
|
this.authenticated = false;
|
||||||
this.socket.disconnect();
|
await this.disconnect();
|
||||||
done.reject('not authenticated');
|
done.reject('not authenticated');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.socket.emit('requestAuth');
|
const requestAuthPayload: interfaces.IRequestAuthPayload = {
|
||||||
|
serverShortId: this.smartsocketRef.shortId
|
||||||
|
};
|
||||||
|
this.socket.emit('requestAuth', requestAuthPayload);
|
||||||
return done.promise;
|
return done.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,5 +170,9 @@ export class SocketConnection {
|
|||||||
return done.promise;
|
return done.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sending ----------------------
|
// disconnecting ----------------------
|
||||||
|
public async disconnect() {
|
||||||
|
this.socket.disconnect(true);
|
||||||
|
this.eventSubject.next('terminated');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@ import * as smarthash from '@pushrocks/smarthash';
|
|||||||
import * as smartdelay from '@pushrocks/smartdelay';
|
import * as smartdelay from '@pushrocks/smartdelay';
|
||||||
import * as smartexpress from '@pushrocks/smartexpress';
|
import * as smartexpress from '@pushrocks/smartexpress';
|
||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
import * as smartpromise from '@pushrocks/smartpromise';
|
||||||
|
import * as smarttime from '@pushrocks/smarttime';
|
||||||
|
import * as smartunique from '@pushrocks/smartunique';
|
||||||
|
import * as smartrx from '@pushrocks/smartrx';
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -18,16 +21,17 @@ export {
|
|||||||
smarthash,
|
smarthash,
|
||||||
smartdelay,
|
smartdelay,
|
||||||
smartexpress,
|
smartexpress,
|
||||||
smartpromise
|
smartpromise,
|
||||||
|
smarttime,
|
||||||
|
smartunique,
|
||||||
|
smartrx
|
||||||
};
|
};
|
||||||
|
|
||||||
// third party scope
|
// third party scope
|
||||||
import * as shortid from 'shortid';
|
|
||||||
import socketIo from 'socket.io';
|
import socketIo from 'socket.io';
|
||||||
import socketIoClient from 'socket.io-client';
|
import socketIoClient from 'socket.io-client';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
shortid,
|
|
||||||
socketIo,
|
socketIo,
|
||||||
socketIoClient
|
socketIoClient
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user