diff --git a/src/channelManager.ts b/src/channelManager.ts index 890689b..572e0cc 100644 --- a/src/channelManager.ts +++ b/src/channelManager.ts @@ -8,11 +8,11 @@ import CustomClient from './clients/types/customClient'; var logger = require('./logger'); class ChannelManager { - channels: any = []; + channels: any[] = []; constructor() { // create default channel... - var channel: PublicChannel = new PublicChannel('default'); + let channel = new PublicChannel('default'); this.channels.push(channel); } @@ -56,13 +56,18 @@ class ChannelManager { } createByChannelType(data: any) { - var channel_name = data.channel_type + 'Channel' - try { - var Channel = require(`./channels/types/${channel_name}`); - logger.accessLog.info(`attempting to create channel of type ${channel_name}, channel id: ${data.channel}...`); - return new Channel(data.channel); + logger.accessLog.info(`attempting to create channel of type ${data.channel_type}, channel id: ${data.channel}...`); + + if (data.channel_type == 'public') { + return new PublicChannel(data.channel) + } else if (data.channel_type == 'private') { + return new PrivateChannel(data.channel) + } else { + return new CustomChannel(data.channel, data.custom) + } } catch (e) { + console.log(e) logger.errorLog.info(e); logger.accessLog.info(`creating base channel: ${data.channel}`); return new PublicChannel(data.channel); diff --git a/src/channels/channelBase.ts b/src/channels/channelBase.ts index 908d9f6..9219110 100644 --- a/src/channels/channelBase.ts +++ b/src/channels/channelBase.ts @@ -1,23 +1,18 @@ import PublicClient from '../clients/types/publicClient'; import PrivateClient from '../clients/types/privateClient'; import CustomClient from '../clients/types/customClient'; -import * as Joi from 'joi'; var logger = require('../logger'); class ChannelBase { id: string; - clients: PrivateClient[]|PublicClient[]|CustomClient[] = []; + clients: any[] = []; constructor(id: string) { this.id = id; logger.accessLog.info('Channel Created', {channelId: id}); } - validations() { - return {} - } - broadcastMessage(from: PublicClient|PrivateClient|CustomClient, message: object) { for (let to of this.clients) { if (this.messageTransactionPossible(from, to)) { diff --git a/src/channels/types/customChannel.ts b/src/channels/types/customChannel.ts index b4a6fbb..9c768a1 100644 --- a/src/channels/types/customChannel.ts +++ b/src/channels/types/customChannel.ts @@ -1,18 +1,18 @@ import CustomClient from '../../clients/types/customClient'; import ChannelBase from '../channelBase'; -import * as Joi from 'joi'; class CustomChannel extends ChannelBase { - validations() { - return { - test: Joi.alternatives().try(Joi.string(), Joi.object()) - } + clients: CustomClient[] = []; + custom: any; + + constructor(id: string, custom: any) { + super(id); + this.custom = custom } messageTransactionPossible(from: CustomClient, to: CustomClient) { - return true + return eval(this.custom.broadcastConditions) } }; -module.exports = CustomChannel; export default CustomChannel; diff --git a/src/channels/types/privateChannel.ts b/src/channels/types/privateChannel.ts index c668b7a..7dc6b03 100644 --- a/src/channels/types/privateChannel.ts +++ b/src/channels/types/privateChannel.ts @@ -4,6 +4,8 @@ import ChannelBase from '../channelBase'; var logger = require('../../logger'); class PrivateChannel extends ChannelBase { + clients: PrivateClient[] = []; + messageTransactionPossible(from: PrivateClient, to: PrivateClient) { return ( to != from && @@ -13,5 +15,4 @@ class PrivateChannel extends ChannelBase { } }; -module.exports = PrivateChannel; export default PrivateChannel; diff --git a/src/channels/types/publicChannel.ts b/src/channels/types/publicChannel.ts index abdc902..07daaa1 100644 --- a/src/channels/types/publicChannel.ts +++ b/src/channels/types/publicChannel.ts @@ -4,6 +4,8 @@ import ChannelBase from '../channelBase'; var logger = require('../../logger'); class PublicChannel extends ChannelBase { + clients: PublicClient[] = []; + messageTransactionPossible(from: PublicClient, to: PublicClient) { return ( to != from @@ -11,5 +13,4 @@ class PublicChannel extends ChannelBase { } }; -module.exports = PublicChannel; export default PublicChannel; diff --git a/src/clientManager.ts b/src/clientManager.ts index 0701716..660d8a7 100644 --- a/src/clientManager.ts +++ b/src/clientManager.ts @@ -7,7 +7,7 @@ import ChannelManager from './channelManager'; var logger = require('./logger'); class ClientManager { - clients: PublicClient[]|PrivateClient[]|CustomClient[] = []; + clients: any[] = []; constructor() { //...maybe one day @@ -68,12 +68,16 @@ class ClientManager { } getClientType(data: any, channelManager: ChannelManager, ws: WebSocket) { - var client_type = data.client_type + 'Client' - try { - var Client = require(`./clients/types/${client_type}`); logger.accessLog.info(`attempting to create client of type ${data.client_type}, client id: ${data.user_id}...`); - return new Client(data, ws, channelManager, this); + + if (data.client_type == 'public') { + return new PublicClient(data, ws, channelManager, this) + } else if (data.channel_type == 'private') { + return new PrivateClient(data, ws, channelManager, this) + } else { + return new CustomClient(data, ws, channelManager, this) + } } catch (e) { logger.errorLog.info(e); logger.accessLog.info(`creating base client: ${data.user_id}`); diff --git a/src/clients/clientBase.ts b/src/clients/clientBase.ts index 966c5fe..bda5248 100644 --- a/src/clients/clientBase.ts +++ b/src/clients/clientBase.ts @@ -4,6 +4,9 @@ import ChannelManager from '../channelManager'; import PublicChannel from '../channels/types/publicChannel'; import PrivateChannel from '../channels/types/privateChannel'; import CustomChannel from '../channels/types/customChannel'; +import PublicClient from '../clients/types/publicClient'; +import PrivateClient from '../clients/types/privateClient'; +import CustomClient from '../clients/types/customClient'; var messageManager = require('../messageManager'); var logger = require('../logger'); @@ -27,10 +30,6 @@ class ClientBase { this.roles = ['receiver'] } - validations() { - return {} - } - getData() { return this.data; } @@ -46,21 +45,24 @@ class ClientBase { connectToChannel(channel: PublicChannel|PrivateChannel|CustomChannel) { this.channel = channel; - var messageListener = (message: any) => { - logger.accessLog.info(`starting message transaction on channel ${channel.id}: `, {message: message}); - message = messageManager.prepareMessage(message, channel, this); + var messageListener = (data: any) => { + logger.accessLog.info(`starting message transaction on channel ${channel.id}: `, {data: data}); + data = messageManager.prepareMessage(data, channel, this); - if (!message.error) { - if (message['message_type'] == 'broadcast') { - channel.broadcastMessage(this, message); - } else if (message['message_type'] == 'changeChannel') { + if (!data.error) { + if (data.message_type == 'broadcast') { + channel.broadcastMessage(this, data); + } else if (data.message_type == 'direct') { + let to = this.clientManager.getClient(data.message.to) + to.directMessage(data) + } else if (data.message_type == 'changeChannel') { this.ws.removeListener('message', messageListener); - this.channelManager.changeChannel(this, message); + this.channelManager.changeChannel(this, data); } - logger.accessLog.info(`message transaction complete on channel ${channel.id}: `, {message: message}); + logger.accessLog.info(`message transaction complete on channel ${channel.id}: `, {message: data}); } else { - logger.errorLog.info(`Validation failed, please review schema: ${channel.id}`, {data: {message: message, error: message.error}}); + logger.errorLog.info(`Validation failed, please review schema: ${channel.id}`, {data: {message: data, error: data.error}}); } } @@ -78,6 +80,11 @@ class ClientBase { }); } + directMessage(message: any) { + this.ws.send(JSON.stringify(message)); + logger.accessLog.info(`sent direct message to ${this.id}`, { data: { message: message }}); + } + replaceWebSocket(ws: WebSocket) { this.ws.close(); this.ws = ws; diff --git a/src/clients/types/customClient.ts b/src/clients/types/customClient.ts index 72b562c..2732b70 100644 --- a/src/clients/types/customClient.ts +++ b/src/clients/types/customClient.ts @@ -1,14 +1,18 @@ import ClientBase from '../clientBase'; +import ClientManager from '../../clientManager'; +import ChannelManager from '../../channelManager'; +import * as WebSocket from 'ws'; import * as Joi from 'joi'; +var logger = require('../../logger'); + class CustomClient extends ClientBase { - // validations() { - // return { - // test: Joi.alternatives().try(Joi.string(), Joi.object()) - // } - // } + constructor(data: any, ws: WebSocket, channelManager: ChannelManager, clientManager: ClientManager) { + super(data, ws, channelManager, clientManager); + this.roles = data.user_roles + logger.accessLog.info('Custom Client Created', {data: data}); + } }; -module.exports = CustomClient; export default CustomClient; diff --git a/src/clients/types/privateClient.ts b/src/clients/types/privateClient.ts index a5fec6c..616838f 100644 --- a/src/clients/types/privateClient.ts +++ b/src/clients/types/privateClient.ts @@ -13,6 +13,5 @@ class PrivateClient extends ClientBase { } }; -module.exports = PrivateClient; export default PrivateClient; diff --git a/src/clients/types/publicClient.ts b/src/clients/types/publicClient.ts index a97e585..f66c3f4 100644 --- a/src/clients/types/publicClient.ts +++ b/src/clients/types/publicClient.ts @@ -4,6 +4,5 @@ var logger = require('../../logger'); class PublicClient extends ClientBase {}; -module.exports = PublicClient; export default PublicClient; diff --git a/src/config/app.ts b/src/config/app.ts index 1e0abc6..58dafbf 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -15,5 +15,5 @@ module.exports = { audience: 'internal', algorithm: ["HS256"] }, - messageTypes : ['broadcast', 'changeChannel'] + messageTypes : ['broadcast', 'direct', 'changeChannel'] } diff --git a/src/messageManager.ts b/src/messageManager.ts index 294b356..6566fa2 100644 --- a/src/messageManager.ts +++ b/src/messageManager.ts @@ -1,31 +1,11 @@ import * as Joi from 'joi'; -import PublicChannel from './channels/types/publicChannel'; -import PrivateChannel from './channels/types/privateChannel'; -import CustomChannel from './channels/types/customChannel'; -import PublicClient from './clients/types/publicClient'; -import PrivateClient from './clients/types/privateClient'; -import CustomClient from './clients/types/customClient'; - -var logger = require('./logger'); -var app = require('./config/app'); - -let schema = (channel: PublicChannel|PrivateChannel|CustomChannel, client: PublicClient|PrivateClient|CustomClient) => { - let validations = { - message_type: Joi.string().valid(app.messageTypes).insensitive().required(), - channel: Joi.string(), - channel_type: Joi.string(), - client_type: Joi.string(), - user_id: Joi.number().integer(), - message: Joi.alternatives().try(Joi.string(), Joi.object()) - } - - return {...validations, ...channel.validations, ...client.validations} -}; +import Validations from './services/validations'; module.exports = { - prepareMessage: (message: string, channel: PublicChannel|PrivateChannel|CustomChannel, client: PublicClient|PrivateClient|CustomClient) => { - var parsed = JSON.parse(message) - const result = Joi.validate(parsed, schema(channel, client)); + prepareMessage: (message: string) => { + let validations = new Validations(message) + let parsed = JSON.parse(message) + const result = Joi.validate(parsed, validations.MessageConditions); if (result.error) { return result diff --git a/src/services/validations.ts b/src/services/validations.ts new file mode 100644 index 0000000..3c09c7d --- /dev/null +++ b/src/services/validations.ts @@ -0,0 +1,26 @@ +import PublicChannel from '../channels/types/publicChannel'; +import PrivateChannel from '../channels/types/privateChannel'; +import CustomChannel from '../channels/types/customChannel'; +import * as Joi from 'joi' + +var app = require('../config/app'); + +class Validations { + MessageConditions = { + message_type: Joi.string().valid(app.messageTypes).insensitive().required(), + channel: Joi.string(), + channel_type: Joi.string(), + client_type: Joi.string(), + user_id: Joi.number().integer(), + message: Joi.alternatives().try(Joi.string(), Joi.object()), + custom: Joi.object() + } + + constructor(message: any) { + if (message.channel_type == 'custom') { + let conditions = message.conditions + } + } +} + +export default Validations; \ No newline at end of file diff --git a/src/test/channelBase.spec.ts b/src/test/channelBase.spec.ts index a302093..fde1dcd 100644 --- a/src/test/channelBase.spec.ts +++ b/src/test/channelBase.spec.ts @@ -40,7 +40,7 @@ describe('ChannelBase', function () { }); it('should not broadcast a message to self', function () { - var result = channel.broadcastMessage(client, 'test message'); + var result = channel.broadcastMessage(client, {message: "test message"}); expect(result.status).to.be.equal('success'); }); diff --git a/src/test/clientManager.spec.ts b/src/test/clientManager.spec.ts index 4e8a418..6b02d2e 100644 --- a/src/test/clientManager.spec.ts +++ b/src/test/clientManager.spec.ts @@ -1,5 +1,5 @@ import * as WebSocket from 'ws'; -import ClientBase from '../clients/clientBase'; +import PublicClient from '../clients/types/publicClient'; import ClientManager from '../clientManager'; import ChannelManager from '../channelManager';