123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- #include <iostream>
- #include <memory>
- #include <mutex>
- #include <sstream>
- #include <unistd.h>
- #include <unordered_map>
- #include "CivetServer.h"
- class WebSocketBase : public CivetWebSocketHandler
- {
- public:
- explicit WebSocketBase(std::string name) : name_(std::move(name))
- {
- }
- bool
- handleConnection(CivetServer *server, const mg_connection *conn) override
- {
- return true;
- }
- void
- handleReadyState(CivetServer *server, mg_connection *conn) override
- {
- std::unique_lock<std::mutex> lock(mutex_);
- pool_.emplace(conn, std::make_shared<std::mutex>());
- }
- bool
- handleData(CivetServer *server,
- mg_connection *conn,
- int bits,
- char *data,
- size_t data_len) override
- {
- if ((bits & 0x0F) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
- return false;
- }
- data_.write(data, data_len);
- if (current_opcode_ == 0x00) {
- current_opcode_ = bits & 0x7f;
- }
- bool is_final_fragment = bits & 0x80;
- if (is_final_fragment) {
- switch (current_opcode_) {
- case MG_WEBSOCKET_OPCODE_TEXT:
- std::cout << data_.str() << std::endl; // print request data
- break;
- default:
- break;
- }
- current_opcode_ = 0x00;
- this->sendData(conn, data_.str()); // response
- data_.clear();
- data_.str(std::string());
- }
- return true;
- }
- void
- handleClose(CivetServer *server, const mg_connection *conn) override
- {
- auto *connection = const_cast<mg_connection *>(conn);
- std::shared_ptr<std::mutex> user_lock;
- {
- std::unique_lock<std::mutex> lock(mutex_);
- user_lock = pool_[connection];
- }
- {
- std::unique_lock<std::mutex> lock_connection(*user_lock);
- std::unique_lock<std::mutex> lock(mutex_);
- pool_.erase(connection);
- }
- }
- bool
- sendData(mg_connection *conn,
- const std::string &data,
- bool skippable = false,
- int op_code = MG_WEBSOCKET_OPCODE_TEXT)
- {
- std::shared_ptr<std::mutex> connection_lock;
- {
- std::unique_lock<std::mutex> lock(mutex_);
- connection_lock = pool_[conn];
- }
- if (!connection_lock->try_lock()) {
- if (skippable) {
- return false;
- }
- connection_lock->lock();
- std::unique_lock<std::mutex> lock(mutex_);
- }
- int ret = mg_websocket_write(conn, op_code, data.c_str(), data.size());
- connection_lock->unlock();
- if (ret != static_cast<int>(data.size())) {
- if (data.empty() && ret == 2) {
- return true;
- }
- return false;
- }
- return true;
- }
- thread_local static std::stringstream data_;
- thread_local static unsigned char current_opcode_;
- private:
- const std::string name_;
- mutable std::mutex mutex_;
- std::unordered_map<mg_connection *, std::shared_ptr<std::mutex>> pool_;
- };
- thread_local unsigned char WebSocketBase::current_opcode_ = 0x00;
- thread_local std::stringstream WebSocketBase::data_;
- int
- main()
- {
- std::cout << "Hello, Civetweb Websocket port:8080!" << std::endl;
- mg_init_library(0);
- std::vector<std::string> options = {
- "document_root",
- ".",
- "listening_ports",
- "8080",
- "access_control_allow_headers",
- "*",
- "access_control_allow_methods",
- "*",
- "access_control_allow_origin",
- "*",
- };
- auto server = std::make_shared<CivetServer>(options);
- auto ws = std::make_shared<WebSocketBase>("simple");
- server->addWebSocketHandler("/ws", *ws);
- while (true) {
- sleep(1);
- }
- server->close();
- return 0;
- }
|