// // sse.cc // // Copyright (c) 2020 Yuji Hirose. All rights reserved. // MIT License // #include #include #include #include #include #include #include #include using namespace httplib; using namespace std; class EventDispatcher { public: EventDispatcher() { } void wait_event(DataSink *sink) { unique_lock lk(m_); int id = id_; cv_.wait(lk, [&] { return cid_ == id; }); if (sink->is_writable()) { sink->write(message_.data(), message_.size()); } } void send_event(const string &message) { lock_guard lk(m_); cid_ = id_++; message_ = message; cv_.notify_all(); } private: mutex m_; condition_variable cv_; atomic_int id_ = 0; atomic_int cid_ = -1; string message_; }; const auto html = R"( SSE demo )"; int main(void) { EventDispatcher ed; Server svr; svr.Get("/", [&](const Request & /*req*/, Response &res) { res.set_content(html, "text/html"); }); svr.Get("/event1", [&](const Request & /*req*/, Response &res) { cout << "connected to event1..." << endl; res.set_chunked_content_provider("text/event-stream", [&](size_t /*offset*/, DataSink &sink) { ed.wait_event(&sink); return true; }); }); svr.Get("/event2", [&](const Request & /*req*/, Response &res) { cout << "connected to event2..." << endl; res.set_chunked_content_provider("text/event-stream", [&](size_t /*offset*/, DataSink &sink) { ed.wait_event(&sink); return true; }); }); thread t([&] { int id = 0; while (true) { this_thread::sleep_for(chrono::seconds(1)); cout << "send event: " << id << std::endl; std::stringstream ss; ss << "data: " << id << "\n\n"; ed.send_event(ss.str()); id++; } }); svr.listen("localhost", 1234); }