2016-08-08 16:20:00 +00:00
|
|
|
import * as plugins from "./smartsocket.plugins";
|
|
|
|
import * as helpers from "./smartsocket.helpers";
|
|
|
|
|
2016-08-15 00:36:17 +00:00
|
|
|
import {Objectmap} from "lik";
|
|
|
|
|
2016-08-08 16:20:00 +00:00
|
|
|
// import classes
|
2016-09-04 22:34:09 +00:00
|
|
|
import { Smartsocket } from "./smartsocket.classes.smartsocket"
|
2016-08-09 16:22:30 +00:00
|
|
|
import { SocketFunction } from "./smartsocket.classes.socketfunction";
|
2016-08-12 03:17:13 +00:00
|
|
|
import { SocketRequest, ISocketRequestDataObject, allSocketRequests } from "./smartsocket.classes.socketrequest";
|
2016-08-08 16:20:00 +00:00
|
|
|
import { SocketRole } from "./smartsocket.classes.socketrole";
|
|
|
|
|
2016-08-09 09:42:21 +00:00
|
|
|
// export interfaces
|
|
|
|
|
2016-08-15 00:36:17 +00:00
|
|
|
/**
|
|
|
|
* defines is a SocketConnection is server or client side. Important for mesh setups.
|
|
|
|
*/
|
|
|
|
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 {
|
2016-08-14 01:25:26 +00:00
|
|
|
alias: string;
|
2016-08-08 16:20:00 +00:00
|
|
|
authenticated: boolean;
|
2016-08-14 01:25:26 +00:00
|
|
|
role: SocketRole;
|
2016-08-15 00:36:17 +00:00
|
|
|
side: TSocketConnectionSide;
|
2016-09-04 22:34:09 +00:00
|
|
|
smartsocketHost: Smartsocket;
|
2016-08-14 01:25:26 +00:00
|
|
|
socket: SocketIO.Socket | SocketIOClient.Socket;
|
2016-08-08 16:20:00 +00:00
|
|
|
};
|
|
|
|
|
2016-08-09 09:42:21 +00:00
|
|
|
/**
|
|
|
|
* interface for authentication data
|
|
|
|
*/
|
|
|
|
export interface ISocketConnectionAuthenticationObject {
|
|
|
|
role: "coreflowContainer",
|
|
|
|
password: "somePassword",
|
|
|
|
alias: "coreflow1"
|
2016-08-15 00:36:17 +00:00
|
|
|
};
|
2016-08-09 09:42:21 +00:00
|
|
|
|
|
|
|
// export classes
|
2016-08-15 00:36:17 +00:00
|
|
|
export let allSocketConnections = new 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 {
|
2016-08-14 01:25:26 +00:00
|
|
|
alias: string;
|
2016-08-15 00:36:17 +00:00
|
|
|
side:TSocketConnectionSide;
|
2016-08-14 23:38:28 +00:00
|
|
|
authenticated: boolean = false;
|
2016-08-14 01:25:26 +00:00
|
|
|
role: SocketRole;
|
2016-09-04 22:34:09 +00:00
|
|
|
smartsocketHost:Smartsocket;
|
2016-08-11 23:32:57 +00:00
|
|
|
socket: SocketIO.Socket | SocketIOClient.Socket;
|
|
|
|
constructor(optionsArg: ISocketConnectionConstructorOptions) {
|
2016-08-08 16:20:00 +00:00
|
|
|
this.alias = optionsArg.alias;
|
|
|
|
this.authenticated = optionsArg.authenticated;
|
|
|
|
this.role = optionsArg.role;
|
2016-08-15 00:36:17 +00:00
|
|
|
this.side = optionsArg.side;
|
2016-09-04 22:34:09 +00:00
|
|
|
this.smartsocketHost = optionsArg.smartsocketHost;
|
2016-08-08 16:20:00 +00:00
|
|
|
this.socket = optionsArg.socket;
|
2016-08-14 01:25:26 +00:00
|
|
|
|
|
|
|
// standard behaviour that is always true
|
2016-08-15 00:36:17 +00:00
|
|
|
allSocketConnections.add(this);
|
2016-08-14 01:25:26 +00:00
|
|
|
this.socket.on("disconnect", () => {
|
2016-08-15 00:36:17 +00:00
|
|
|
plugins.beautylog.info(`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`);
|
|
|
|
allSocketConnections.remove(this);
|
2016-08-14 01:25:26 +00:00
|
|
|
});
|
|
|
|
};
|
2016-08-12 01:22:36 +00:00
|
|
|
|
|
|
|
// authenticating --------------------------
|
|
|
|
|
2016-08-08 16:20:00 +00:00
|
|
|
/**
|
|
|
|
* authenticate the socket
|
|
|
|
*/
|
|
|
|
authenticate() {
|
|
|
|
let done = plugins.q.defer();
|
2016-08-16 02:48:42 +00:00
|
|
|
this.socket.on("dataAuth", (dataArg:ISocketConnectionAuthenticationObject) => {
|
2016-08-08 16:20:00 +00:00
|
|
|
plugins.beautylog.log("received authentication data. now hashing and comparing...");
|
|
|
|
this.socket.removeListener("dataAuth", () => { });
|
2016-09-04 22:34:09 +00:00
|
|
|
if (helpers.checkPasswordForRole(dataArg,this.smartsocketHost)) { // TODO: authenticate password
|
2016-08-08 16:20:00 +00:00
|
|
|
this.alias = dataArg.alias
|
|
|
|
this.authenticated = true;
|
2016-09-04 22:34:09 +00:00
|
|
|
this.role = helpers.getSocketRoleByName(dataArg.role,this.smartsocketHost);
|
2016-08-08 16:20:00 +00:00
|
|
|
this.socket.emit("authenticated");
|
|
|
|
plugins.beautylog.ok(`socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`);
|
|
|
|
done.resolve(this);
|
|
|
|
} else {
|
2016-08-14 23:38:28 +00:00
|
|
|
this.authenticated = false;
|
2016-08-08 16:20:00 +00:00
|
|
|
this.socket.disconnect();
|
|
|
|
done.reject("not authenticated");
|
|
|
|
};
|
|
|
|
});
|
|
|
|
this.socket.emit("requestAuth");
|
|
|
|
return done.promise;
|
|
|
|
};
|
|
|
|
|
2016-08-12 01:22:36 +00:00
|
|
|
// listening -------------------------------
|
|
|
|
|
2016-08-08 16:20:00 +00:00
|
|
|
/**
|
|
|
|
* listen to function requests
|
|
|
|
*/
|
2016-08-14 23:38:28 +00:00
|
|
|
listenToFunctionRequests(){
|
2016-08-08 16:20:00 +00:00
|
|
|
let done = plugins.q.defer();
|
|
|
|
if(this.authenticated){
|
2016-08-09 16:22:30 +00:00
|
|
|
this.socket.on("function", (dataArg:ISocketRequestDataObject) => {
|
2016-08-09 21:37:25 +00:00
|
|
|
// check if requested function is available to the socket's scope
|
2016-08-14 23:38:28 +00:00
|
|
|
plugins.beautylog.log("function request received");
|
2016-08-09 09:42:21 +00:00
|
|
|
let referencedFunction:SocketFunction = this.role.allowedFunctions.find((socketFunctionArg) => {
|
2016-08-09 21:37:25 +00:00
|
|
|
return socketFunctionArg.name === dataArg.funcCallData.funcName;
|
2016-08-09 09:42:21 +00:00
|
|
|
});
|
|
|
|
if(referencedFunction !== undefined){
|
2016-08-14 23:38:28 +00:00
|
|
|
plugins.beautylog.ok!("function in access scope");
|
2016-08-09 14:33:56 +00:00
|
|
|
let localSocketRequest = new SocketRequest({
|
|
|
|
side:"responding",
|
2016-08-09 16:22:30 +00:00
|
|
|
originSocketConnection:this,
|
|
|
|
shortId:dataArg.shortId,
|
2016-08-09 21:37:25 +00:00
|
|
|
funcCallData:dataArg.funcCallData
|
2016-08-09 14:33:56 +00:00
|
|
|
});
|
2016-08-12 01:22:36 +00:00
|
|
|
localSocketRequest.createResponse(); // takes care of creating response and sending it back
|
2016-08-09 09:42:21 +00:00
|
|
|
} else {
|
|
|
|
plugins.beautylog.warn("function not existent or out of access scope");
|
|
|
|
};
|
2016-08-09 14:33:56 +00:00
|
|
|
});
|
2016-08-09 16:22:30 +00:00
|
|
|
this.socket.on("functionResponse", (dataArg:ISocketRequestDataObject) => {
|
2016-08-14 23:38:28 +00:00
|
|
|
plugins.beautylog.info(`received response for request with id ${dataArg.shortId}`);
|
2016-08-12 03:17:13 +00:00
|
|
|
let targetSocketRequest = helpers.getSocketRequestById(dataArg.shortId);
|
|
|
|
targetSocketRequest.handleResponse(dataArg);
|
2016-08-14 23:38:28 +00:00
|
|
|
});
|
|
|
|
plugins.beautylog.log(`now listening to function requests for ${this.alias}`);
|
|
|
|
done.resolve(this);
|
2016-08-08 16:20:00 +00:00
|
|
|
} else {
|
2016-08-14 23:38:28 +00:00
|
|
|
let errMessage: "socket needs to be authenticated first";
|
|
|
|
plugins.beautylog.error(errMessage);
|
|
|
|
done.reject(errMessage);
|
2016-08-08 16:20:00 +00:00
|
|
|
};
|
|
|
|
return done.promise;
|
2016-08-12 01:22:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// sending ----------------------
|
|
|
|
|
2016-08-08 16:20:00 +00:00
|
|
|
};
|