From 4db3ab4c843ab5aaf668c8a5958fd642f606ec52 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Mon, 31 Mar 2025 17:41:44 +0700 Subject: [PATCH] feat: add socket server for notification --- src/app.ts | 3 ++ src/services/socket.ts | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/services/socket.ts diff --git a/src/app.ts b/src/app.ts index 5b35577..b18eaba 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,10 +6,13 @@ import swaggerUi from "swagger-ui-express"; import swaggerDocument from "./swagger.json"; import error from "./middlewares/error"; import { RegisterRoutes } from "./routes"; +import { initWebSocket } from "./services/socket"; async function main() { const app = express(); + initWebSocket(+(process.env.SOCKET_PORT || 3001)); + app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); diff --git a/src/services/socket.ts b/src/services/socket.ts new file mode 100644 index 0000000..3e4aca1 --- /dev/null +++ b/src/services/socket.ts @@ -0,0 +1,69 @@ +import { Server } from "socket.io"; + +let io: Server; + +export function initWebSocket(port?: number) { + if (io) return; + + io = new Server({ cors: { origin: "*" }, path: "/api/v1/backup-socket" }); + + io.use(async (socket, next) => { + const token = socket.handshake.auth.token; + + const res = await fetch(`${process.env.AUTH_REALM_URL}/protocol/openid-connect/userinfo`, { + headers: { authorization: `Bearer ${token}` }, + }).catch((e) => console.error(e)); + + if (res?.ok) { + socket.data.user = await res.json(); + } + + next(); + }); + + io.on("connection", (ws) => { + console.log("✅ Client connected to WebSocket"); + + ws.on("close", () => { + console.log("❌ Client disconnected"); + }); + + ws.on("error", (error: any) => { + console.error("WebSocket error:", error); + }); + }); + + io.listen(port || 3001); +} + +export async function sendWebSocket( + event: string, + data: any, + opts?: { + roles?: string[]; + userId?: string[]; + }, +) { + if (!io) initWebSocket(); + + for (let [id, session] of io.of("/").sockets) { + const user: { + sub: string; + name: string; + given_name: string; + family_name: string; + preferred_username: string; + email: string; + role: string[]; + } = session.data.user; + + if (!user) continue; + + if ( + user.role?.some((v) => opts?.roles?.includes(v)) || + opts?.userId?.some((v) => user.sub === v) + ) { + io.to(id).emit(event, JSON.stringify(data)); + } + } +}