302 lines
8.3 KiB
JavaScript
302 lines
8.3 KiB
JavaScript
const { Client } = require("../Client.js");
|
|
let {randomUUID} = require("crypto");
|
|
const joi = require("joi");
|
|
let {addService,addListener} = require("../WebSocket.js");
|
|
let term = require("terminal-kit").terminal;
|
|
|
|
function Room()
|
|
{
|
|
/**
|
|
* @type {string}
|
|
*/
|
|
this.id = randomUUID();
|
|
/**
|
|
* @type {string}
|
|
*/
|
|
this.name = "";
|
|
/**
|
|
* @type {string}
|
|
*/
|
|
this.description = "";
|
|
/**
|
|
* @type {Client}
|
|
*/
|
|
this.owner = null;
|
|
/**
|
|
* @type {Date}
|
|
*/
|
|
this.createdAt = new Date();
|
|
/**
|
|
* @type {Map<string, Client>}
|
|
*/
|
|
this.clients = new Map();
|
|
/**
|
|
* @type {"public"|"private"}
|
|
*/
|
|
this.accessType = "";
|
|
/**
|
|
* @type {"free"|"invite"|"password"|"lock"}
|
|
*/
|
|
this.joinType = "invite";
|
|
/**
|
|
* @type {boolean}
|
|
*/
|
|
this.notifyActionInvite = false;
|
|
/**
|
|
* @type {boolean}
|
|
*/
|
|
this.notifyActionJoined = true;
|
|
/**
|
|
* @type {boolean}
|
|
*/
|
|
this.notifyActionEjected = true;
|
|
/**
|
|
* @type {string}
|
|
*/
|
|
this.password = null;
|
|
/**
|
|
* @type {string[]}
|
|
*/
|
|
this.waitingInvited = new Set();
|
|
}
|
|
/**
|
|
* @param {Room} room
|
|
*/
|
|
Room.prototype.publish = function(room){
|
|
Room.rooms.set(this.id, this);
|
|
term.green("Room Published ").white(this.name," in ").yellow(this.clients.size).white(" clients")('\n');
|
|
};
|
|
Room.prototype.toJSON = function(){
|
|
let obj = {};
|
|
obj.id = this.id;
|
|
obj.accessType = this.accessType;
|
|
obj.createdAt = this.createdAt;
|
|
obj.description = this.description;
|
|
obj.joinType = this.joinType;
|
|
obj.name = this.name;
|
|
obj.owner = this.owner.id;
|
|
obj.waitingInvited = [...this.waitingInvited];
|
|
return obj;
|
|
};
|
|
Room.prototype.send = function(obj){
|
|
for (const client of this.clients.values()) {
|
|
client.send(obj);
|
|
}
|
|
term.green("Room bulk message ").white(this.name," in ").yellow(this.clients.size + "").white(" clients")('\n');
|
|
};
|
|
/**
|
|
* @param {Client} client
|
|
*/
|
|
Room.prototype.join = function(client){
|
|
if(this.notifyActionJoined)
|
|
{
|
|
this.send([{
|
|
id: client.id,
|
|
roomid: this.id,
|
|
ownerid: this.owner.id
|
|
},'room/joined']);
|
|
};
|
|
client.rooms.add(this.id);
|
|
this.clients.set(client.id, client);
|
|
term.green("Client Room joined ").white(this.name," in ").yellow(this.clients.size + "").white(" clients")('\n');
|
|
};
|
|
Room.prototype.down = function(){
|
|
term.red("Room is downed ").red(this.name," in ").yellow(this.clients.size + "").red(" clients")('\n');
|
|
this.send([{
|
|
id: client.id,
|
|
roomid: this.id,
|
|
ownerid: this.owner.id
|
|
},'room/closed']);
|
|
Room.rooms.delete(this.id);
|
|
};
|
|
/**
|
|
* @param {Client} client
|
|
*/
|
|
Room.prototype.eject = function(client){
|
|
if(this.notifyActionEjected)
|
|
{
|
|
this.send([{
|
|
id: client.id,
|
|
roomid: this.id,
|
|
ownerid: this.owner.id
|
|
},'room/ejected']);
|
|
}
|
|
client.rooms.delete(this.id);
|
|
this.clients.delete(client.id);
|
|
term.red("Client Room ejected ").red(this.name," in ").yellow(this.clients.size + "").red(" clients")('\n');
|
|
};
|
|
|
|
/**
|
|
* @type {Map<string, Room>}
|
|
*/
|
|
Room.rooms = new Map();
|
|
|
|
addListener('connect',(global, client)=>{
|
|
let room = new Room();
|
|
room.accessType = "private";
|
|
room.joinType = "notify";
|
|
room.description = 'Yourself private room, you can invite friends';
|
|
room.id = client.id;
|
|
room.name = "Your Room | " + client.id;
|
|
room.owner = client;
|
|
room.join(client);
|
|
room.publish();
|
|
});
|
|
|
|
addListener('disconnect',(global, client)=>{
|
|
Room.rooms.get(client.id).eject(client);
|
|
for (const roomId of client.rooms) {
|
|
Room.rooms.get(roomId).eject(client);
|
|
}
|
|
});
|
|
|
|
|
|
let CreateRoomVerify = joi.object({
|
|
type: joi.any().required(),
|
|
accessType: joi.string().pattern(/^public$|private$/).required(),
|
|
notifyActionInvite: joi.boolean().required(),
|
|
notifyActionJoined: joi.boolean().required(),
|
|
notifyActionEjected: joi.boolean().required(),
|
|
joinType: joi.string().pattern(/^free$|^invite$|^password$|^lock$/).required(),
|
|
description: joi.string().required(),
|
|
name: joi.string().required()
|
|
});
|
|
|
|
addService(({
|
|
client,
|
|
end,
|
|
global,
|
|
message,
|
|
next,
|
|
response
|
|
})=>{
|
|
let {type} = message;
|
|
switch(type)
|
|
{
|
|
case 'myroom-info':{
|
|
let room = Room.rooms.get(client.id);
|
|
end(room.toJSON())
|
|
break;
|
|
}
|
|
case 'room-info':{
|
|
let {name} = message;
|
|
for (const [roomId,{name:RoomName}] of Room.rooms) {
|
|
if(name == RoomName)
|
|
{
|
|
return end({
|
|
status : "success",
|
|
room : Room.rooms.get(roomId).toJSON()
|
|
})
|
|
}
|
|
};
|
|
return end({
|
|
status : "fail",
|
|
message : "NOT-FOUND-ROOM"
|
|
})
|
|
break;
|
|
}
|
|
case 'joinedrooms':{
|
|
let data = [
|
|
...client.rooms
|
|
].map(e => {
|
|
return Room.rooms.get(e).toJSON()
|
|
});
|
|
end(data)
|
|
break;
|
|
}
|
|
case 'create-room':{
|
|
let {error} = CreateRoomVerify.validate(message);
|
|
if(error)
|
|
{
|
|
return end({
|
|
status: 'fail',
|
|
messages: error.message
|
|
})
|
|
}else{
|
|
let {name} = message;
|
|
for (const [,{name:RoomName}] of Room.rooms) {
|
|
if(name == RoomName)
|
|
{
|
|
return end({
|
|
status : "fail",
|
|
message : "ALREADY-EXISTS"
|
|
})
|
|
}
|
|
}
|
|
let room = new Room();
|
|
room.accessType = message.accessType;
|
|
room.notifyActionInvite = message.notifyActionInvite;
|
|
room.notifyActionJoined = message.notifyActionJoined;
|
|
room.notifyActionEjected = message.notifyActionEjected;
|
|
room.joinType = message.joinType;
|
|
room.description = message.description;
|
|
room.name = message.name;
|
|
room.owner = client;
|
|
room.join(client);
|
|
room.publish();
|
|
end({
|
|
status: "success",
|
|
room: room.toJSON()
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case 'joinroom':{
|
|
let {name} = message;
|
|
let roomId;
|
|
for (const [_roomId,{name:RoomName}] of Room.rooms) {
|
|
if(name == RoomName)
|
|
{
|
|
roomId = _roomId
|
|
break;
|
|
}
|
|
}
|
|
let isRoom = Room.rooms.has(roomId);
|
|
if(isRoom)
|
|
{
|
|
let room = Room.rooms.get(roomId);
|
|
if(room.joinType == "lock")
|
|
{
|
|
return end({
|
|
status : "fail",
|
|
message : "LOCKED-ROOM"
|
|
})
|
|
}else if(room.joinType == "password")
|
|
{
|
|
if(room.password == message.credential)
|
|
{
|
|
room.join(client);
|
|
return end({status : "success"})
|
|
}else return end({
|
|
status : "fail",
|
|
message : "WRONG-PASSWORD"
|
|
})
|
|
}else if(room.joinType == "free"){
|
|
room.join(client);
|
|
return end({status : "success"})
|
|
}else if(room.joinType == "invite"){
|
|
room.waitingInvited.add(client.id);
|
|
if(room.notifyActionInvite)
|
|
{
|
|
room.send([{
|
|
id: client.id
|
|
},"room/invite"]);
|
|
}else{
|
|
room.owner.send([{
|
|
id: client.id
|
|
},"room/invite"]);
|
|
}
|
|
};
|
|
}else{
|
|
return end({
|
|
status : "fail",
|
|
message : "NOT-FOUND-ROOM"
|
|
})
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
exports.Room = Room; |