ssesvr.cc 2.4 KB

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