import * as plugins from './smartsocket.plugins' import * as helpers from './smartsocket.helpers' import { Objectmap } from 'lik' // import classes import { Smartsocket } from './smartsocket.classes.smartsocket' import { SocketFunction } from './smartsocket.classes.socketfunction' import { SocketRequest, ISocketRequestDataObject, allSocketRequests } from './smartsocket.classes.socketrequest' import { SocketRole } from './smartsocket.classes.socketrole' // export interfaces /** * defines is a SocketConnection is server or client side. Important for mesh setups. */ export type TSocketConnectionSide = 'server' | 'client' /** * interface for constructor of class SocketConnection */ export interface ISocketConnectionConstructorOptions { alias: string authenticated: boolean role: SocketRole side: TSocketConnectionSide smartsocketHost: Smartsocket socket: SocketIO.Socket | SocketIOClient.Socket } /** * interface for authentication data */ export interface ISocketConnectionAuthenticationObject { role: 'coreflowContainer', password: 'somePassword', alias: 'coreflow1' } // export classes export let allSocketConnections = new Objectmap() /** * class SocketConnection represents a websocket connection */ export class SocketConnection { alias: string side: TSocketConnectionSide authenticated: boolean = false role: SocketRole smartsocketHost: Smartsocket socket: any //: SocketIO.Socket | SocketIOClient.Socket constructor (optionsArg: ISocketConnectionConstructorOptions) { this.alias = optionsArg.alias this.authenticated = optionsArg.authenticated this.role = optionsArg.role this.side = optionsArg.side this.smartsocketHost = optionsArg.smartsocketHost this.socket = optionsArg.socket // standard behaviour that is always true allSocketConnections.add(this) this.socket.on('disconnect', () => { plugins.beautylog.info(`SocketConnection with >alias ${this.alias} on >side ${this.side} disconnected`) allSocketConnections.remove(this) }) } // authenticating -------------------------- /** * authenticate the socket */ authenticate () { let done = plugins.smartq.defer() this.socket.on('dataAuth', (dataArg: ISocketConnectionAuthenticationObject) => { plugins.beautylog.log('received authentication data. now hashing and comparing...') this.socket.removeListener('dataAuth', () => { }) if (helpers.checkPasswordForRole(dataArg, this.smartsocketHost)) { // TODO: authenticate password this.alias = dataArg.alias this.authenticated = true this.role = helpers.getSocketRoleByName(dataArg.role, this.smartsocketHost) this.socket.emit('authenticated') plugins.beautylog.ok(`socket with >>alias ${this.alias} >>role ${this.role} is authenticated!`) done.resolve(this) } else { this.authenticated = false this.socket.disconnect() done.reject('not authenticated') } }) this.socket.emit('requestAuth') return done.promise } // listening ------------------------------- /** * listen to function requests */ listenToFunctionRequests () { let done = plugins.smartq.defer() if (this.authenticated) { this.socket.on('function', (dataArg: ISocketRequestDataObject) => { // check if requested function is available to the socket's scope plugins.beautylog.log('function request received') let referencedFunction: SocketFunction = this.role.allowedFunctions.find((socketFunctionArg) => { return socketFunctionArg.name === dataArg.funcCallData.funcName }) if (referencedFunction !== undefined) { plugins.beautylog.ok!('function in access scope') let localSocketRequest = new SocketRequest({ side: 'responding', originSocketConnection: this, shortId: dataArg.shortId, funcCallData: dataArg.funcCallData }) localSocketRequest.createResponse() // takes care of creating response and sending it back } else { plugins.beautylog.warn('function not existent or out of access scope') } }) this.socket.on('functionResponse', (dataArg: ISocketRequestDataObject) => { plugins.beautylog.info(`received response for request with id ${dataArg.shortId}`) let targetSocketRequest = helpers.getSocketRequestById(dataArg.shortId) targetSocketRequest.handleResponse(dataArg) }) plugins.beautylog.log(`now listening to function requests for ${this.alias}`) done.resolve(this) } else { let errMessage: 'socket needs to be authenticated first' plugins.beautylog.error(errMessage) done.reject(errMessage) } return done.promise } // sending ---------------------- }