import express from "express"; import http from "http"; import log4js from "log4js"; import { Server } from "socket.io"; import { loadHistory, saveToDatabase, queryHistory, getDatabaseState } from "./storage.js"; const PORT = process.env.PORT || 5691; const app = express(); const server = http.createServer(app); const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"], }, }); const logger = log4js.getLogger("app"); app.use(express.static("static")) logger.level = process.env.LOG_LEVEL || "debug"; // 初始化在线列表 let onlineList = []; let clientMap = new Map(); class Response { constructor(status, msg) { this.status = status this.msg = msg } } app.get("/online", (req, res) => { res.status(200).send({ online: onlineList.length, user: onlineList }) }) app.get("/history", (req, res) => { if (!getDatabaseState()) { res.status(500).send({ status: 500, msg: "database is not ready", data: null }) } if (!req.query.limit || isNaN(req.query.limit) || req.query.limit <= 0 || req.query.limit > 100) { req.query.limit = 10; } loadHistory(req.query.limit).then((data) => { res.status(200).send({ status: 200, msg: "success", data: data }) }).catch((err) => { logger.error(`database error: ${err}`) res.status(500).send({ status: 500, msg: "database error", data: null }) }) }) io.on("connection", (socket) => { logger.info(`A client connected, id: ${socket.id}`) socket.on("system", data => { if (!data) { socket.emit("system", JSON.stringify(new Response(false, "data payload is empty."))) return; } if (clientMap.has(socket.id)) { socket.emit("system", JSON.stringify(new Response(false, "you are already online."))) return; } try { const { opt, args } = JSON.parse(data); console.log(opt, args) if (opt == "signin") { if (!args || !args.username) { socket.emit("system", JSON.stringify(new Response(false, "username is empty."))) return; } const { username } = args if (username.length > 20) { socket.emit("system", JSON.stringify(new Response(false, "username is too long."))) } if (onlineList.indexOf(username) != -1) { socket.emit("system", JSON.stringify(new Response(false, "username is already taken."))) return; } socket.username = username; onlineList.push(username); clientMap.set(socket.id, username); socket.emit("username", socket.username); socket.emit("system", JSON.stringify(new Response(true, `welcome, ${socket.username}`))) io.emit("notice", JSON.stringify(new Response(true, `${socket.username} join the chat.`))) logger.debug(`socket(${socket.id}) -- ${username} signed in.`) } } catch (err) { logger.error(`socket(${socket.id}) -- ${err}.`) socket.emit("system", JSON.stringify(new Response(false, "data payload is invaild."))) return; } console.log(clientMap) console.log(onlineList) }) socket.on("msg", data => { if (!socket.username) { socket.emit("system", JSON.stringify(new Response(false, "you are not signed in."))); return; } logger.debug(`socket(${socket.id}) -- ${data}`) io.emit("msg", JSON.stringify({sender: socket.username, msg: data})) saveToDatabase(socket.username, data, new Date().getTime()) }) socket.on("disconnect", (reason, description) => { logger.info(`A client disconnected, id: ${socket.id}`) logger.trace(`socket(${socket.id}) -- reason: ${reason}, description: ${description}`); if (clientMap.has(socket.id)) clientMap.delete(socket.id); // TODO: 这个算法有点不安全 if (onlineList.includes(socket.username)) onlineList.splice(onlineList.indexOf(socket.id)); io.emit("notice", JSON.stringify(new Response(true, `${socket.username} left the chat.`))); }) }); server.listen(PORT, () => { logger.info(`Server running on port ${PORT}`); });