forked from Hri7566/mpp-server-dev2
major update
This commit is contained in:
parent
2887369331
commit
784853a7c7
|
@ -1,3 +1,4 @@
|
|||
.env
|
||||
node_modules
|
||||
ssl/
|
||||
src/db/users.json
|
||||
|
|
|
@ -3,10 +3,10 @@ module.exports = Object.seal({
|
|||
motd: "big th0nk",
|
||||
_id_PrivateKey: process.env.SALT,
|
||||
defaultUsername: "Anonymous",
|
||||
//defaultRoomColor: "#3b5054",
|
||||
defaultRoomColor: "#9900ff",
|
||||
// defaultRoomColor: "#3b5054",
|
||||
defaultRoomColor: "#000000",
|
||||
// defaultLobbyColor: "#19b4b9",
|
||||
defaultLobbyColor: "#5e32a8",
|
||||
defaultLobbyColor: "#9900ff",
|
||||
// defaultLobbyColor2: "#801014",
|
||||
defaultLobbyColor2: "#801014",
|
||||
adminpass: process.env.ADMINPASS,
|
||||
|
|
20
index.js
20
index.js
|
@ -1,26 +1,31 @@
|
|||
// dotenv to keep secret variables in (they won't show on github)
|
||||
// dotenv
|
||||
require('dotenv').config();
|
||||
|
||||
//call new Server
|
||||
// call new Server
|
||||
global.WebSocket = require('ws');
|
||||
global.EventEmitter = require('events').EventEmitter;
|
||||
global.fs = require('fs');
|
||||
global.createKeccakHash = require('keccak');
|
||||
const AsyncConsole = require('asyncconsole')
|
||||
const AsyncConsole = require('asyncconsole');
|
||||
|
||||
global.isString = function(a){
|
||||
global.isString = function(a) {
|
||||
return typeof a === 'string';
|
||||
}
|
||||
global.isBool = function(a){
|
||||
|
||||
global.isBool = function(a) {
|
||||
return typeof a === 'boolean';
|
||||
}
|
||||
global.isObj = function(a){
|
||||
|
||||
global.isObj = function(a) {
|
||||
return typeof a === "object" && !Array.isArray(a) && a !== null;
|
||||
}
|
||||
|
||||
let Server = require("./src/Server.js");
|
||||
let config = require('./config');
|
||||
global.SERVER = new Server(config);
|
||||
|
||||
// below commented because it doesn't work with pm2
|
||||
|
||||
/*
|
||||
let console = process.platform == 'win32' ? new AsyncConsole("", input => {
|
||||
try {
|
||||
console.log(JSON.stringify(eval(input)));
|
||||
|
@ -28,3 +33,4 @@ let console = process.platform == 'win32' ? new AsyncConsole("", input => {
|
|||
console.log(e.toString());
|
||||
}
|
||||
}) : {};
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"ignore": [
|
||||
"**/*.json"
|
||||
]
|
||||
}
|
|
@ -3,42 +3,55 @@ const Quota = require ("./Quota.js");
|
|||
const quotas = require('../Quotas');
|
||||
const RateLimit = require('./Ratelimit.js').RateLimit;
|
||||
const RateLimitChain = require('./Ratelimit.js').RateLimitChain;
|
||||
const User = require("./User.js");
|
||||
const Database = require("./Database.js");
|
||||
require('node-json-color-stringify');
|
||||
|
||||
class Client extends EventEmitter {
|
||||
constructor(ws, req, server) {
|
||||
super();
|
||||
EventEmitter.call(this);
|
||||
this.user;
|
||||
this.connectionid = server.connectionid;
|
||||
this.server = server;
|
||||
this.participantId;
|
||||
this.channel;
|
||||
|
||||
this.staticQuotas = {
|
||||
room: new RateLimit(quotas.room.time)
|
||||
};
|
||||
|
||||
this.quotas = {};
|
||||
this.ws = ws;
|
||||
this.req = req;
|
||||
this.ip = (req.connection.remoteAddress).replace("::ffff:", "");
|
||||
this.destroied = false;
|
||||
this.bindEventListeners();
|
||||
require('./Message.js')(this);
|
||||
|
||||
Database.getUserData(this, server).then(data => {
|
||||
this.user = new User(this, data);
|
||||
this.destroied = false;
|
||||
this.bindEventListeners();
|
||||
require('./Message.js')(this);
|
||||
});
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return this.ws && this.ws.readyState === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
isConnecting() {
|
||||
return this.ws && this.ws.readyState === WebSocket.CONNECTING;
|
||||
}
|
||||
|
||||
setChannel(_id, settings) {
|
||||
if (this.channel && this.channel._id == _id) return;
|
||||
if (this.server.rooms.get(_id)) {
|
||||
let room = this.server.rooms.get(_id, settings);
|
||||
let userbanned = room.bans.get(this.user._id);
|
||||
|
||||
if (userbanned && (Date.now() - userbanned.bannedtime >= userbanned.msbanned)) {
|
||||
room.bans.delete(userbanned.user._id);
|
||||
userbanned = undefined;
|
||||
}
|
||||
|
||||
if (userbanned) {
|
||||
room.Notification(this.user._id,
|
||||
"Notice",
|
||||
|
@ -51,9 +64,11 @@ class Client extends EventEmitter {
|
|||
this.setChannel("test/awkward", settings);
|
||||
return;
|
||||
}
|
||||
|
||||
let channel = this.channel;
|
||||
if (channel) this.channel.emit("bye", this);
|
||||
if (channel) this.channel.updateCh();
|
||||
if (channel) this.channel.updateCh(this);
|
||||
|
||||
this.channel = this.server.rooms.get(_id);
|
||||
this.channel.join(this);
|
||||
} else {
|
||||
|
@ -61,7 +76,7 @@ class Client extends EventEmitter {
|
|||
this.server.rooms.set(_id, room);
|
||||
if (this.channel) this.channel.emit("bye", this);
|
||||
this.channel = this.server.rooms.get(_id);
|
||||
this.channel.join(this);
|
||||
this.channel.join(this, settings);
|
||||
}
|
||||
}
|
||||
sendArray(arr) {
|
||||
|
@ -70,6 +85,7 @@ class Client extends EventEmitter {
|
|||
this.ws.send(JSON.stringify(arr));
|
||||
}
|
||||
}
|
||||
|
||||
initParticipantQuotas() {
|
||||
this.quotas = {
|
||||
//"chat": new Quota(Quota.PARAMS_A_NORMAL),
|
||||
|
@ -88,6 +104,7 @@ class Client extends EventEmitter {
|
|||
"-ls": new Quota(Quota.PARAMS_USED_A_LOT)
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.ws.close();
|
||||
if (this.channel) {
|
||||
|
@ -102,6 +119,7 @@ class Client extends EventEmitter {
|
|||
this.destroied = true;
|
||||
console.log(`Removed Connection ${this.connectionid}.`);
|
||||
}
|
||||
|
||||
bindEventListeners() {
|
||||
this.ws.on("message", (evt, admin) => {
|
||||
try {
|
||||
|
@ -120,14 +138,17 @@ class Client extends EventEmitter {
|
|||
}
|
||||
});
|
||||
this.ws.on("close", () => {
|
||||
if (!this.destroied)
|
||||
if (!this.destroied) {
|
||||
this.destroy();
|
||||
}
|
||||
});
|
||||
this.ws.addEventListener("error", (err) => {
|
||||
console.error(err);
|
||||
if (!this.destroied)
|
||||
if (!this.destroied) {
|
||||
this.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Client;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
const fs = require('fs');
|
||||
const { promisify } = require('util');
|
||||
const createKeccakHash = require('keccak');
|
||||
const ColorEncoder = require('./ColorEncoder');
|
||||
|
||||
class Database {
|
||||
static userdb;
|
||||
|
||||
static async load() {
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
const readdir = promisify(fs.readdir);
|
||||
|
||||
let files = await readdir("src/db/");
|
||||
if (!files.includes("users.json")) {
|
||||
await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2))
|
||||
this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
} else {
|
||||
this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
}
|
||||
}
|
||||
|
||||
static async getUserData(cl, server) {
|
||||
if (!this.userdb || (this.userdb instanceof Map && [...this.userdb.entries()] == [])) {
|
||||
await this.load();
|
||||
}
|
||||
|
||||
let _id = createKeccakHash('keccak256').update((cl.server._id_Private_Key + cl.ip)).digest('hex').substr(0, 24);
|
||||
let usertofind = this.userdb.get(_id);
|
||||
|
||||
if (!usertofind) {
|
||||
if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return;
|
||||
|
||||
this.userdb.set(_id, {
|
||||
"color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`,
|
||||
"name": server.defaultUsername,
|
||||
"_id": _id,
|
||||
"ip": cl.ip
|
||||
});
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
let user = this.userdb.get(_id);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
static async update() {
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
await writeFile('src/db/users.json', JSON.stringify(this.strMapToObj(this.userdb), null, 2));
|
||||
}
|
||||
|
||||
static strMapToObj(strMap) {
|
||||
return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Database;
|
117
src/Message.js
117
src/Message.js
|
@ -1,20 +1,27 @@
|
|||
const Quota = require('./Quota');
|
||||
const User = require("./User.js");
|
||||
const Room = require("./Room.js");
|
||||
const RoomSettings = require('./RoomSettings');
|
||||
|
||||
module.exports = (cl) => {
|
||||
cl.once("hi", () => {
|
||||
let user = new User(cl);
|
||||
user.getUserData().then((data) => {
|
||||
let msg = {};
|
||||
msg.m = "hi";
|
||||
msg.motd = cl.server.welcome_motd;
|
||||
msg.t = Date.now();
|
||||
msg.u = data;
|
||||
msg.v = "Beta";
|
||||
cl.sendArray([msg])
|
||||
cl.user = data;
|
||||
})
|
||||
})
|
||||
cl.once("hi", msg => {
|
||||
let m = {};
|
||||
|
||||
m.m = "hi";
|
||||
m.motd = cl.server.welcome_motd;
|
||||
m.t = Date.now();
|
||||
m.u = {
|
||||
name: cl.user.name,
|
||||
_id: cl.user._id,
|
||||
id: cl.participantId,
|
||||
color: cl.user.color
|
||||
};
|
||||
|
||||
m.v = "https://gitlab.com/hri7566/mpp-server";
|
||||
|
||||
cl.sendArray([m]);
|
||||
});
|
||||
|
||||
cl.on("t", msg => {
|
||||
if (msg.hasOwnProperty("e") && !isNaN(msg.e))
|
||||
cl.sendArray([{
|
||||
|
@ -22,13 +29,17 @@ module.exports = (cl) => {
|
|||
t: Date.now(),
|
||||
e: msg.e
|
||||
}])
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("ch", msg => {
|
||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
||||
if (typeof(msg.set) !== 'object') msg.set = {};
|
||||
|
||||
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
||||
if (msg._id.length > 512) return;
|
||||
if (!cl.staticQuotas.room.attempt()) return;
|
||||
|
||||
cl.setChannel(msg._id, msg.set);
|
||||
|
||||
let param;
|
||||
if (cl.channel.isLobby(cl.channel._id)) {
|
||||
param = Quota.N_PARAMS_LOBBY;
|
||||
|
@ -39,10 +50,12 @@ module.exports = (cl) => {
|
|||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
}
|
||||
}
|
||||
|
||||
param.m = "nq";
|
||||
cl.sendArray([param])
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("m", (msg, admin) => {
|
||||
// if (!cl.quotas.cursor.attempt() && !admin) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
|
@ -50,43 +63,63 @@ module.exports = (cl) => {
|
|||
if (!msg.hasOwnProperty("y")) msg.y = null;
|
||||
if (parseInt(msg.x) == NaN) msg.x = null;
|
||||
if (parseInt(msg.y) == NaN) msg.y = null;
|
||||
cl.channel.emit("m", cl, msg.x, msg.y)
|
||||
cl.channel.emit("m", cl, msg.x, msg.y);
|
||||
});
|
||||
|
||||
})
|
||||
cl.on("chown", (msg, admin) => {
|
||||
if (!cl.quotas.chown.attempt() && !admin) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
|
||||
//console.log((Date.now() - cl.channel.crown.time))
|
||||
//console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000));
|
||||
|
||||
if (!(cl.channel.crown.userId == cl.user._id) && !((Date.now() - cl.channel.crown.time) > 15000)) return;
|
||||
|
||||
if (msg.hasOwnProperty("id")) {
|
||||
// console.log(cl.channel.crown)
|
||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
||||
if (!admin) {
|
||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) {
|
||||
cl.channel.chown(msg.id);
|
||||
if (msg.id == cl.user.id) {
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cl.channel.chown(msg.id);
|
||||
if (msg.id == cl.user.id) {
|
||||
param = Quota.N_PARAMS_RIDICULOUS;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
||||
if (!admin) {
|
||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) {
|
||||
cl.channel.chown();
|
||||
param = Quota.N_PARAMS_NORMAL;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param])
|
||||
}
|
||||
} else {
|
||||
cl.channel.chown();
|
||||
param = Quota.N_PARAMS_NORMAL;
|
||||
param.m = "nq";
|
||||
cl.sendArray([param])
|
||||
cl.sendArray([param]);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("chset", msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!cl.channel.crown) return;
|
||||
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{});
|
||||
Object.keys(cl.channel.settings).forEach(key => {
|
||||
if (cl.channel.settings[key] !== msg.set[key]) {
|
||||
cl.channel.settings[key] = msg.set[key];
|
||||
}
|
||||
});
|
||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = new RoomSettings(cl.channel.settings, 'user');
|
||||
cl.channel.settings.changeSettings(msg.set);
|
||||
cl.channel.updateCh();
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("a", (msg, admin) => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty('message')) return;
|
||||
|
@ -102,7 +135,8 @@ module.exports = (cl) => {
|
|||
}
|
||||
cl.channel.emit('a', cl, msg);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on('n', msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty('t') || !msg.hasOwnProperty('n')) return;
|
||||
|
@ -114,7 +148,8 @@ module.exports = (cl) => {
|
|||
} else {
|
||||
cl.channel.playNote(cl, msg);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on('+ls', msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
cl.server.roomlisteners.set(cl.connectionid, cl);
|
||||
|
@ -131,11 +166,13 @@ module.exports = (cl) => {
|
|||
"c": true,
|
||||
"u": rooms
|
||||
}])
|
||||
})
|
||||
});
|
||||
|
||||
cl.on('-ls', msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
cl.server.roomlisteners.delete(cl.connectionid);
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("userset", msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
||||
|
@ -157,7 +194,8 @@ module.exports = (cl) => {
|
|||
})
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on('kickban', msg => {
|
||||
if (cl.channel.crown == null) return;
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
|
@ -169,17 +207,20 @@ module.exports = (cl) => {
|
|||
let ms = msg.ms || 3600000;
|
||||
cl.channel.kickban(_id, ms);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("bye", msg => {
|
||||
cl.destroy();
|
||||
})
|
||||
});
|
||||
|
||||
cl.on("admin message", msg => {
|
||||
if (!(cl.channel && cl.participantId)) return;
|
||||
if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return;
|
||||
if (typeof msg.msg != 'object') return;
|
||||
if (msg.password !== cl.server.adminpass) return;
|
||||
cl.ws.emit("message", JSON.stringify([msg.msg]), true);
|
||||
})
|
||||
});
|
||||
|
||||
//admin only stuff
|
||||
cl.on('color', (msg, admin) => {
|
||||
if (!admin) return;
|
||||
|
|
133
src/Room.js
133
src/Room.js
|
@ -2,7 +2,11 @@
|
|||
//room class
|
||||
//room deleter
|
||||
//databases in Map
|
||||
|
||||
const createKeccakHash = require('keccak');
|
||||
const Quota = require("./Quota.js");
|
||||
const RoomSettings = require('./RoomSettings.js');
|
||||
|
||||
class Room extends EventEmitter {
|
||||
constructor(server, _id, settings) {
|
||||
super();
|
||||
|
@ -11,9 +15,7 @@ class Room extends EventEmitter {
|
|||
this.server = server;
|
||||
this.crown = null;
|
||||
this.crowndropped = false;
|
||||
this.settings = this.verifySet(this._id, {
|
||||
set: settings
|
||||
});
|
||||
this.settings = settings;
|
||||
this.chatmsgs = [];
|
||||
this.ppl = new Map();
|
||||
this.connections = [];
|
||||
|
@ -21,14 +23,15 @@ class Room extends EventEmitter {
|
|||
this.server.rooms.set(_id, this);
|
||||
this.bans = new Map();
|
||||
}
|
||||
join(cl) { //this stuff is complicated
|
||||
|
||||
join(cl, set) { //this stuff is complicated
|
||||
let otheruser = this.connections.find((a) => a.user._id == cl.user._id)
|
||||
if (!otheruser) {
|
||||
let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24);
|
||||
cl.user.id = participantId;
|
||||
cl.participantId = participantId;
|
||||
cl.initParticipantQuotas();
|
||||
if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && !this.isLobby(this._id)) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown.
|
||||
if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown.
|
||||
//cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED);
|
||||
this.crown = {
|
||||
participantId: cl.participantId,
|
||||
|
@ -43,15 +46,29 @@ class Room extends EventEmitter {
|
|||
y: this.getCrownY()
|
||||
}
|
||||
}
|
||||
|
||||
this.crowndropped = false;
|
||||
this.settings = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false};
|
||||
this.settings = new RoomSettings(set, 'user');
|
||||
} else {
|
||||
//cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL);
|
||||
this.settings = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false,lobby:true};
|
||||
console.log(this.isLobby(this._id));
|
||||
|
||||
if (this.isLobby(this._id)) {
|
||||
this.settings = new RoomSettings(this.server.lobbySettings, 'user');
|
||||
this.settings.visible = true;
|
||||
this.settings.crownsolo = false;
|
||||
this.settings.color = this.server.lobbySettings.color;
|
||||
this.settings.color2 = this.server.lobbySettings.color2;
|
||||
this.settings.lobby = true;
|
||||
} else {
|
||||
this.settings = new RoomSettings(set, 'user');
|
||||
}
|
||||
}
|
||||
|
||||
this.ppl.set(participantId, cl);
|
||||
|
||||
this.connections.push(cl);
|
||||
|
||||
this.sendArray([{
|
||||
color: this.ppl.get(cl.participantId).user.color,
|
||||
id: this.ppl.get(cl.participantId).participantId,
|
||||
|
@ -79,6 +96,7 @@ class Room extends EventEmitter {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
remove(p) { //this is complicated too
|
||||
let otheruser = this.connections.filter((a) => a.user._id == p.user._id);
|
||||
if (!(otheruser.length > 1)) {
|
||||
|
@ -99,31 +117,40 @@ class Room extends EventEmitter {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
updateCh(cl) { //update channel for all people in channel
|
||||
if (Array.from(this.ppl.values()).length <= 0) {
|
||||
setTimeout(() => {
|
||||
this.destroy();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
this.connections.forEach((usr) => {
|
||||
this.server.connections.get(usr.connectionid).sendArray([this.fetchData(usr, cl)])
|
||||
})
|
||||
});
|
||||
|
||||
this.server.updateRoom(this.fetchData());
|
||||
}
|
||||
|
||||
updateParticipant(pid, options) {
|
||||
let p = null;
|
||||
let p;
|
||||
|
||||
Array.from(this.ppl).map(rpg => {
|
||||
if(rpg[1].user._id == pid) p = rpg[1];
|
||||
if (rpg[1].user._id == pid) p = rpg[1];
|
||||
});
|
||||
if (p == null) return;
|
||||
|
||||
if (typeof(p) == 'undefined') return;
|
||||
|
||||
options.name ? p.user.name = options.name : {};
|
||||
options._id ? p.user._id = options._id : {};
|
||||
options.color ? p.user.color = options.color : {};
|
||||
|
||||
this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => {
|
||||
options.name ? usr.user.name = options.name : {};
|
||||
options._id ? usr.user._id = options._id : {};
|
||||
options.color ? usr.user.color = options.color : {};
|
||||
})
|
||||
});
|
||||
|
||||
this.sendArray([{
|
||||
color: p.user.color,
|
||||
id: p.participantId,
|
||||
|
@ -132,17 +159,20 @@ class Room extends EventEmitter {
|
|||
x: p.x || 200,
|
||||
y: p.y || 100,
|
||||
_id: p.user._id
|
||||
}])
|
||||
}]);
|
||||
}
|
||||
|
||||
destroy() { //destroy room
|
||||
if (this.ppl.size > 0) return;
|
||||
this._id;
|
||||
console.log(`Deleted room ${this._id}`);
|
||||
this.settings = {};
|
||||
this.settings = undefined;
|
||||
this.ppl;
|
||||
this.connnections;
|
||||
this.chatmsgs;
|
||||
this.server.rooms.delete(this._id);
|
||||
}
|
||||
|
||||
sendArray(arr, not, onlythisparticipant) {
|
||||
this.connections.forEach((usr) => {
|
||||
if (!not || (usr.participantId != not.participantId && !onlythisparticipant) || (usr.connectionid != not.connectionid && onlythisparticipant)) {
|
||||
|
@ -152,13 +182,16 @@ class Room extends EventEmitter {
|
|||
console.log(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fetchData(usr, cl) {
|
||||
let chppl = [];
|
||||
|
||||
[...this.ppl.values()].forEach((a) => {
|
||||
chppl.push(a.user);
|
||||
})
|
||||
});
|
||||
|
||||
let data = {
|
||||
m: "ch",
|
||||
p: "ofo",
|
||||
|
@ -170,6 +203,7 @@ class Room extends EventEmitter {
|
|||
},
|
||||
ppl: chppl
|
||||
}
|
||||
|
||||
if (cl) {
|
||||
if (usr.connectionid == cl.connectionid) {
|
||||
data.p = cl.participantId;
|
||||
|
@ -179,13 +213,16 @@ class Room extends EventEmitter {
|
|||
} else {
|
||||
delete data.p;
|
||||
}
|
||||
|
||||
if (data.ch.crown == null) {
|
||||
delete data.ch.crown;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
verifyColor(strColor) {
|
||||
var test2 = /^#[0-9A-F]{6}$/i.test(strColor);
|
||||
if (test2 == true) {
|
||||
|
@ -194,6 +231,7 @@ class Room extends EventEmitter {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isLobby(_id) {
|
||||
if (_id.startsWith("lobby")) {
|
||||
if (_id == "lobby") {
|
||||
|
@ -221,12 +259,15 @@ class Room extends EventEmitter {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
getCrownY() {
|
||||
return 50 - 30;
|
||||
return Math.floor(Math.random() * 10000) / 100;
|
||||
}
|
||||
|
||||
getCrownX() {
|
||||
return 50;
|
||||
return Math.floor(Math.random() * 10000) / 100;
|
||||
}
|
||||
|
||||
chown(id) {
|
||||
let prsn = this.ppl.get(id);
|
||||
if (prsn) {
|
||||
|
@ -259,9 +300,11 @@ class Room extends EventEmitter {
|
|||
}
|
||||
this.crowndropped = true;
|
||||
}
|
||||
|
||||
this.updateCh();
|
||||
}
|
||||
setCords(p, x, y) {
|
||||
|
||||
setCoords(p, x, y) {
|
||||
if (p.participantId && this.ppl.get(p.participantId)) {
|
||||
x ? this.ppl.get(p.participantId).x = x : {};
|
||||
y ? this.ppl.get(p.participantId).y = y : {};
|
||||
|
@ -273,6 +316,7 @@ class Room extends EventEmitter {
|
|||
}], p, false);
|
||||
}
|
||||
}
|
||||
|
||||
chat(p, msg) {
|
||||
if (msg.message.length > 512) return;
|
||||
let filter = ["AMIGHTYWIND"];
|
||||
|
@ -309,6 +353,7 @@ class Room extends EventEmitter {
|
|||
this.chatmsgs.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
playNote(cl, note) {
|
||||
this.sendArray([{
|
||||
m: "n",
|
||||
|
@ -317,6 +362,7 @@ class Room extends EventEmitter {
|
|||
t: note.t
|
||||
}], cl, true);
|
||||
}
|
||||
|
||||
kickban(_id, ms) {
|
||||
ms = parseInt(ms);
|
||||
if (ms >= (1000 * 60 * 60)) return;
|
||||
|
@ -365,6 +411,7 @@ class Room extends EventEmitter {
|
|||
|
||||
})
|
||||
}
|
||||
|
||||
Notification(who, title, text, html, duration, target, klass, id) {
|
||||
let obj = {
|
||||
m: "notification",
|
||||
|
@ -410,7 +457,7 @@ class Room extends EventEmitter {
|
|||
})
|
||||
|
||||
this.on("m", (participant, x, y) => {
|
||||
this.setCords(participant, x, y);
|
||||
this.setCoords(participant, x, y);
|
||||
})
|
||||
|
||||
this.on("a", (participant, msg) => {
|
||||
|
@ -418,37 +465,27 @@ class Room extends EventEmitter {
|
|||
})
|
||||
}
|
||||
|
||||
verifySet(_id,msg){
|
||||
if(!isObj(msg.set)) msg.set = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false};
|
||||
if(isBool(msg.set.lobby)){
|
||||
if(!this.isLobby(_id)) delete msg.set.lobby; // keep it nice and clean
|
||||
}else{
|
||||
if(this.isLobby(_id)) msg.set = {visible:true,color:this.server.defaultLobbyColor,color2:this.server.defaultLobbyColor2,chat:true,crownsolo:false,lobby:true};
|
||||
verifySet(_id, msg){
|
||||
if(typeof(msg.set) !== 'object') {
|
||||
msg.set = {
|
||||
visible: true,
|
||||
color: this.server.defaultSettings.color, chat:true,
|
||||
crownsolo:false
|
||||
}
|
||||
}
|
||||
if(!isBool(msg.set.visible)){
|
||||
if(msg.set.visible == undefined) msg.set.visible = (!isObj(this.settings) ? true : this.settings.visible);
|
||||
else msg.set.visible = true;
|
||||
};
|
||||
if(!isBool(msg.set.chat)){
|
||||
if(msg.set.chat == undefined) msg.set.chat = (!isObj(this.settings) ? true : this.settings.chat);
|
||||
else msg.set.chat = true;
|
||||
};
|
||||
if(!isBool(msg.set.crownsolo)){
|
||||
if(msg.set.crownsolo == undefined) msg.set.crownsolo = (!isObj(this.settings) ? false : this.settings.crownsolo);
|
||||
else msg.set.crownsolo = false;
|
||||
};
|
||||
if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (!isObj(this.settings) ? this.server.defaultRoomColor : this.settings.color);
|
||||
if(isString(msg.set.color2)){
|
||||
if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){
|
||||
if(this.settings){
|
||||
if(this.settings.color2) msg.set.color2 = this.settings.color2;
|
||||
else delete msg.set.color2; // keep it nice and clean
|
||||
} else {
|
||||
delete msg.set.color2;
|
||||
|
||||
msg.set = RoomSettings.changeSettings(msg.set);
|
||||
|
||||
if (typeof(msg.set.lobby) !== 'undefined') {
|
||||
if (msg.set.lobby == true) {
|
||||
if (!this.isLobby(_id)) delete msg.set.lobby; // keep it nice and clean
|
||||
} else {
|
||||
if (this.isLobby(_id)) {
|
||||
msg.set = this.server.lobbySettings;
|
||||
}
|
||||
}
|
||||
};
|
||||
return msg.set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Room;
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
class RoomSettings {
|
||||
static allowedProperties = {
|
||||
color: {
|
||||
type: 'color',
|
||||
default: "#9900ff",
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
color2: {
|
||||
type: 'color2',
|
||||
default: "#5900bf",
|
||||
allowedChange: true,
|
||||
required: false
|
||||
},
|
||||
lobby: {
|
||||
type: 'boolean',
|
||||
allowedChange: false,
|
||||
required: false
|
||||
},
|
||||
visible: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
chat: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
allowedChange: false,
|
||||
required: false
|
||||
},
|
||||
crownsolo: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
allowedChange: true,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
|
||||
constructor (set, cont) {
|
||||
Object.keys(RoomSettings.allowedProperties).forEach(key => {
|
||||
if (typeof(RoomSettings.allowedProperties[key].default) !== 'undefined') {
|
||||
if (this[key] !== RoomSettings.allowedProperties[key].default) {
|
||||
this[key] = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(RoomSettings.allowedProperties).forEach(key => {
|
||||
if (RoomSettings.allowedProperties[key].required == true) {
|
||||
if (typeof(this[key]) == 'undefined') {
|
||||
this[key] = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof(set) !== 'undefined') {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (typeof(set[key]) == 'undefined') return;
|
||||
if (Object.keys(RoomSettings.allowedProperties).indexOf(key) !== -1) {
|
||||
if (typeof(cont) == 'undefined') {
|
||||
this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
|
||||
} else {
|
||||
if (cont == 'user') {
|
||||
if (RoomSettings.allowedProperties[key].allowedChange) {
|
||||
this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
verifyPropertyType(key, pr, type) {
|
||||
let ret;
|
||||
|
||||
if (typeof(RoomSettings.allowedProperties[key]) !== 'object') return;
|
||||
|
||||
switch (type) {
|
||||
case 'color':
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
case 'color2':
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (typeof(pr) == type) {
|
||||
ret = pr;
|
||||
} else if (typeof(RoomSettings.allowedProperties[key].default) !== 'undefined') {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
} else {
|
||||
ret = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
changeSettings(set) {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (RoomSettings.allowedProperties[key].allowedChange) {
|
||||
this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static changeSettings(set) {
|
||||
Object.keys(set).forEach(key => {
|
||||
if (RoomSettings.allowedProperties[key].allowedChange) {
|
||||
set[key] = RoomSettings.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
|
||||
}
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
static verifyPropertyType(key, pr, type) {
|
||||
let ret;
|
||||
|
||||
if (typeof(RoomSettings.allowedProperties[key]) !== 'object') return;
|
||||
|
||||
switch (type) {
|
||||
case 'color':
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
case 'color2':
|
||||
if (/^#[0-9a-f]{6}$/i.test(pr)) {
|
||||
ret = pr;
|
||||
} else {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (typeof(pr) == type) {
|
||||
ret = pr;
|
||||
} else if (typeof(RoomSettings.allowedProperties[key].default) !== 'undefined') {
|
||||
ret = RoomSettings.allowedProperties[key].default;
|
||||
} else {
|
||||
ret = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RoomSettings;
|
|
@ -3,11 +3,13 @@ const banned = require('../banned.json');
|
|||
const https = require("https");
|
||||
const http = require("http");
|
||||
const fs = require('fs');
|
||||
const RoomSettings = require('./RoomSettings');
|
||||
|
||||
class Server extends EventEmitter {
|
||||
constructor(config) {
|
||||
super();
|
||||
EventEmitter.call(this);
|
||||
|
||||
if (config.ssl == true) {
|
||||
this.https_server = https.createServer({
|
||||
key: fs.readFileSync('ssl/privkey.pem', 'utf8'),
|
||||
|
@ -35,31 +37,42 @@ class Server extends EventEmitter {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.defaultUsername = "Anonymous";
|
||||
this.defaultRoomSettings = new RoomSettings(config.defaultRoomSettings);
|
||||
|
||||
this.lobbySettings = new RoomSettings(config.defaultRoomSettings);
|
||||
this.lobbySettings.lobby = true;
|
||||
this.lobbySettings.color = config.defaultLobbyColor || "#9900ff";
|
||||
this.lobbySettings.color2 = config.defaultLobbyColor2 || "#9900ff";
|
||||
|
||||
console.log(`Server started on port ${config.port}`);
|
||||
this.connectionid = 0;
|
||||
this.connections = new Map();
|
||||
this.roomlisteners = new Map();
|
||||
this.rooms = new Map();
|
||||
|
||||
this.wss.on('connection', (ws, req) => {
|
||||
this.connections.set(++this.connectionid, new Client(ws, req, this));
|
||||
});
|
||||
|
||||
this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color", "eval", "notification"]
|
||||
this.welcome_motd = config.motd || "You agree to read this message.";
|
||||
|
||||
this._id_Private_Key = config._id_PrivateKey || "boppity";
|
||||
this.defaultUsername = config.defaultUsername || "Anonymous";
|
||||
this.defaultRoomColor = config.defaultRoomColor || "#3b5054";
|
||||
this.defaultLobbyColor = config.defaultLobbyColor || "#19b4b9";
|
||||
this.defaultLobbyColor2 = config.defaultLobbyColor2 || "#801014";
|
||||
|
||||
this.adminpass = config.adminpass || "Bop It";
|
||||
};
|
||||
}
|
||||
|
||||
updateRoom(data) {
|
||||
if (!data.ch.settings.visible) return;
|
||||
|
||||
for (let cl of Array.from(this.roomlisteners.values())) {
|
||||
cl.sendArray([{
|
||||
"m": "ls",
|
||||
"c": false,
|
||||
"u": [data.ch]
|
||||
}])
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
65
src/User.js
65
src/User.js
|
@ -1,53 +1,24 @@
|
|||
const ColorEncoder = require("./ColorEncoder.js");
|
||||
const { promisify } = require('util');
|
||||
let userdb;
|
||||
const Database = require("./Database");
|
||||
|
||||
class User {
|
||||
constructor(cl) {
|
||||
this.cl = cl;
|
||||
this.server = this.cl.server;
|
||||
this.userdb = userdb;
|
||||
this.default_db = {};
|
||||
constructor(cl, data) {
|
||||
this.server = cl.server;
|
||||
this.name = data.name;
|
||||
this._id = data._id;
|
||||
this.color = data.color;
|
||||
this.ip = data.ip;
|
||||
}
|
||||
async getUserData() {
|
||||
if (!userdb || (userdb instanceof Map && [...userdb.entries()] == [])) {
|
||||
await this.setUpDb();
|
||||
|
||||
static updateUserModel(cl, user) {
|
||||
let u2 = new User(cl, user);
|
||||
if (typeof(u2) == 'undefined') return;
|
||||
|
||||
for (let id in Object.keys(u2)) {
|
||||
if (!user.hasOwnProperty(id)) {
|
||||
user[id] = u2[id];
|
||||
}
|
||||
}
|
||||
let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24);
|
||||
let usertofind = userdb.get(_id);
|
||||
if (!usertofind) {
|
||||
if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return;
|
||||
userdb.set(_id, {
|
||||
"color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`,
|
||||
"name": this.server.defaultUsername,
|
||||
"_id": _id,
|
||||
"ip": this.cl.ip
|
||||
});
|
||||
this.updatedb();
|
||||
}
|
||||
let user = userdb.get(_id);
|
||||
return {
|
||||
"color": user.color,
|
||||
"name": user.name,
|
||||
"_id": user._id,
|
||||
}
|
||||
}
|
||||
async updatedb() {
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
await writeFile('src/db/users.json', JSON.stringify(User.strMapToObj(userdb), null, 2));
|
||||
}
|
||||
async setUpDb() {
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
const readdir = promisify(fs.readdir);
|
||||
let files = await readdir("src/db/");
|
||||
if (!files.includes("users.json")) {
|
||||
await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2))
|
||||
userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
} else {
|
||||
userdb = new Map(Object.entries(require("./db/users.json")));
|
||||
}
|
||||
}
|
||||
static strMapToObj(strMap) {
|
||||
return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = User;
|
||||
|
|
Loading…
Reference in New Issue