initial addition of custom channels and clients

This commit is contained in:
Josh Burman 2019-12-22 01:24:37 -05:00
parent 60562c3139
commit df864790f9
14 changed files with 143 additions and 63 deletions

View File

@ -1,6 +1,6 @@
{
"name": "braid",
"version": "1.2",
"version": "1.2.0",
"description": "",
"main": "index.js",
"scripts": {

View File

@ -1,7 +1,9 @@
import ChannelBase from './channels/channelBase';
import ClientBase from './clients/clientBase';
import PrivateClient from './clients/types/privateClient';
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');
@ -10,13 +12,13 @@ class ChannelManager {
constructor() {
// create default channel...
var channel: ChannelBase = new ChannelBase('default');
var channel: PublicChannel = new PublicChannel('default');
this.channels.push(channel);
}
createChannel(data: any) {
var channelExists: ChannelBase|PrivateChannel|null = this.channelExists(data.channel);
var channel: ChannelBase|PrivateChannel;
var channelExists: PublicChannel|PrivateChannel|CustomChannel|null = this.channelExists(data.channel);
var channel: PublicChannel|PrivateChannel|CustomChannel;
if (channelExists) {
channel = channelExists;
@ -40,8 +42,8 @@ class ChannelManager {
return null;
}
addClientToChannel(client: ClientBase|PrivateClient, channel_id: string) {
var channel: ChannelBase|PrivateChannel|null = this.channelExists(channel_id);
addClientToChannel(client: PublicClient|PrivateClient|CustomClient, channel_id: string) {
var channel: PrivateChannel|PrivateChannel|CustomChannel|null = this.channelExists(channel_id);
if (channel) {
channel.addClient(client);
@ -63,7 +65,7 @@ class ChannelManager {
} catch (e) {
logger.errorLog.info(e);
logger.accessLog.info(`creating base channel: ${data.channel}`);
return new ChannelBase(data.channel);
return new PublicChannel(data.channel);
}
}
@ -83,7 +85,7 @@ class ChannelManager {
return false;
}
changeChannel(client: ClientBase|PrivateClient, changeRequest: any) {
changeChannel(client: PublicClient|PrivateClient|CustomClient, changeRequest: any) {
if (client.channel != null) {
this.removeClientFromChannel(client.id, client.channel.id)
}

View File

@ -1,21 +1,44 @@
import ClientBase from '../clients/clientBase';
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[]|ClientBase[] = [];
clients: PrivateClient[]|PublicClient[]|CustomClient[] = [];
constructor(id: string) {
this.id = id;
logger.accessLog.info('Channel Created', {channelId: id});
}
addClient(client: PrivateClient|ClientBase) {
validations() {
return {}
}
broadcastMessage(from: PublicClient|PrivateClient|CustomClient, message: object) {
for (let to of this.clients) {
if (this.messageTransactionPossible(from, to)) {
to.ws.send(JSON.stringify(message));
logger.accessLog.info(`sent to ${to.id}`, { data: { message: message }});
} else {
logger.accessLog.info(`client is unable to send: ${to.id}`, { data: { message: message }});
}
}
return {'status': 'success', 'message': `message broadcast complete`};
}
messageTransactionPossible(_from: PublicClient|PrivateClient|CustomClient, _to: PublicClient|PrivateClient|CustomClient) {
return true
}
addClient(client: PublicClient|PrivateClient|CustomClient) {
if (this.clientExists(client.id)) {
logger.errorLog.info('Client already exits in channel', {channelId: this.id, clientId: client.id});
return {'status': 'notice', 'message': 'client aleady exists in channel'};
return {'status': 'notice', 'message': 'client already exists in channel'};
} else {
this.clients.push(client);
logger.accessLog.info('Added client to channel', {channelId: this.id, clientId: client.id});
@ -44,19 +67,6 @@ class ChannelBase {
return false;
}
broadcastMessage(from: ClientBase|null, message: string) {
for (let client of this.clients) {
if (client != from) {
client.ws.send(JSON.stringify(message));
logger.accessLog.info(`sent to ${client.id}`, { data: { message: message }});
} else {
logger.accessLog.info(`client is same as sender: ${client.id}`, { data: { message: message }});
}
}
return {'status': 'success', 'message': `message broadcast complete`};
}
};
export default ChannelBase;

View File

@ -0,0 +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())
}
}
messageTransactionPossible(from: CustomClient, to: CustomClient) {
return true
}
};
module.exports = CustomChannel;
export default CustomChannel;

View File

@ -4,18 +4,12 @@ import ChannelBase from '../channelBase';
var logger = require('../../logger');
class PrivateChannel extends ChannelBase {
broadcastMessage(from: PrivateClient, message: any) {
for (let client of this.clients) {
if (client != from && client.roles.includes('receiver') && from.roles.includes('broadcaster')) {
console.log('sending message: ' + JSON.stringify(message))
client.ws.send(JSON.stringify(message));
logger.accessLog.info(`sent to ${client.id}`, { data: { message: message }});
} else {
logger.accessLog.info(`client is either just a broadcaster or is the sender: ${client.id}`, { data: { message: message }});
}
}
return {'status': 'success', 'message': `message broadcast complete`};
messageTransactionPossible(from: PrivateClient, to: PrivateClient) {
return (
to != from &&
to.roles.includes('receiver') &&
from.roles.includes('broadcaster')
)
}
};

View File

@ -0,0 +1,15 @@
import PublicClient from '../../clients/types/publicClient';
import ChannelBase from '../channelBase';
var logger = require('../../logger');
class PublicChannel extends ChannelBase {
messageTransactionPossible(from: PublicClient, to: PublicClient) {
return (
to != from
)
}
};
module.exports = PublicChannel;
export default PublicChannel;

View File

@ -1,12 +1,13 @@
import * as WebSocket from 'ws';
import ClientBase from './clients/clientBase';
import PublicClient from './clients/types/publicClient';
import PrivateClient from './clients/types/privateClient';
import CustomClient from './clients/types/customClient';
import ChannelManager from './channelManager';
var logger = require('./logger');
class ClientManager {
clients: ClientBase[]|PrivateClient[] = [];
clients: PublicClient[]|PrivateClient[]|CustomClient[] = [];
constructor() {
//...maybe one day
@ -26,7 +27,7 @@ class ClientManager {
}
clientsOfType(client_type: string) {
var result: ClientBase[]|PrivateClient[] = [];
var result: PublicClient[]|PrivateClient[]|CustomClient[] = [];
for (let client of this.clients) {
if (client.type() == client_type) {
@ -76,7 +77,7 @@ class ClientManager {
} catch (e) {
logger.errorLog.info(e);
logger.accessLog.info(`creating base client: ${data.user_id}`);
return new ClientBase(data, ws, channelManager, this);
return new PublicClient(data, ws, channelManager, this);
}
}
};

View File

@ -1,8 +1,9 @@
import * as WebSocket from 'ws';
import ClientManager from '../clientManager';
import ChannelManager from '../channelManager';
import ChannelBase from '../channels/channelBase';
import Private from '../channels/types/privateChannel';
import PublicChannel from '../channels/types/publicChannel';
import PrivateChannel from '../channels/types/privateChannel';
import CustomChannel from '../channels/types/customChannel';
var messageManager = require('../messageManager');
var logger = require('../logger');
@ -11,7 +12,7 @@ class ClientBase {
ws: WebSocket;
data: any;
id: number;
channel: ChannelBase|Private|null;
channel: PublicChannel|PrivateChannel|CustomChannel|null;
clientManager: ClientManager;
channelManager: ChannelManager;
roles: Array<string>;
@ -26,6 +27,10 @@ class ClientBase {
this.roles = ['receiver']
}
validations() {
return {}
}
getData() {
return this.data;
}
@ -38,12 +43,12 @@ class ClientBase {
return this.data.client;
}
connectToChannel(channel: Private) {
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);
message = messageManager.prepareMessage(message, channel, this);
if (!message.error) {
if (message['message_type'] == 'broadcast') {

View File

@ -0,0 +1,17 @@
import ClientBase from '../clientBase';
import * as Joi from 'joi';
class CustomClient extends ClientBase {
// validations() {
// return {
// test: Joi.alternatives().try(Joi.string(), Joi.object())
// }
// }
validations() {
return { what: "test"}
}
};
module.exports = CustomClient;
export default CustomClient;

View File

@ -6,7 +6,6 @@ import ChannelManager from '../../channelManager';
var logger = require('../../logger');
class PrivateClient extends ClientBase {
constructor(data: any, ws: WebSocket, channelManager: ChannelManager, clientManager: ClientManager) {
super(data, ws, channelManager, clientManager);
this.roles = data.user_roles

View File

@ -0,0 +1,9 @@
import ClientBase from '../clientBase';
var logger = require('../../logger');
class PublicClient extends ClientBase {};
module.exports = PublicClient;
export default PublicClient;

View File

@ -1,21 +1,31 @@
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 = {
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()),
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}
};
module.exports = {
prepareMessage: (message: string) => {
prepareMessage: (message: string, channel: PublicChannel|PrivateChannel|CustomChannel, client: PublicClient|PrivateClient|CustomClient) => {
var parsed = JSON.parse(message)
const result = Joi.validate(parsed, schema);
const result = Joi.validate(parsed, schema(channel, client));
if (result.error) {
return result

View File

@ -14,7 +14,7 @@ var wsClient = new WebSocketClient();
var channel: ChannelBase;
var clientManager = new ClientManager();
var channelManager = new ChannelManager();
var data: any = { 'client': 'test', 'client_type':'site', 'user_id': 125, 'user_type': 'user', 'channel': name }
var data: any = { 'channel_type': 'private', 'client_type':'private', 'user_id': 125, 'user_roles': ['broadcaster', 'receiver'], 'channel': name }
var client: ClientBase = new ClientBase(data, wsClient, channelManager, clientManager);
describe('ChannelBase', function () {

View File

@ -8,7 +8,7 @@ var assert = require('chai').assert;
var sinon = require('sinon');
var name: string = 'test channel';
var data: any = { 'client': 'test', 'client_type':'site', 'user_id': 125, 'user_type': 'user', 'channel': name }
var data: any = { 'channel_type': 'private', 'client_type':'private', 'user_id': 125, 'user_roles': ['broadcaster', 'receiver'], 'channel': name }
var WebSocketClient = require('websocket').client;
var wsClient = new WebSocketClient();
var clientManager = new ClientManager();
@ -23,7 +23,7 @@ describe('ClientManager', function () {
});
it('should get clients of type', function () {
var result = clientManager.clientsOfType('site');
var result = clientManager.clientsOfType('private');
assert(result.length > 0, 'returns one client');
});
@ -52,7 +52,7 @@ describe('ClientManager', function () {
});
it('should add client of type PrivateClient', function () {
var data: any = { 'channel_type': 'private', 'client_type':'private', 'user_id': 125, 'user_roles': '["broadcaster", "receiver"]', 'channel': name }
var data: any = { 'channel_type': 'private', 'client_type': 'private', 'user_id': 125, 'user_roles': ['broadcaster', 'receiver'], 'channel': name }
var result = clientManager.getClientType(data, channelManager, wsClient);
expect(result.clientType()).to.be.equal('private');
});