|
| 1 | +#include <set> |
1 | 2 | #include <websocketpp/config/asio_no_tls.hpp>
|
2 | 3 | #include <websocketpp/server.hpp>
|
3 |
| - |
4 | 4 | #include <iostream>
|
5 | 5 |
|
6 |
| -typedef websocketpp::server<websocketpp::config::asio> server; |
7 | 6 |
|
| 7 | +struct connection_data { |
| 8 | + int session; |
| 9 | + std::string room; |
| 10 | +}; |
| 11 | + |
| 12 | +struct custom_config : public websocketpp::config::asio { |
| 13 | + // Default settings from our core config |
| 14 | + typedef websocketpp::config::asio core; |
| 15 | + |
| 16 | + typedef core::concurrency_type concurrency_type; |
| 17 | + typedef core::request_type request_type; |
| 18 | + typedef core::response_type response_type; |
| 19 | + typedef core::message_type message_type; |
| 20 | + typedef core::con_msg_manager_type con_msg_manager_type; |
| 21 | + typedef core::endpoint_msg_manager_type endpoint_msg_manager_type; |
| 22 | + typedef core::alog_type alog_type; |
| 23 | + typedef core::elog_type elog_type; |
| 24 | + typedef core::rng_type rng_type; |
| 25 | + typedef core::transport_type transport_type; |
| 26 | + typedef core::endpoint_base endpoint_base; |
| 27 | + |
| 28 | + // Set a custom connection_base class to handle indetification. |
| 29 | + typedef connection_data connection_base; |
| 30 | +}; |
| 31 | + |
| 32 | +typedef websocketpp::server<custom_config> server; |
| 33 | +typedef server::connection_ptr connection_ptr; |
| 34 | +typedef server::message_ptr message_ptr; |
| 35 | +typedef server::connection_ptr connection_ptr; |
| 36 | + |
| 37 | +using websocketpp::connection_hdl; |
8 | 38 | using websocketpp::lib::placeholders::_1;
|
9 | 39 | using websocketpp::lib::placeholders::_2;
|
10 | 40 | using websocketpp::lib::bind;
|
11 | 41 |
|
12 |
| -// pull out the type of messages sent by our config |
13 |
| -typedef server::message_ptr message_ptr; |
14 | 42 |
|
15 |
| -// Define a callback to handle incoming messages |
16 |
| -void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) { |
17 |
| - try { |
18 |
| - s->send(hdl, msg->get_payload(), msg->get_opcode()); |
19 |
| - } catch (websocketpp::exception const & e) { |
20 |
| - std::cout << "Error: " |
21 |
| - << "(" << e.what() << ")" << std::endl; |
| 43 | +// This class will be heart of our app. |
| 44 | +class EchoServer |
| 45 | +{ |
| 46 | +public: |
| 47 | + EchoServer() |
| 48 | + { |
| 49 | + // Try to not fail. Please. I have faith on you. |
| 50 | + try { |
| 51 | + // Set logging settings |
| 52 | + _server.set_access_channels(websocketpp::log::alevel::none); |
| 53 | + _server.clear_access_channels(websocketpp::log::alevel::none); |
| 54 | + _server.init_asio(); |
| 55 | + |
| 56 | + // Message handler |
| 57 | + _server.set_open_handler(bind(&EchoServer::onOpen,this,::_1)); |
| 58 | + _server.set_close_handler(bind(&EchoServer::onClose,this,::_1)); |
| 59 | + _server.set_message_handler(bind(&EchoServer::onMessage,this,::_1,::_2)); |
| 60 | + _server.listen(80); |
| 61 | + |
| 62 | + // Tell something :) |
| 63 | + std::cout << "Starting GameTactic CPP Echo server...\n"; |
| 64 | + std::cout << "--------------------------------------------------------\n"; |
| 65 | + std::cout << "| Copyright 2019 Niko Granö <niko@ironlions.fi> |\n"; |
| 66 | + std::cout << "| Licensed under GPLv3. |\n"; |
| 67 | + std::cout << "| https://gametactic.eu |\n"; |
| 68 | + std::cout << "--------------------------------------------------------\n\n"; |
| 69 | + |
| 70 | + // Start the server. |
| 71 | + _server.start_accept(); |
| 72 | + _server.run(); |
| 73 | + } catch (websocketpp::exception const & e) { |
| 74 | + std::cout << e.what() << std::endl; |
| 75 | + } catch (...) { |
| 76 | + std::cout << "Error: " << std::endl; |
| 77 | + } |
22 | 78 | }
|
23 |
| -} |
24 | 79 |
|
| 80 | + // Callback to handle incoming messages |
| 81 | + void onMessage(connection_hdl conn, message_ptr msg) { |
| 82 | + // Get connection |
| 83 | + connection_ptr ptr = _server.get_con_from_hdl(conn); |
| 84 | + |
| 85 | + // Check if client is requesting to join. |
| 86 | + if (msg->get_payload().substr(0,5) == "join:") { |
| 87 | + std::string room = msg->get_payload().substr(5); |
| 88 | + ptr->room = room; |
| 89 | + std::stringstream ss; |
| 90 | + ss << "{\"success\":\"Room " << room << " selected.\"}"; |
| 91 | + ptr->send(ss.str()); |
| 92 | + |
| 93 | + return; |
| 94 | + } |
| 95 | + |
| 96 | + if (ptr->room.empty()) { |
| 97 | + ptr->send("{\"error\":\"No room selected.\"}"); |
| 98 | + |
| 99 | + return; |
| 100 | + } |
| 101 | + |
| 102 | + try { |
| 103 | + for (auto c : _connections) { |
| 104 | + connection_ptr _ptr = _server.get_con_from_hdl(c); |
| 105 | + if (_ptr->room == ptr->room) { |
| 106 | + _server.send(c,msg); |
| 107 | + } |
| 108 | + } |
| 109 | + } catch (websocketpp::exception const &e) { |
| 110 | + std::cout << "Error: " << "(" << e.what() << ")" << std::endl; |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + // Callback to handle new connections |
| 115 | + void onOpen(connection_hdl conn) { |
| 116 | + connection_ptr ptr = _server.get_con_from_hdl(conn); |
| 117 | + ptr->session = _session++; |
| 118 | + _connections.insert(conn); |
| 119 | + } |
| 120 | + |
| 121 | + // Callback to handle closing connection |
| 122 | + void onClose(connection_hdl conn) { |
| 123 | + connection_ptr ptr = _server.get_con_from_hdl(conn); |
| 124 | + _connections.erase(conn); |
| 125 | + } |
| 126 | + |
| 127 | +private: |
| 128 | + typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list; |
| 129 | + |
| 130 | + // Create a server and list for connections. |
| 131 | + server _server; |
| 132 | + con_list _connections; |
| 133 | + |
| 134 | + // Every client has own id to help identify. |
| 135 | + int _session; |
| 136 | + |
| 137 | + // Rooms |
| 138 | + //std::map<int, string::string> _rooms; |
| 139 | + //std::vector<std::map<std::string, std::string>> _rooms; |
| 140 | +}; |
| 141 | + |
| 142 | +// Basic signal hander |
25 | 143 | void signalHandler( int signum ) {
|
26 | 144 | std::cout << "Interrupt signal (" << signum << ") received.\n";
|
27 | 145 | exit(signum);
|
28 | 146 | }
|
29 | 147 |
|
30 |
| - |
31 | 148 | int main() {
|
32 | 149 | // Handle signals.
|
33 | 150 | signal(SIGINT, signalHandler);
|
34 | 151 |
|
35 |
| - // Create a server endpoint |
36 |
| - server _server; |
37 |
| - |
38 |
| - try { |
39 |
| - // Set logging settings |
40 |
| - _server.set_access_channels(websocketpp::log::alevel::none); |
41 |
| - _server.clear_access_channels(websocketpp::log::alevel::none); |
42 |
| - _server.init_asio(); |
43 |
| - |
44 |
| - // Message handler |
45 |
| - _server.set_message_handler(bind(&on_message,&_server,::_1,::_2)); |
46 |
| - _server.listen(80); |
47 |
| - |
48 |
| - // Tell something :) |
49 |
| - std::cout << "Starting GameTactic CPP Echo server...\n"; |
50 |
| - std::cout << "--------------------------------------------------------------------------------\n"; |
51 |
| - std::cout << "| Copyright 2019 Niko Granö <niko@ironlions.fi> |\n"; |
52 |
| - std::cout << "| Licensed under GPLv3. |\n"; |
53 |
| - std::cout << "| https://gametactic.eu |\n"; |
54 |
| - std::cout << "--------------------------------------------------------------------------------\n\n"; |
55 |
| - |
56 |
| - // Start the server. |
57 |
| - // First start itself, second start asio. |
58 |
| - _server.start_accept(); |
59 |
| - _server.run(); |
60 |
| - } catch (websocketpp::exception const & e) { |
61 |
| - std::cout << e.what() << std::endl; |
62 |
| - } catch (...) { |
63 |
| - std::cout << "Error: " << std::endl; |
64 |
| - } |
| 152 | + // Start app. |
| 153 | + EchoServer srv; |
65 | 154 | }
|
0 commit comments