forked from Hri7566/mpp-server-dev2
basic channels, users. Clients stack
This commit is contained in:
parent
c7f398788e
commit
3d4c8430cf
|
@ -0,0 +1 @@
|
||||||
|
*.json
|
|
@ -0,0 +1,18 @@
|
||||||
|
//call new Server
|
||||||
|
global.WebSocket = require('ws');
|
||||||
|
global.EventEmitter = require('events').EventEmitter;
|
||||||
|
global.fs = require('fs');
|
||||||
|
global.createKeccakHash = require('keccak');
|
||||||
|
const AsyncConsole = require('asyncconsole')
|
||||||
|
|
||||||
|
let Server = require("./src/Server.js");
|
||||||
|
global.SERVER = new Server({
|
||||||
|
port: 8080
|
||||||
|
});
|
||||||
|
let console = new AsyncConsole("", input => {
|
||||||
|
try {
|
||||||
|
console.log(JSON.stringify(eval(input)));
|
||||||
|
} catch(e) {
|
||||||
|
console.log(e.toString());
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,81 @@
|
||||||
|
const Room = require("./Room.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.ws = ws;
|
||||||
|
this.req = req;
|
||||||
|
this.ip = (req.connection.remoteAddress).replace("::ffff:","");
|
||||||
|
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.server.rooms.get(_id)) {
|
||||||
|
let channel = this.channel;
|
||||||
|
if (channel) this.channel.emit("bye", this);
|
||||||
|
if (channel) this.channel.updateCh();
|
||||||
|
this.channel = this.server.rooms.get(_id);
|
||||||
|
this.channel.join(this);
|
||||||
|
} else {
|
||||||
|
let room = new Room(this.server, _id, settings);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendArray(arr) {
|
||||||
|
if (this.isConnected()) {
|
||||||
|
console.log(`SEND: `, JSON.colorStringify(arr));
|
||||||
|
this.ws.send(JSON.stringify(arr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
this.ws.close();
|
||||||
|
this.user;
|
||||||
|
this.participantId;
|
||||||
|
this.channel;
|
||||||
|
this.connectionid;
|
||||||
|
this.server.connections.delete(this.connectionid);
|
||||||
|
if (this.channel) {
|
||||||
|
this.channel.emit("bye", this)
|
||||||
|
}
|
||||||
|
console.log(`Removed Connection ${this.connectionid}.`);
|
||||||
|
}
|
||||||
|
bindEventListeners() {
|
||||||
|
this.ws.on("message", (evt) => {
|
||||||
|
try {
|
||||||
|
var transmission = JSON.parse(evt);
|
||||||
|
} catch (e) {
|
||||||
|
this.destroy();
|
||||||
|
} finally {
|
||||||
|
for (let msg of transmission) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ws.on("close", () => {
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("error", (err) => {
|
||||||
|
console.error(err);
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = Client;
|
|
@ -0,0 +1,16 @@
|
||||||
|
function hashCode(str) { // java String#hashCode
|
||||||
|
var hash = 0;
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
function intToRGB(i){
|
||||||
|
var c = (i & 0x00FFFFFF)
|
||||||
|
.toString(16)
|
||||||
|
.toUpperCase();
|
||||||
|
|
||||||
|
return "00000".substring(0, 6 - c.length) + c;
|
||||||
|
}
|
||||||
|
module.exports = {hashCode, intToRGB};
|
|
@ -0,0 +1,32 @@
|
||||||
|
const User = require("./User.js");
|
||||||
|
const Room = require("./Room.js");
|
||||||
|
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 = "1.0 Alpha";
|
||||||
|
cl.sendArray([msg])
|
||||||
|
cl.user = data;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
cl.on("t", msg => {
|
||||||
|
if (msg.hasOwnProperty("e") && !isNaN(msg.e))
|
||||||
|
cl.sendArray([{
|
||||||
|
m: "t",
|
||||||
|
t: Date.now(),
|
||||||
|
e: msg.e
|
||||||
|
}])
|
||||||
|
})
|
||||||
|
cl.on("ch", msg => {
|
||||||
|
if (!msg.hasOwnProperty("set")) msg.set = {};
|
||||||
|
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
||||||
|
if (msg._id.length > 512) return;
|
||||||
|
cl.setChannel(msg._id, msg.set);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
//noteQuota.js
|
|
@ -0,0 +1,105 @@
|
||||||
|
//array of rooms
|
||||||
|
//room class
|
||||||
|
//room deleter
|
||||||
|
//databases in Map
|
||||||
|
|
||||||
|
class Room extends EventEmitter { //clean?
|
||||||
|
constructor(server, _id, settings) {
|
||||||
|
super();
|
||||||
|
EventEmitter.call(this);
|
||||||
|
this._id = _id;
|
||||||
|
this.server = server;
|
||||||
|
this.settings = {
|
||||||
|
lobby: true,
|
||||||
|
visible: settings.visible || true,
|
||||||
|
crownsolo: settings.crownsolo || false,
|
||||||
|
chat: settings.chat || true,
|
||||||
|
color: this.verifyColor(settings.color) || this.server.defaultRoomColor,
|
||||||
|
color2: this.verifyColor(settings.color) || this.defaultLobbyColor2
|
||||||
|
}
|
||||||
|
this.ppl = new Map();
|
||||||
|
this.bindEventListeners();
|
||||||
|
this.server.rooms.set(_id, this);
|
||||||
|
}
|
||||||
|
join(cl) {
|
||||||
|
let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24);
|
||||||
|
cl.user.id = participantId;
|
||||||
|
cl.participantId = participantId;
|
||||||
|
this.ppl.set(participantId, cl);
|
||||||
|
this.sendArray([{
|
||||||
|
color: this.ppl.get(cl.participantId).user.color,
|
||||||
|
id: this.ppl.get(cl.participantId).participantId,
|
||||||
|
m: "p",
|
||||||
|
name: this.ppl.get(cl.participantId).user.name,
|
||||||
|
x: this.ppl.get(cl.participantId).x || 200,
|
||||||
|
y: this.ppl.get(cl.participantId).y || 100,
|
||||||
|
_id: cl.user._id
|
||||||
|
}], cl)
|
||||||
|
this.updateCh(cl);
|
||||||
|
}
|
||||||
|
remove(p) {
|
||||||
|
//this.participants.splice(this.participants.findIndex((cl) => cl.participantId == p.participantId), 1);
|
||||||
|
this.ppl.delete(p.participantId);
|
||||||
|
this.sendArray([{
|
||||||
|
m: "bye",
|
||||||
|
p: p.participantId
|
||||||
|
}]);
|
||||||
|
this.updateCh();
|
||||||
|
|
||||||
|
}
|
||||||
|
updateCh(cl) {
|
||||||
|
if (this.ppl.keys().next().value.length <= 0) this.destroy();
|
||||||
|
this.ppl.forEach((usr) => {
|
||||||
|
this.server.connections.get(usr.connectionid).sendArray([this.fetchData(usr, cl)])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
destroy() {
|
||||||
|
this._id;
|
||||||
|
console.log(`Deleted room ${this._id}`);
|
||||||
|
this.settings = {};
|
||||||
|
this.ppl;
|
||||||
|
this.server.rooms.delete(_id);
|
||||||
|
}
|
||||||
|
sendArray(arr, not) {
|
||||||
|
this.ppl.forEach((usr) => {
|
||||||
|
if (!not || usr.participantId != not.participantId) {
|
||||||
|
try {
|
||||||
|
this.server.connections.get(usr.connectionid).sendArray(arr)
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fetchData(usr, cl) {
|
||||||
|
let chppl = [];
|
||||||
|
[...this.ppl.values()].forEach((a) => {
|
||||||
|
chppl.push(a.user);
|
||||||
|
})
|
||||||
|
let data = {
|
||||||
|
m: "ch",
|
||||||
|
ch: {
|
||||||
|
count: chppl.length,
|
||||||
|
settings: this.settings,
|
||||||
|
_id: this._id
|
||||||
|
},
|
||||||
|
ppl: chppl
|
||||||
|
}
|
||||||
|
if (cl) {
|
||||||
|
if (usr.user.id == cl.user.id) {
|
||||||
|
data.p = cl.participantId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
verifyColor(color) {
|
||||||
|
return color; //TODO make this
|
||||||
|
}
|
||||||
|
bindEventListeners() {
|
||||||
|
this.on("bye", participant => {
|
||||||
|
this.remove(participant);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
module.exports = Room;
|
|
@ -0,0 +1,29 @@
|
||||||
|
const Client = require("./Client.js")
|
||||||
|
class Server extends EventEmitter {
|
||||||
|
constructor(config) {
|
||||||
|
super();
|
||||||
|
EventEmitter.call(this);
|
||||||
|
this.wss = new WebSocket.Server({
|
||||||
|
port: config.port,
|
||||||
|
backlog: 100,
|
||||||
|
verifyClient: function (info, done) {
|
||||||
|
done(true)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.connectionid = 0;
|
||||||
|
this.connections = 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"]
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Server;
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
Room.js make color verifier
|
|
@ -0,0 +1,58 @@
|
||||||
|
const ColorEncoder = require("./ColorEncoder.js");
|
||||||
|
class User {
|
||||||
|
constructor(cl) {
|
||||||
|
this.cl = cl;
|
||||||
|
this.userdb;
|
||||||
|
this.server = this.cl.server;
|
||||||
|
this.default_db = {}
|
||||||
|
}
|
||||||
|
async getUserData() {
|
||||||
|
if (!this.userdb) {
|
||||||
|
this.setUpDb();
|
||||||
|
}
|
||||||
|
let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24);
|
||||||
|
if (!this.userdb.get(_id)) {
|
||||||
|
this.userdb.set(_id, {
|
||||||
|
"color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`,
|
||||||
|
"name": this.server.defaultUsername,
|
||||||
|
"_id": _id,
|
||||||
|
"ip": this.cl.ip
|
||||||
|
});
|
||||||
|
this.updatedb();
|
||||||
|
}
|
||||||
|
let user = this.userdb.get(_id);
|
||||||
|
return {
|
||||||
|
"color": user.color,
|
||||||
|
"name": user.name,
|
||||||
|
"_id": user._id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatedb() {
|
||||||
|
fs.writeFileSync('src/db/users.json', JSON.stringify(this.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")) {
|
||||||
|
fs.writeFileSync('src/db/users.json', JSON.stringify(this.default_db, null, 2), (err) => {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||||
|
} else {
|
||||||
|
this.userdb = new Map(Object.entries(require("./db/users.json")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = User;
|
Loading…
Reference in New Issue