| 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_;intmain(){	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;}
 |