diff --git a/index.js b/index.js index 755561c..752cb17 100644 --- a/index.js +++ b/index.js @@ -6,9 +6,8 @@ global.createKeccakHash = require('keccak'); const AsyncConsole = require('asyncconsole') let Server = require("./src/Server.js"); -global.SERVER = new Server({ - port: 8080 -}); +let config = require('./src/db/config.json'); +global.SERVER = new Server(config); let console = new AsyncConsole("", input => { try { console.log(JSON.stringify(eval(input))); diff --git a/src/Client.js b/src/Client.js index 74a5844..74758f6 100644 --- a/src/Client.js +++ b/src/Client.js @@ -25,6 +25,24 @@ class Client extends EventEmitter { setChannel(_id, settings) { if (this.channel && this.channel._id == _id) return; if (this.server.rooms.get(_id)) { + let room = this.server.rooms.get(_id); + 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) { + console.log(Date.now() - userbanned.bannedtime) + room.Notification(this.user._id, + "Notice", + `Currently banned from \"${_id}\" for ${Math.ceil(Math.floor((userbanned.msbanned - (Date.now() - userbanned.bannedtime)) / 1000) / 60)} minutes.`, + 7000, + "", + "#room", + "short" + ); + return; + } let channel = this.channel; if (channel) this.channel.emit("bye", this); if (channel) this.channel.updateCh(); @@ -40,7 +58,7 @@ class Client extends EventEmitter { } sendArray(arr) { if (this.isConnected()) { - console.log(`SEND: `, JSON.colorStringify(arr)); + //console.log(`SEND: `, JSON.colorStringify(arr)); this.ws.send(JSON.stringify(arr)); } } @@ -52,6 +70,7 @@ class Client extends EventEmitter { this.user; this.participantId; this.channel; + this.server.roomlisteners.delete(this.connectionid); this.connectionid; this.server.connections.delete(this.connectionid); this.destroied = true; @@ -65,7 +84,7 @@ class Client extends EventEmitter { if (!msg.hasOwnProperty("m")) return; if (!this.server.legit_m.includes(msg.m)) return; this.emit(msg.m, msg); - console.log(`RECIEVE: `, JSON.colorStringify(msg)); + //console.log(`RECIEVE: `, JSON.colorStringify(msg)); } } catch (e) { console.log(e) @@ -74,12 +93,12 @@ class Client extends EventEmitter { }); this.ws.on("close", () => { if (!this.destroied) - this.destroy(); + this.destroy(); }); this.ws.addEventListener("error", (err) => { console.error(err); if (!this.destroied) - this.destroy(); + this.destroy(); }); } } diff --git a/src/Message.js b/src/Message.js index 764dc50..a56a1fd 100644 --- a/src/Message.js +++ b/src/Message.js @@ -9,7 +9,7 @@ module.exports = (cl) => { msg.motd = cl.server.welcome_motd; msg.t = Date.now(); msg.u = data; - msg.v = "1.0 Alpha"; + msg.v = "Beta"; cl.sendArray([msg]) cl.user = data; }) @@ -64,7 +64,67 @@ module.exports = (cl) => { settings.color = cl.channel.verifyColor(msg.set.color) || cl.channel.settings.color; settings.color2 = cl.channel.verifyColor(msg.set.color2) || cl.channel.settings.color2; cl.channel.settings = settings; - console.log(settings) cl.channel.updateCh(); }) + cl.on("a", msg => { + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty('message')) return; + cl.channel.emit('a', cl, msg); + }) + cl.on('n', msg => { + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty('t') || !msg.hasOwnProperty('n')) return; + if (typeof msg.t != 'number' || typeof msg.n != 'object') return; + cl.channel.playNote(cl, msg); + }) + cl.on('+ls', msg => { + cl.server.roomlisteners.set(cl.connectionid, cl); + let rooms = []; + for (let room of Array.from(cl.server.rooms.values())) { + let data = room.fetchData().ch; + if (room.bans.get(cl.user._id)) { + data.banned = true; + } + rooms.push(data); + } + cl.sendArray([{ + "m": "ls", + "c": true, + "u": rooms + }]) + }) + cl.on('-ls', msg => { + cl.server.roomlisteners.delete(cl.connectionid); + }) + cl.on("userset", msg => { + if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; + if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") { + if (msg.set.name.length > 40) return; + cl.user.name = msg.set.name; + let user = new User(cl); + user.getUserData().then((usr) => { + let dbentry = user.userdb.get(cl.user._id); + if (!dbentry) return; + dbentry.name = msg.set.name; + user.updatedb(); + cl.server.rooms.forEach((room) => { + room.updateParticipant(cl.participantId, msg.set.name); + }) + }) + + } + }) + cl.on('kickban', msg => { + if (!(cl.channel && cl.participantId)) return; + if (!(cl.user._id == cl.channel.crown.userId)) return; + if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { + let _id = msg._id; + let ms = msg.ms || 0; + cl.channel.kickban(_id, ms); + } + }) + cl.on("bye", msg => { + cl.destroy(); + }) + } \ No newline at end of file diff --git a/src/Room.js b/src/Room.js index 51d944e..3701474 100644 --- a/src/Room.js +++ b/src/Room.js @@ -19,10 +19,12 @@ class Room extends EventEmitter { color: this.verifyColor(settings.color) || this.getColor(_id), color2: this.verifyColor(settings.color) || this.getColor2(_id) } + this.chatmsgs = []; this.ppl = new Map(); this.connections = []; this.bindEventListeners(); this.server.rooms.set(_id, this); + this.bans = new Map(); } join(cl) { //this stuff is complicated let otheruser = this.connections.find((a) => a.user._id == cl.user._id) @@ -30,7 +32,7 @@ class Room extends EventEmitter { let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24); cl.user.id = participantId; cl.participantId = participantId; - 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)) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown. this.crown = { participantId: cl.participantId, userId: cl.user._id, @@ -57,7 +59,11 @@ class Room extends EventEmitter { x: this.ppl.get(cl.participantId).x || 200, y: this.ppl.get(cl.participantId).y || 100, _id: cl.user._id - }], cl) + }], cl, false) + cl.sendArray([{ + m: "c", + c: this.chatmsgs.slice(-1 * 32) + }]) this.updateCh(cl); } else { cl.user.id = otheruser.participantId; @@ -76,10 +82,11 @@ class Room extends EventEmitter { this.sendArray([{ m: "bye", p: p.participantId - }], p); - if (this.crown.userId == p.user._id && !this.crowndropped) { - this.chown(); - } + }], p, false); + if (this.crown) + if (this.crown.userId == p.user._id && !this.crowndropped) { + this.chown(); + } this.updateCh(); } else { this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); @@ -91,6 +98,24 @@ class Room extends EventEmitter { this.connections.forEach((usr) => { this.server.connections.get(usr.connectionid).sendArray([this.fetchData(usr, cl)]) }) + this.server.updateRoom(this.fetchData()); + } + updateParticipant(pid, name) { + let p = this.ppl.get(pid); + if (!p) return; + this.ppl.get(pid).user.name = name; + this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { + usr.user.name = name; + }) + this.sendArray([{ + color: p.user.color, + id: p.participantId, + m: "p", + name: p.user.name, + x: p.x || 200, + y: p.y || 100, + _id: p.user._id + }]) } destroy() { //destroy room this._id; @@ -98,11 +123,12 @@ class Room extends EventEmitter { this.settings = {}; this.ppl; this.connnections; + this.chatmsgs; this.server.rooms.delete(this._id); } - sendArray(arr, not) { + sendArray(arr, not, onlythisparticipant) { this.connections.forEach((usr) => { - if (!not || usr.participantId != not.participantId) { + if (!not || (usr.participantId != not.participantId && !onlythisparticipant) || (usr.connectionid != not.connectionid && onlythisparticipant)) { try { this.server.connections.get(usr.connectionid).sendArray(arr) } catch (e) { @@ -128,7 +154,7 @@ class Room extends EventEmitter { ppl: chppl } if (cl) { - if (usr.user.id == cl.user.id) { + if (usr.connectionid == cl.connectionid) { data.p = cl.participantId; } else { delete data.p; @@ -138,7 +164,6 @@ class Room extends EventEmitter { } if (data.ch.crown == null) { delete data.ch.crown; - this.crown = crown; } else { } @@ -223,15 +248,133 @@ class Room extends EventEmitter { this.updateCh(); } setCords(p, x, y) { - if (p.participantId) + if (p.participantId && this.ppl.get(p.participantId)) { x ? this.ppl.get(p.participantId).x = x : {}; - y ? this.ppl.get(p.participantId).y = y : {}; + y ? this.ppl.get(p.participantId).y = y : {}; + this.sendArray([{ + m: "m", + id: p.participantId, + x: this.ppl.get(p.participantId).x, + y: this.ppl.get(p.participantId).y + }], p, false); + } + } + chat(p, msg) { + if (msg.message.length > 512) return; + let filter = ["AMIGHTYWIND"]; + let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i"); + if (regexp.test(msg.message)) return; + let prsn = this.ppl.get(p.participantId); + if (prsn) { + let message = {}; + message.m = "a"; + message.a = msg.message; + message.p = { + color: p.user.color, + id: p.participantId, + name: p.user.name, + _id: p.user._id + }; + message.t = Date.now(); + this.sendArray([message]); + this.chatmsgs.push(message); + } + } + playNote(cl, note) { this.sendArray([{ - m: "m", - id: p.participantId, - x: this.ppl.get(p.participantId).x, - y: this.ppl.get(p.participantId).y - }], p); + m: "n", + n: note.n, + p: cl.participantId, + t: Date.now() + }], cl, true); + } + kickban(_id, ms) { + ms = parseInt(ms); + if (ms >= (1000 * 60 * 60 - 500)) return; + if (ms < 0) return; + ms = Math.round(ms / 1000) * 1000; + let user = this.connections.find((usr) => usr.user._id == _id); + if (!user) return; + let asd = true; + let tonc = true; + let pthatbanned = this.ppl.get(this.crown.participantId); + this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => { + user.bantime = Math.floor(Math.floor(ms / 1000) / 60); + user.bannedtime = Date.now(); + user.msbanned = ms; + this.bans.set(user.user._id, user); + if (this.crown && (this.crown.userId)) { + u.setChannel("test/awkward", {}); + if (asd) + this.Notification(user.user._id, + "Notice", + `Banned from \"${this._id}\" for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, + "", + 7000, + "#room", + "short" + ) + if (asd) + this.Notification("room", + "Notice", + `${pthatbanned.user.name} banned ${user.user.name} from the channel for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, + "", + 7000, + "#room", + "short" + ) + if (this.crown && (this.crown.userId == _id) && tonc) { + this.Notification("room", + "Certificate of Award", + `Let it be known that ${user.user.name} kickbanned him/her self.`, + "", + 7000, + "#room" + ); + tonc = false; + } + + } + + }) + } + Notification(who, title, text, html, duration, target, klass, id) { + let obj = { + m: "notification", + title: title, + text: text, + html: html, + target: target, + duration: duration, + class: klass, + id: id + }; + if (!id) delete obj.id; + if (!title) delete obj.title; + if (!text) delete obj.text; + if (!html) delete obj.html; + if (!target) delete obj.target; + if (!duration) delete obj.duration; + if (!klass) delete obj.class; + switch (who) { + case "all": { + for (let con of Array.from(this.server.connections.values())) { + con.sendArray([obj]); + } + break; + } + case "room": { + for (let con of this.connections) { + con.sendArray([obj]); + } + break; + } + default: { + Array.from(this.server.connections.values()).filter((usr) => usr.user._id == who).forEach((p) => { + p.sendArray([obj]); + }); + } + } } bindEventListeners() { this.on("bye", participant => { @@ -241,6 +384,10 @@ class Room extends EventEmitter { this.on("m", (participant, x, y) => { this.setCords(participant, x, y); }) + + this.on("a", (participant, msg) => { + this.chat(participant, msg); + }) } } diff --git a/src/Server.js b/src/Server.js index 48ea9b0..6b95656 100644 --- a/src/Server.js +++ b/src/Server.js @@ -12,6 +12,7 @@ class Server extends EventEmitter { }); 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)); @@ -24,6 +25,15 @@ class Server extends EventEmitter { this.defaultLobbyColor = config.defaultLobbyColor || "#19b4b9"; this.defaultLobbyColor2 = config.defaultLobbyColor2 || "#801014"; }; + updateRoom(data) { + for (let cl of Array.from(this.roomlisteners.values())) { + cl.sendArray([{ + "m": "ls", + "c": false, + "u": [data.ch] + }]) + } + } } module.exports = Server; \ No newline at end of file diff --git a/src/User.js b/src/User.js index 2514265..4abe7ae 100644 --- a/src/User.js +++ b/src/User.js @@ -28,19 +28,12 @@ class User { } } updatedb() { - fs.writeFileSync('src/db/users.json', JSON.stringify(this.strMapToObj(this.userdb), null, 2), (err) => { + fs.writeFileSync('src/db/users.json', JSON.stringify(User.strMapToObj(this.userdb), null, 2), (err) => { if (err) { throw err; } }); } - strMapToObj(strMap) { - let obj = Object.create(null); - for (let [k, v] of strMap) { - obj[k] = v; - } - return obj; - } setUpDb() { let files = fs.readdirSync("src/db/"); if (!files.includes("users.json")) { @@ -54,5 +47,12 @@ class User { this.userdb = new Map(Object.entries(require("./db/users.json"))); } } + static strMapToObj(strMap) { + let obj = Object.create(null); + for (let [k, v] of strMap) { + obj[k] = v; + } + return obj; + } } module.exports = User; \ No newline at end of file