240 lines
6.2 KiB
JavaScript
240 lines
6.2 KiB
JavaScript
const { Client } = require("../Client.js");
|
|
let {randomUUID} = require("crypto");
|
|
const joi = require("joi");
|
|
let {addService,addListener} = require("../WebSocket.js");
|
|
|
|
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(room.id, room);
|
|
};
|
|
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);
|
|
}
|
|
};
|
|
/**
|
|
* @param {Client} client
|
|
*/
|
|
Room.prototype.join = function(client){
|
|
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);
|
|
};
|
|
Room.prototype.active = function(){
|
|
Room.rooms.set(this.id, this);
|
|
};
|
|
Room.prototype.deactive = function(){
|
|
Room.rooms.delete(this.id);
|
|
};
|
|
/**
|
|
* @param {Client} client
|
|
*/
|
|
Room.prototype.eject = function(client){
|
|
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);
|
|
};
|
|
|
|
/**
|
|
* @type {Map<string, Room>}
|
|
*/
|
|
Room.rooms = new Map();
|
|
|
|
addListener('connect',(global, client)=>{
|
|
let room = new Room();
|
|
room.accessType = "private";
|
|
room.joinType = "notify";
|
|
room.clients.set(client.id, client);
|
|
room.description = 'Yourself private room, you can invite friends';
|
|
room.id = client.id;
|
|
room.name = "Your Room";
|
|
room.owner = client;
|
|
room.join(client);
|
|
room.active();
|
|
});
|
|
|
|
addListener('disconnect',(global, client)=>{
|
|
for (const roomId of client.rooms) {
|
|
Room.rooms.get(roomId).eject(client);
|
|
Room.rooms.get(roomId).deactive();
|
|
}
|
|
});
|
|
|
|
|
|
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 'create-room':{
|
|
let {error} = CreateRoomVerify.validate(message);
|
|
if(error)
|
|
{
|
|
return end({
|
|
status: 'fail',
|
|
messages: error.message
|
|
})
|
|
}else{
|
|
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.active();
|
|
end(room.toJSON())
|
|
}
|
|
break;
|
|
}
|
|
case 'join':{
|
|
let isRoom = Room.rooms.has(client.id);
|
|
if(isRoom)
|
|
{
|
|
let room = Room.rooms.get(client.id);
|
|
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);
|
|
}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; |