import { Server as SocketIOServer } from "socket.io"; import { randomUUID } from "crypto"; import server from "./server.js"; import Message from "./models/Message.js"; import { Quota } from "./util.js"; export var io = new SocketIOServer(server, { cors: {origin: "*"}, maxHttpBufferSize: 100000, perMessageDeflate: true }); io.on("connection", socket => { socket.ip = socket.handshake.headers["x-forwarded-for"]?.split(',')[0] || socket.handshake.address; console.log("connect", socket.ip, socket.id); socket.quotas = { user: new Quota(1000, 1000*60*60), message: new Quota(30, 60000) }; socket.on("disconnect", reason => { console.log("disconnect", socket.id, reason); for (var quota in socket.quotas) { socket.quotas[quota].destroy(); } }) socket.on("user", user => { if (!socket.quotas.user.spend()) return; if (typeof user != "object") return; user = { name: user.name?.toString().trim().substring(0,32), color: user.color?.toString().trim().substring(0,32), website: user.website?.toString().trim().substring(0,1000), uuid: user.uuid?.toString().substring(0,128) || "A"+randomUUID(), secret: user.secret?.toString().substring(0,128), socketid: socket.id, ip: socket.ip, agent: socket.handshake.headers["user-agent"] }; console.debug("user", JSON.stringify(user)); socket.data.user = user; broadcastUsers(); }); socket.once("user", async user => { if (typeof user != "object") return; //await newMessage({color: "#00FF00", content:`${user.name} connected`}); socket.on("disconnect", () => { //newMessage({color: "#FF0000", content: `${socket.data.user.name} disconnected`}); broadcastUsers(); }); socket.on("message", message => { if (!socket.quotas.message.spend()) return; if (typeof message != "object") return; newMessage({ content: message.content?.toString().substring(0,10000), user: {...socket.data.user} }).catch(error => { console.error(socket.id, error.message); }); }); socket.on("type", () => { io.emit("type", socket.id); }); socket.on("mouse", (x, y) => { if (typeof x != "number" || typeof y != "number") return; //socket.broadcast.emit("mouse", x, y, socket.id); // see own cursor (test) io.emit("mouse", x, y, socket.id); }); Message.getMessages({secret: user.secret}).then(messages => { socket.emit("messages", messages); }); }); }); async function broadcastUsers() { var users = await io.fetchSockets().then(sockets => sockets.filter(socket => socket.data.user).map(socket => { var user = Object.assign({}, socket.data.user); delete user.ip; delete user.secret; return user; })); io.emit("users", users); } async function newMessage(message) { message = new Message(message); message.timestamp = new Date(); message = await message.save(); message = message.toObject(); console.debug("message", message); delete message.user.ip; delete message.user.secret; io.emit("message", message); }