1
0

ssesvr.cc 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include <atomic>
  2. #include <chrono>
  3. #include <condition_variable>
  4. #include <httplib.h>
  5. #include <iostream>
  6. #include <mutex>
  7. #include <sstream>
  8. #include <thread>
  9. using namespace httplib;
  10. using namespace std;
  11. class EventDispatcher {
  12. public:
  13. EventDispatcher() {}
  14. bool wait_event(DataSink *sink) {
  15. unique_lock<mutex> lk(m_);
  16. int id = id_;
  17. // Wait with timeout to prevent hanging if client disconnects
  18. if (!cv_.wait_for(lk, std::chrono::seconds(5),
  19. [&] { return cid_ == id; })) {
  20. return false; // Timeout occurred
  21. }
  22. sink->write(message_.data(), message_.size());
  23. return true;
  24. }
  25. void send_event(const string &message) {
  26. lock_guard<mutex> lk(m_);
  27. cid_ = id_++;
  28. message_ = message;
  29. cv_.notify_all();
  30. }
  31. private:
  32. mutex m_;
  33. condition_variable cv_;
  34. atomic_int id_{0};
  35. atomic_int cid_{-1};
  36. string message_;
  37. };
  38. const auto html = R"(
  39. <!DOCTYPE html>
  40. <html lang="en">
  41. <head>
  42. <meta charset="UTF-8">
  43. <title>SSE demo</title>
  44. </head>
  45. <body>
  46. <script>
  47. const ev1 = new EventSource("event1");
  48. ev1.onmessage = function(e) {
  49. console.log('ev1', e.data);
  50. }
  51. const ev2 = new EventSource("event2");
  52. ev2.onmessage = function(e) {
  53. console.log('ev2', e.data);
  54. }
  55. </script>
  56. </body>
  57. </html>
  58. )";
  59. int main(void) {
  60. EventDispatcher ed;
  61. Server svr;
  62. svr.Get("/", [&](const Request & /*req*/, Response &res) {
  63. res.set_content(html, "text/html");
  64. });
  65. svr.Get("/event1", [&](const Request & /*req*/, Response &res) {
  66. cout << "connected to event1..." << endl;
  67. res.set_chunked_content_provider("text/event-stream",
  68. [&](size_t /*offset*/, DataSink &sink) {
  69. return ed.wait_event(&sink);
  70. });
  71. });
  72. svr.Get("/event2", [&](const Request & /*req*/, Response &res) {
  73. cout << "connected to event2..." << endl;
  74. res.set_chunked_content_provider("text/event-stream",
  75. [&](size_t /*offset*/, DataSink &sink) {
  76. return ed.wait_event(&sink);
  77. });
  78. });
  79. thread t([&] {
  80. int id = 0;
  81. while (true) {
  82. this_thread::sleep_for(chrono::seconds(1));
  83. cout << "send event: " << id << std::endl;
  84. std::stringstream ss;
  85. ss << "data: " << id << "\n\n";
  86. ed.send_event(ss.str());
  87. id++;
  88. }
  89. });
  90. svr.listen("localhost", 1234);
  91. }