sse.cc 2.3 KB

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