smartsocket/ts/smartsocket.classes.socketconnection.ts

176 lines
5.9 KiB
TypeScript
Raw Normal View History

2018-03-15 01:29:40 +00:00
import * as plugins from './smartsocket.plugins';
2019-11-06 23:26:47 +00:00
import * as interfaces from './interfaces';
2016-08-08 16:20:00 +00:00
// import classes
2018-03-15 01:29:40 +00:00
import { Smartsocket } from './smartsocket.classes.smartsocket';
import { SocketFunction } from './smartsocket.classes.socketfunction';
2019-08-12 20:46:57 +00:00
import { SocketRequest, ISocketRequestDataObject } from './smartsocket.classes.socketrequest';
2018-03-15 01:29:40 +00:00
import { SocketRole } from './smartsocket.classes.socketrole';
// socket.io
import * as SocketIO from 'socket.io';
2019-08-12 20:31:40 +00:00
import { SmartsocketClient } from './smartsocket.classes.smartsocketclient';
2020-09-24 18:03:01 +00:00
import { logger } from './smartsocket.logging';
2016-08-08 16:20:00 +00:00
2016-08-09 09:42:21 +00:00
// export interfaces
/**
* defines is a SocketConnection is server or client side. Important for mesh setups.
*/
2018-03-15 01:29:40 +00:00
export type TSocketConnectionSide = 'server' | 'client';
2016-08-09 09:42:21 +00:00
/**
* interface for constructor of class SocketConnection
*/
2016-08-11 23:32:57 +00:00
export interface ISocketConnectionConstructorOptions {
2018-03-15 01:29:40 +00:00
alias: string;
authenticated: boolean;
role: SocketRole;
side: TSocketConnectionSide;
2019-08-12 20:31:40 +00:00
smartsocketHost: Smartsocket | SmartsocketClient;
2018-03-15 01:29:40 +00:00
socket: SocketIO.Socket | SocketIOClient.Socket;
2017-07-07 20:02:19 +00:00
}
2016-08-08 16:20:00 +00:00
2016-08-09 09:42:21 +00:00
/**
* interface for authentication data
*/
export interface ISocketConnectionAuthenticationObject {
2018-03-15 01:29:40 +00:00
role: 'coreflowContainer';
password: 'somePassword';
alias: 'coreflow1';
2017-07-07 20:02:19 +00:00
}
2016-08-09 09:42:21 +00:00
// export classes
2020-09-24 18:03:01 +00:00
export let allSocketConnections = new plugins.lik.ObjectMap<SocketConnection>();
2016-08-09 09:42:21 +00:00
/**
* class SocketConnection represents a websocket connection
*/
2016-08-08 16:20:00 +00:00
export class SocketConnection {
2019-06-07 06:40:24 +00:00
public alias: string;
public side: TSocketConnectionSide;
public authenticated: boolean = false;
public role: SocketRole;
2019-08-12 20:31:40 +00:00
public smartsocketRef: Smartsocket | SmartsocketClient;
2019-06-07 06:40:24 +00:00
public socket: SocketIO.Socket | SocketIOClient.Socket;
2019-11-06 23:26:47 +00:00
2019-11-08 17:41:08 +00:00
public eventSubject = new plugins.smartrx.rxjs.Subject<interfaces.TConnectionStatus>();
public eventStatus: interfaces.TConnectionStatus = 'new';
2019-11-06 23:26:47 +00:00
2018-03-15 01:29:40 +00:00
constructor(optionsArg: ISocketConnectionConstructorOptions) {
this.alias = optionsArg.alias;
this.authenticated = optionsArg.authenticated;
this.role = optionsArg.role;
this.side = optionsArg.side;
2019-08-12 20:31:40 +00:00
this.smartsocketRef = optionsArg.smartsocketHost;
2018-03-15 01:29:40 +00:00
this.socket = optionsArg.socket;
2016-08-12 01:22:36 +00:00
2017-07-07 20:02:19 +00:00
// standard behaviour that is always true
2018-03-15 01:29:40 +00:00
allSocketConnections.add(this);
2019-11-08 17:48:39 +00:00
// handle connection
this.socket.on('connect', async () => {
this.updateStatus('connected');
});
2019-11-08 16:11:41 +00:00
this.socket.on('disconnect', async () => {
2020-09-24 18:03:01 +00:00
logger.log(
'info',
2018-03-15 01:29:40 +00:00
`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`
);
2019-11-08 16:11:41 +00:00
await this.disconnect();
2018-03-15 01:29:40 +00:00
allSocketConnections.remove(this);
});
2017-07-07 20:02:19 +00:00
}
2016-08-12 01:22:36 +00:00
2017-07-07 20:02:19 +00:00
// authenticating --------------------------
2016-08-08 16:20:00 +00:00
2017-07-07 20:02:19 +00:00
/**
* authenticate the socket
*/
2019-08-12 20:31:40 +00:00
public authenticate() {
const done = plugins.smartpromise.defer();
2019-11-06 23:26:47 +00:00
this.socket.on('dataAuth', async (dataArg: ISocketConnectionAuthenticationObject) => {
2020-09-24 18:04:11 +00:00
logger.log('info', 'received authentication data. now hashing and comparing...');
2018-03-15 01:29:40 +00:00
this.socket.removeListener('dataAuth', () => {});
2019-08-12 20:31:40 +00:00
if (SocketRole.checkPasswordForRole(dataArg, this.smartsocketRef)) {
2018-03-15 01:29:40 +00:00
// TODO: authenticate password
this.alias = dataArg.alias;
this.authenticated = true;
2019-08-12 20:31:40 +00:00
this.role = SocketRole.getSocketRoleByName(this.smartsocketRef, dataArg.role);
2018-03-15 01:29:40 +00:00
this.socket.emit('authenticated');
2020-09-24 18:04:11 +00:00
logger.log('ok', `socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`);
2018-03-15 01:29:40 +00:00
done.resolve(this);
2017-07-07 20:02:19 +00:00
} else {
2018-03-15 01:29:40 +00:00
this.authenticated = false;
2019-11-06 23:26:47 +00:00
await this.disconnect();
2018-03-15 01:29:40 +00:00
done.reject('not authenticated');
2017-07-07 20:02:19 +00:00
}
2018-03-15 01:29:40 +00:00
});
2019-11-06 23:26:47 +00:00
const requestAuthPayload: interfaces.IRequestAuthPayload = {
2020-09-24 18:04:11 +00:00
serverShortId: this.smartsocketRef.shortId,
2019-11-06 23:26:47 +00:00
};
this.socket.emit('requestAuth', requestAuthPayload);
2018-03-15 01:29:40 +00:00
return done.promise;
2017-07-07 20:02:19 +00:00
}
2016-08-12 01:22:36 +00:00
2017-07-07 20:02:19 +00:00
// listening -------------------------------
/**
* listen to function requests
*/
2019-08-12 20:31:40 +00:00
public listenToFunctionRequests() {
const done = plugins.smartpromise.defer();
2017-07-07 20:02:19 +00:00
if (this.authenticated) {
2019-09-09 21:58:32 +00:00
this.socket.on('function', (dataArg: ISocketRequestDataObject<any>) => {
2017-07-07 20:02:19 +00:00
// check if requested function is available to the socket's scope
2020-09-24 18:03:01 +00:00
logger.log('info', 'function request received');
2019-09-09 21:58:32 +00:00
const referencedFunction: SocketFunction<any> = this.role.allowedFunctions.find(
2020-09-24 18:04:11 +00:00
(socketFunctionArg) => {
2018-03-15 01:29:40 +00:00
return socketFunctionArg.name === dataArg.funcCallData.funcName;
}
);
2019-08-13 09:36:31 +00:00
if (referencedFunction) {
2020-09-24 18:03:01 +00:00
logger.log('ok', 'function in access scope');
2019-08-12 20:31:40 +00:00
const localSocketRequest = new SocketRequest(this.smartsocketRef, {
2017-07-07 20:02:19 +00:00
side: 'responding',
originSocketConnection: this,
shortId: dataArg.shortId,
2020-09-24 18:04:11 +00:00
funcCallData: dataArg.funcCallData,
2018-03-15 01:29:40 +00:00
});
localSocketRequest.createResponse(); // takes care of creating response and sending it back
2016-08-08 16:20:00 +00:00
} else {
2020-09-24 18:04:11 +00:00
logger.log('warn', 'function not existent or out of access scope');
2017-07-07 20:02:19 +00:00
}
2018-03-15 01:29:40 +00:00
});
2019-09-09 21:58:32 +00:00
this.socket.on('functionResponse', (dataArg: ISocketRequestDataObject<any>) => {
2020-09-24 18:04:11 +00:00
logger.log('info', `received response for request with id ${dataArg.shortId}`);
2019-08-12 20:46:57 +00:00
const targetSocketRequest = SocketRequest.getSocketRequestById(
this.smartsocketRef,
dataArg.shortId
);
2018-03-15 01:29:40 +00:00
targetSocketRequest.handleResponse(dataArg);
});
2020-09-24 18:04:11 +00:00
logger.log('info', `now listening to function requests for ${this.alias}`);
2018-03-15 01:29:40 +00:00
done.resolve(this);
2017-07-07 20:02:19 +00:00
} else {
2019-08-12 20:31:40 +00:00
const errMessage = 'socket needs to be authenticated first';
2020-09-24 18:03:01 +00:00
logger.log('error', errMessage);
2018-03-15 01:29:40 +00:00
done.reject(errMessage);
2017-07-07 20:02:19 +00:00
}
2018-03-15 01:29:40 +00:00
return done.promise;
2017-07-07 20:02:19 +00:00
}
2019-11-06 23:26:47 +00:00
// disconnecting ----------------------
public async disconnect() {
this.socket.disconnect(true);
2019-11-08 17:41:08 +00:00
this.updateStatus('disconnected');
}
2020-09-24 18:04:11 +00:00
private updateStatus(statusArg: interfaces.TConnectionStatus) {
2019-11-08 17:41:08 +00:00
if (this.eventStatus !== statusArg) {
this.eventSubject.next(statusArg);
}
this.eventStatus = statusArg;
2019-11-06 23:26:47 +00:00
}
2017-07-07 20:02:19 +00:00
}