(function () { var WebSocketServer = require("ws").Server; var wss = new WebSocketServer({ port: 8080 }); var bannedKeys = []; var bannedIps = []; var rooms = []; var events = []; var clients = {}; var bannedKeyWords = []; var messages = { create: function (key, nickname, avatar, config, mode) { if (this.onlineKey != key) return; this.nickname = util.getNickname(nickname); this.avatar = avatar; var room = {}; rooms.push(room); this.room = room; delete this.status; room.owner = this; room.key = key; this.sendl("createroom", key); }, enter: function (key, nickname, avatar) { this.nickname = util.getNickname(nickname); this.avatar = avatar; var room = false; for (var i of rooms) { if (i.key == key) { room = i; break; } } if (!room) { this.sendl("enterroomfailed"); return; } this.room = room; delete this.status; if (room.owner) { if ( room.servermode && !room.owner._onconfig && config && mode ) { room.owner.sendl("createroom", index, config, mode); room.owner._onconfig = this; room.owner.nickname = util.getNickname(nickname); room.owner.avatar = avatar; } else if ( !room.config || (room.config.gameStarted && (!room.config.observe || !room.config.observeReady)) ) { this.sendl("enterroomfailed"); } else { this.owner = room.owner; this.owner.sendl("onconnection", this.wsid); } util.updaterooms(); } }, changeAvatar: function (nickname, avatar) { this.nickname = util.getNickname(nickname); this.avatar = avatar; util.updateclients(); }, server: function (cfg) { if (cfg) { this.servermode = true; var room = rooms[cfg[0]]; if (!room || room.owner) { this.sendl("reloadroom", true); } else { room.owner = this; this.room = room; this.nickname = util.getNickname(cfg[1]); this.avatar = cfg[2]; this.sendl("createroom", cfg[0], {}, "auto"); } } else { for (var i = 0; i < rooms.length; i++) { if (!rooms[i].owner) { rooms[i].owner = this; rooms[i].servermode = true; this.room = rooms[i]; this.servermode = true; break; } } util.updaterooms(); } }, key: function (id) { if (!id || typeof id != "object") { this.sendl("denied", "key"); this.close(); clearTimeout(this.keyCheck); delete this.keyCheck; return; } else if (bannedKeys.indexOf(id[0]) != -1) { bannedIps.push(this._socket.remoteAddress); this.close(); } this.onlineKey = id[0]; clearTimeout(this.keyCheck); delete this.keyCheck; }, events: function (cfg, id, type) { if ( bannedKeys.indexOf(id) != -1 || typeof id != "string" || this.onlineKey != id ) { bannedIps.push(this._socket.remoteAddress); console.log(id, this._socket.remoteAddress); this.close(); return; } var changed = false; var time = new Date().getTime(); if (cfg && id) { if (typeof cfg == "string") { for (var i = 0; i < events.length; i++) { if (events[i].id == cfg) { if (type == "join") { if (events[i].members.indexOf(id) == -1) { events[i].members.push(id); } changed = true; } else if (type == "leave") { var index = events[i].members.indexOf(id); if (index != -1) { events[i].members.splice(index, 1); if (events[i].members.length == 0) { events.splice(i--, 1); } } changed = true; } } } } else if ( cfg.hasOwnProperty("utc") && cfg.hasOwnProperty("day") && cfg.hasOwnProperty("hour") && cfg.hasOwnProperty("content") ) { if (events.length >= 20) { this.sendl("eventsdenied", "total"); } else if (cfg.utc <= time) { this.sendl("eventsdenied", "time"); } else if (util.isBanned(cfg.content)) { this.sendl("eventsdenied", "ban"); } else { cfg.nickname = util.getNickname(cfg.nickname); cfg.avatar = cfg.nickname || "caocao"; cfg.creator = id; cfg.id = util.getid(); cfg.members = [id]; events.unshift(cfg); changed = true; } } } if (changed) { util.updateevents(); } }, config: function (config) { var room = this.room; if (room && room.owner == this) { if (room.servermode) { room.servermode = false; if (this._onconfig) { if (clients[this._onconfig.wsid]) { this._onconfig.owner = this; this.sendl("onconnection", this._onconfig.wsid); } delete this._onconfig; } } room.config = config; } util.updaterooms(); }, status: function (str) { if (typeof str == "string") { this.status = str; } else { delete this.status; } util.updateclients(); }, send: function (id, message) { if (clients[id] && clients[id].owner == this) { try { clients[id].send(message); } catch (e) { clients[id].close(); } } }, close: function (id) { if (clients[id] && clients[id].owner == this) { clients[id].close(); } }, }; var util = { getNickname: function (str) { return typeof str == "string" ? str.slice(0, 12) : "无名玩家"; }, isBanned: function (str) { for (var i of bannedKeyWords) { if (str.indexOf(i) != -1) return true; } return false; }, sendl: function () { var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } try { this.send(JSON.stringify(args)); } catch (e) { this.close(); } }, getid: function () { return Math.floor( 1000000000 + 9000000000 * Math.random() ).toString(); }, getroomlist: function () { var roomlist = []; for (var i = 0; i < rooms.length; i++) { rooms[i]._num = 0; } for (var i in clients) { if (clients[i].room && !clients[i].servermode) { clients[i].room._num++; } } for (var i = 0; i < rooms.length; i++) { if (rooms[i].servermode) { roomlist[i] = "server"; } else if (rooms[i].owner && rooms[i].config) { if (rooms[i]._num == 0) { rooms[i].owner.sendl("reloadroom"); } roomlist.push([ rooms[i].owner.nickname, rooms[i].owner.avatar, rooms[i].config, rooms[i]._num, rooms[i].key, ]); } delete rooms[i]._num; } return roomlist; }, getclientlist: function () { var clientlist = []; for (var i in clients) { clientlist.push([ clients[i].nickname, clients[i].avatar, !clients[i].room, clients[i].status, clients[i].wsid, clients[i].onlineKey, ]); } return clientlist; }, updaterooms: function () { var roomlist = util.getroomlist(); var clientlist = util.getclientlist(); for (var i in clients) { if (!clients[i].room) { clients[i].sendl("updaterooms", roomlist, clientlist); } } }, updateclients: function () { var clientlist = util.getclientlist(); for (var i in clients) { if (!clients[i].room) { clients[i].sendl("updateclients", clientlist); } } }, checkevents: function () { if (events.length) { var time = new Date().getTime(); for (var i = 0; i < events.length; i++) { if (events[i].utc <= time) { events.splice(i--, 1); } } } return events; }, updateevents: function () { util.checkevents(); for (var i in clients) { if (!clients[i].room) { clients[i].sendl("updateevents", events); } } }, }; wss.on("connection", function (ws) { ws.sendl = util.sendl; if (bannedIps.indexOf(ws._socket.remoteAddress) != -1) { ws.sendl("denied", "banned"); setTimeout(function () { ws.close(); }, 500); return; } ws.keyCheck = setTimeout(function () { ws.sendl("denied", "key"); setTimeout(function () { ws.close(); }, 500); }, 2000); ws.wsid = util.getid(); clients[ws.wsid] = ws; ws.sendl( "roomlist", util.getroomlist(), util.checkevents(), util.getclientlist(ws), ws.wsid ); ws.heartbeat = setInterval(function () { if (ws.beat) { ws.close(); clearInterval(ws.heartbeat); } else { ws.beat = true; try { ws.send("heartbeat"); } catch (e) { ws.close(); } } }, 60000); ws.on("message", function (message) { if (!clients[this.wsid]) return; if (message == "heartbeat") { this.beat = false; } else if (this.owner) { this.owner.sendl("onmessage", this.wsid, message); } else { var arr; try { arr = JSON.parse(message); if (!Array.isArray(arr)) { throw "err"; } } catch (e) { this.sendl("denied", "banned"); return; } if (arr.shift() == "server") { var type = arr.shift(); if (messages[type]) { messages[type].apply(this, arr); } } } }); ws.on("close", function () { for (var i = 0; i < rooms.length; i++) { if (rooms[i].owner == this) { for (var j in clients) { if (clients[j].room == rooms[i] && clients[j] != this) { clients[j].sendl("selfclose"); // clients[j].close(); // delete clients[j]; } } rooms.splice(i--, 1); } } if (clients[this.wsid]) { if (this.owner) { this.owner.sendl("onclose", this.wsid); } delete clients[this.wsid]; } if (this.room) util.updaterooms(); else util.updateclients(); }); }); })();