Line data Source code
1 : #include "Com/WebSocketServer.hpp" 2 : 3 : #include <spdlog/spdlog.h> 4 : 5 : #include <websocketpp/close.hpp> 6 : 7 : #include "GlobalState.hpp" 8 : #include "utils/string.hpp" 9 : 10 : using namespace std; 11 : using namespace Com; 12 : 13 : typedef websocketpp::server<websocketpp::config::asio> server; 14 : typedef server::message_ptr message_ptr; 15 : 16 : using websocketpp::lib::bind; 17 : using websocketpp::lib::placeholders::_1; 18 : 19 : typedef websocketpp::log::alevel alevel; 20 : 21 0 : WebSocketServer::WebSocketServer(int port) { 22 : // From https://github.com/zaphoyd/websocketpp/blob/master/examples/echo_server/echo_server.cpp 23 0 : try { 24 0 : spdlog::info("Starting WebSockets server"); 25 : 26 : // Set logging settings 27 0 : srv.set_access_channels(alevel::all); 28 0 : srv.clear_access_channels(alevel::frame_header | alevel::frame_payload); 29 : 30 : // Initialize Asio 31 0 : srv.init_asio(); 32 : 33 : // Register our message handler 34 0 : srv.set_open_handler(bind(&WebSocketServer::wsHandler, this, ::_1)); 35 : 36 : // Listen on port 9001 37 0 : srv.listen((uint16_t)port); 38 : 39 : // Start the server accept loop 40 0 : srv.start_accept(); 41 : 42 0 : spdlog::info("Started WebSockets server"); 43 0 : } catch(const exception &e) { 44 0 : spdlog::error("Exception, what(): {}", e.what()); 45 : } 46 0 : } 47 : 48 0 : void WebSocketServer::loop() { 49 : // Start the ASIO io_service run loop 50 0 : srv.run(); 51 0 : } 52 : 53 0 : void WebSocketServer::wsHandler(websocketpp::connection_hdl hdl) { 54 0 : thread t(&WebSocketServer::wsHandlerThread, this, hdl); 55 0 : t.detach(); 56 0 : } 57 : 58 0 : void WebSocketServer::wsHandlerThread(websocketpp::connection_hdl hdl) { 59 0 : try { 60 0 : wsStringStream(hdl); 61 0 : } catch(const exception &e) { 62 0 : spdlog::error("Exception, what(): {}", e.what()); 63 : } 64 0 : } 65 : 66 0 : void WebSocketServer::wsStringStream(websocketpp::connection_hdl hdl) { 67 : // From https://stackoverflow.com/questions/30514362/handle-websocketpp-connection-path 68 0 : server::connection_ptr con = srv.get_con_from_hdl(hdl); 69 : 70 0 : const string postfix = "/log"; 71 : 72 0 : const string &resource = con->get_resource(); 73 0 : assert(utils::ends_with(resource, postfix)); 74 0 : const string resourceID = resource.substr(0, resource.size() - postfix.size()); 75 0 : const string streamID = "stream://" + resourceID; 76 : 77 0 : try { 78 0 : utils::pipestream &ios = GlobalState::streams.get(streamID); 79 0 : istream &is = ios.i(); 80 : 81 0 : string payload; 82 0 : while(getline(is, payload)) { 83 0 : srv.send(hdl, payload, websocketpp::frame::opcode::binary); 84 : } 85 0 : } catch(const GlobalState::ResourceException &e) { 86 0 : srv.close(hdl, websocketpp::close::status::internal_endpoint_error, e.what()); 87 0 : return; 88 0 : } catch(const iostream::failure &e) { 89 0 : spdlog::error("Exception reading pipestream, what(): {}", e.what()); 90 0 : srv.close(hdl, websocketpp::close::status::internal_endpoint_error, "Exception, what(): "s + e.what()); 91 : } 92 : 93 0 : srv.close(hdl, websocketpp::close::status::normal, "EOF"); 94 : }