sse.cc 2.2 KB

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