main.cc 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include <iostream>
  2. #include <memory>
  3. #include <mutex>
  4. #include <sstream>
  5. #include <unistd.h>
  6. #include <unordered_map>
  7. #include "CivetServer.h"
  8. class WebSocketBase : public CivetWebSocketHandler
  9. {
  10. public:
  11. explicit WebSocketBase(std::string name) : name_(std::move(name))
  12. {
  13. }
  14. bool
  15. handleConnection(CivetServer *server, const mg_connection *conn) override
  16. {
  17. return true;
  18. }
  19. void
  20. handleReadyState(CivetServer *server, mg_connection *conn) override
  21. {
  22. std::unique_lock<std::mutex> lock(mutex_);
  23. pool_.emplace(conn, std::make_shared<std::mutex>());
  24. }
  25. bool
  26. handleData(CivetServer *server,
  27. mg_connection *conn,
  28. int bits,
  29. char *data,
  30. size_t data_len) override
  31. {
  32. if ((bits & 0x0F) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
  33. return false;
  34. }
  35. data_.write(data, data_len);
  36. if (current_opcode_ == 0x00) {
  37. current_opcode_ = bits & 0x7f;
  38. }
  39. bool is_final_fragment = bits & 0x80;
  40. if (is_final_fragment) {
  41. switch (current_opcode_) {
  42. case MG_WEBSOCKET_OPCODE_TEXT:
  43. std::cout << data_.str() << std::endl; // print request data
  44. break;
  45. default:
  46. break;
  47. }
  48. current_opcode_ = 0x00;
  49. this->sendData(conn, data_.str()); // response
  50. data_.clear();
  51. data_.str(std::string());
  52. }
  53. return true;
  54. }
  55. void
  56. handleClose(CivetServer *server, const mg_connection *conn) override
  57. {
  58. auto *connection = const_cast<mg_connection *>(conn);
  59. std::shared_ptr<std::mutex> user_lock;
  60. {
  61. std::unique_lock<std::mutex> lock(mutex_);
  62. user_lock = pool_[connection];
  63. }
  64. {
  65. std::unique_lock<std::mutex> lock_connection(*user_lock);
  66. std::unique_lock<std::mutex> lock(mutex_);
  67. pool_.erase(connection);
  68. }
  69. }
  70. bool
  71. sendData(mg_connection *conn,
  72. const std::string &data,
  73. bool skippable = false,
  74. int op_code = MG_WEBSOCKET_OPCODE_TEXT)
  75. {
  76. std::shared_ptr<std::mutex> connection_lock;
  77. {
  78. std::unique_lock<std::mutex> lock(mutex_);
  79. connection_lock = pool_[conn];
  80. }
  81. if (!connection_lock->try_lock()) {
  82. if (skippable) {
  83. return false;
  84. }
  85. connection_lock->lock();
  86. std::unique_lock<std::mutex> lock(mutex_);
  87. }
  88. int ret = mg_websocket_write(conn, op_code, data.c_str(), data.size());
  89. connection_lock->unlock();
  90. if (ret != static_cast<int>(data.size())) {
  91. if (data.empty() && ret == 2) {
  92. return true;
  93. }
  94. return false;
  95. }
  96. return true;
  97. }
  98. thread_local static std::stringstream data_;
  99. thread_local static unsigned char current_opcode_;
  100. private:
  101. const std::string name_;
  102. mutable std::mutex mutex_;
  103. std::unordered_map<mg_connection *, std::shared_ptr<std::mutex>> pool_;
  104. };
  105. thread_local unsigned char WebSocketBase::current_opcode_ = 0x00;
  106. thread_local std::stringstream WebSocketBase::data_;
  107. int
  108. main()
  109. {
  110. std::cout << "Hello, Civetweb Websocket port:8080!" << std::endl;
  111. mg_init_library(0);
  112. std::vector<std::string> options = {
  113. "document_root",
  114. ".",
  115. "listening_ports",
  116. "8080",
  117. "access_control_allow_headers",
  118. "*",
  119. "access_control_allow_methods",
  120. "*",
  121. "access_control_allow_origin",
  122. "*",
  123. };
  124. auto server = std::make_shared<CivetServer>(options);
  125. auto ws = std::make_shared<WebSocketBase>("simple");
  126. server->addWebSocketHandler("/ws", *ws);
  127. while (true) {
  128. sleep(1);
  129. }
  130. server->close();
  131. return 0;
  132. }