diff --git a/apps/sse-gateway/README.md b/apps/sse-gateway/README.md new file mode 100644 index 00000000..a61c440a --- /dev/null +++ b/apps/sse-gateway/README.md @@ -0,0 +1,19 @@ +# SSE Gateway (functional stream) + +## Run + +```bash +npm i express +node apps/sse-gateway/server.mjs +``` + +## Test + +```bash +curl -N "http://localhost:5000/sse?q=email" +``` + +You should receive: +- `status` event +- `result` event +- periodic keep-alive comments (`: keep-alive`) diff --git a/apps/sse-gateway/server.mjs b/apps/sse-gateway/server.mjs new file mode 100644 index 00000000..76d35576 --- /dev/null +++ b/apps/sse-gateway/server.mjs @@ -0,0 +1,62 @@ +import express from "express"; + +const app = express(); +const PORT = Number(process.env.PORT) || 5000; + +app.get("/", (_req, res) => { + res.json({ ok: true, service: "sse-gateway" }); +}); + +function detectIntent(q = "") { + const s = String(q).toLowerCase(); + + if (s.includes("email")) return ["email", ["Gmail"]]; + if (s.includes("docs")) return ["docs", ["Google Docs"]]; + if (s.includes("storage")) return ["storage", ["Google Drive"]]; + if (s.includes("dev")) return ["dev", ["Replit", "Vercel"]]; + if (s.includes("payment")) return ["payment", ["PayPal"]]; + if (s.includes("ai")) return ["ai", ["Hugging Face"]]; + + return ["general", ["General"]]; +} + +app.get("/sse", (req, res) => { + const q = String(req.query.q || ""); + const [intent, tools] = detectIntent(q); + + res.setHeader("Content-Type", "text/event-stream; charset=utf-8"); + res.setHeader("Cache-Control", "no-cache"); + res.setHeader("Connection", "keep-alive"); + + if (typeof res.flushHeaders === "function") { + res.flushHeaders(); + } + + res.write("event: status\n"); + res.write(`data: ${JSON.stringify({ status: "processing" })}\n\n`); + + const resultTimer = setTimeout(() => { + res.write("event: result\n"); + res.write( + `data: ${JSON.stringify({ + query: q, + intent, + tools, + })}\n\n`, + ); + }, 300); + + const heartbeat = setInterval(() => { + res.write(": keep-alive\n\n"); + }, 15000); + + req.on("close", () => { + clearTimeout(resultTimer); + clearInterval(heartbeat); + res.end(); + }); +}); + +app.listen(PORT, "0.0.0.0", () => { + console.log(`SSE server running on ${PORT}`); +}); diff --git a/package.json b/package.json index 1dc449e4..c734ea66 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "example": "examples" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "sse:gateway": "node apps/sse-gateway/server.mjs" }, "repository": { "type": "git", @@ -22,6 +23,7 @@ }, "homepage": "https://github.com/NguyenCuong1989/DAIOF-Framework#readme", "dependencies": { - "@playwright/test": "^1.56.1" + "@playwright/test": "^1.56.1", + "express": "^4.21.2" } }