#include "App.hpp" #include "../fw/Data.hpp" #include "../fw/Router.hpp" #include "../fw/Validate.hpp" namespace molo::example::app { // Realtime demos answer over plain HTTP in the skeleton: the WebSocket and // Socket.IO endpoints describe the upgrade contract and echo posted frames, // SSE streams real event text. Gap: real framing, namespaces, rooms, and // long-polling fallback in 06-realtime.md plus matching clients. void register_realtime_demo(fw::Router& router, Services& services) { fw::WebdavStore* webdav = services.webdav.get(); router.get("/streaming/feed", "stream", [](fw::Request req) { (void)req; return fw::Response( fw::StreamingResponse({"chunk-1\n", "chunk-2\n", "chunk-3\n"})); }); router.get("/streaming/passthrough", "passthrough", [](fw::Request req) { std::string target = req.query_or("target", "/health"); return fw::Response(fw::StreamingResponse( {"passthrough from " + target + "\n", "{\"status\":\"ok\"}\n"})); }); router.get("/ws/chat", "ws", [](fw::Request req) { std::string upgrade = req.headers.get("Upgrade"); if (upgrade == "websocket") return fw::JsonResponse( "{\"upgraded\":false,\"note\":\"skeleton: echo over POST\"}", 200); return fw::JsonResponse( "{\"protocol\":\"websocket\",\"path\":\"/ws/chat\",\"upgrade\":" "\"send Upgrade: websocket\"}", 200); }); router.post("/ws/chat", "ws-echo", [](fw::Request req) { return fw::JsonResponse( "{\"echo\":\"" + fw::json_escape(req.body) + "\"}", 200); }); router.get("/socketio/rooms", "socketio", [](fw::Request req) { (void)req; return fw::JsonResponse( "{\"protocol\":\"socket.io\",\"namespaces\":[\"/\"],\"rooms\":[" "\"lobby\"],\"fallback\":\"long-polling\"}", 200); }); router.post("/socketio/rooms", "socketio-emit", [](fw::Request req) { auto input = fw::parse_json_object_flat(req.body); if (input.empty()) input = fw::parse_form(req.body); std::string room = input.count("room") ? input["room"] : "lobby"; std::string event = input.count("event") ? input["event"] : "message"; return fw::JsonResponse("{\"emitted\":\"" + fw::json_escape(event) + "\",\"room\":\"" + fw::json_escape(room) + "\",\"ack\":true}", 200); }); router.get("/sse/events", "sse", [](fw::Request req) { (void)req; return fw::Response( fw::SseResponse({"hello", "tick", "goodbye"})); }); router.any({fw::Method::Propfind}, "/webdav/files/", "webdav-propfind", [webdav](fw::Request req) { (void)req; return fw::Response(207, webdav->propfind_xml("/files/"), "application/xml"); }); router.any({fw::Method::Get}, "/webdav/files/{name}", "webdav-get", [webdav](fw::Request req) -> fw::Response { std::string content; if (!webdav->get("/files/" + req.param_or("name", ""), content)) return fw::JsonResponse("{\"error\":\"not found\"}", 404); return fw::TextResponse(content, 200); }); router.any({fw::Method::Put}, "/webdav/files/{name}", "webdav-put", [webdav](fw::Request req) { webdav->put("/files/" + req.param_or("name", ""), req.body); return fw::JsonResponse("{\"stored\":true}", 201); }); router.any({fw::Method::Delete}, "/webdav/files/{name}", "webdav-delete", [webdav](fw::Request req) { if (!webdav->remove("/files/" + req.param_or("name", ""))) return fw::JsonResponse("{\"error\":\"not found\"}", 404); return fw::JsonResponse("{\"deleted\":true}", 200); }); } } // namespace molo::example::app