CppServer  1.0.0.0
C++ Server Library
websocket_server.inl
Go to the documentation of this file.
1 
9 namespace CppServer {
10 namespace Asio {
11 
12 template <class TServer, class TSession>
13 inline WebSocketServer<TServer, TSession>::WebSocketServer(std::shared_ptr<Service> service, InternetProtocol protocol, int port)
14  : _service(service),
15  _initialized(false),
16  _started(false),
17  _messages_sent(0),
18  _messages_received(0),
19  _bytes_sent(0),
20  _bytes_received(0)
21 {
22  assert((service != nullptr) && "ASIO service is invalid!");
23  if (service == nullptr)
24  throw CppCommon::ArgumentException("ASIO service is invalid!");
25 
26  switch (protocol)
27  {
29  _endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port);
30  break;
32  _endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v6(), port);
33  break;
34  }
35 
36  InitAsio();
37 }
38 
39 template <class TServer, class TSession>
40 inline WebSocketServer<TServer, TSession>::WebSocketServer(std::shared_ptr<Service> service, const std::string& address, int port)
41  : _service(service),
42  _initialized(false),
43  _started(false),
44  _messages_sent(0),
45  _messages_received(0),
46  _bytes_sent(0),
47  _bytes_received(0)
48 {
49  assert((service != nullptr) && "ASIO service is invalid!");
50  if (service == nullptr)
51  throw CppCommon::ArgumentException("ASIO service is invalid!");
52 
53  _endpoint = asio::ip::tcp::endpoint(asio::ip::address::from_string(address), port);
54 
55  InitAsio();
56 }
57 
58 template <class TServer, class TSession>
59 inline WebSocketServer<TServer, TSession>::WebSocketServer(std::shared_ptr<Service> service, const asio::ip::tcp::endpoint& endpoint)
60  : _service(service),
61  _endpoint(endpoint),
62  _initialized(false),
63  _started(false),
64  _messages_sent(0),
65  _messages_received(0),
66  _bytes_sent(0),
67  _bytes_received(0)
68 {
69  assert((service != nullptr) && "ASIO service is invalid!");
70  if (service == nullptr)
71  throw CppCommon::ArgumentException("ASIO service is invalid!");
72 
73  InitAsio();
74 }
75 
76 template <class TServer, class TSession>
78 {
79  assert(!_initialized && "Asio is already initialed!");
80  if (_initialized)
81  return;
82 
83  // Setup WebSocket server core Asio service
84  websocketpp::lib::error_code ec;
85  _core.init_asio(_service->service().get(), ec);
86  if (ec)
87  {
88  SendError(ec);
89  return;
90  }
91 
92  _initialized = true;
93 }
94 
95 template <class TServer, class TSession>
97 {
98  assert(_initialized && "Asio is not initialed!");
99  if (!_initialized)
100  return false;
101 
102  assert(!IsStarted() && "WebSocket server is already started!");
103  if (IsStarted())
104  return false;
105 
106  // Post the start routine
107  auto self(this->shared_from_this());
108  _service->service()->post([this, self]()
109  {
110  websocketpp::lib::error_code ec;
111 
112  // Setup WebSocket server core logging
113  _core.set_access_channels(websocketpp::log::alevel::none);
114  _core.set_error_channels(websocketpp::log::elevel::none);
115 
116  // Setup WebSocket server core handlers
117  _core.set_open_handler([this](websocketpp::connection_hdl connection) { RegisterSession(connection); });
118  _core.set_close_handler([this](websocketpp::connection_hdl connection) { UnregisterSession(connection); });
119 
120  // Start WebSocket server core
121  _core.listen(_endpoint, ec);
122  if (ec)
123  {
124  SendError(ec);
125  onStopped();
126  return;
127  }
128 
129  // Reset statistic
130  _messages_sent = 0;
131  _messages_received = 0;
132  _bytes_sent = 0;
133  _bytes_received = 0;
134 
135  // Update the started flag
136  _started = true;
137 
138  // Call the server started handler
139  onStarted();
140 
141  // Start WebSocket core acceptor
142  _core.start_accept(ec);
143  if (ec)
144  {
145  SendError(ec);
146  Stop();
147  return;
148  }
149  });
150 
151  return true;
152 }
153 
154 template <class TServer, class TSession>
156 {
157  assert(IsStarted() && "WebSocket server is not started!");
158  if (!IsStarted())
159  return false;
160 
161  // Post the stopped routine
162  auto self(this->shared_from_this());
163  _service->service()->post([this, self]()
164  {
165  // Stop WebSocket server
166  websocketpp::lib::error_code ec;
167  _core.stop_listening(ec);
168  if (ec)
169  SendError(ec);
170 
171  // Clear multicast buffer
172  ClearBuffers();
173 
174  // Disconnect all sessions
175  DisconnectAll();
176 
177  // Update the started flag
178  _started = false;
179 
180  // Call the server stopped handler
181  onStopped();
182  });
183 
184  return true;
185 }
186 
187 template <class TServer, class TSession>
189 {
190  if (!Stop())
191  return false;
192 
193  while (IsStarted())
194  CppCommon::Thread::Yield();
195 
196  return Start();
197 }
198 
199 template <class TServer, class TSession>
200 inline bool WebSocketServer<TServer, TSession>::Multicast(const void* buffer, size_t size, websocketpp::frame::opcode::value opcode)
201 {
202  assert((buffer != nullptr) && "Pointer to the buffer should not be equal to 'nullptr'!");
203  assert((size > 0) && "Buffer size should be greater than zero!");
204  if ((buffer == nullptr) || (size == 0))
205  return false;
206 
207  if (!IsStarted())
208  return false;
209 
210  {
211  std::lock_guard<std::mutex> locker(_multicast_lock);
212 
213  // Fill the multicast buffer
214  std::vector<uint8_t> message((const uint8_t*)buffer, ((const uint8_t*)buffer) + size);
215  _multicast_buffer.emplace_back(std::make_tuple(message, opcode));
216  }
217 
218  MulticastAll();
219  return true;
220 }
221 
222 template <class TServer, class TSession>
223 inline bool WebSocketServer<TServer, TSession>::Multicast(const std::string& text, websocketpp::frame::opcode::value opcode)
224 {
225  if (!IsStarted())
226  return false;
227 
228  {
229  std::lock_guard<std::mutex> locker(_multicast_lock);
230 
231  // Fill the multicast buffer
232  _multicast_text.emplace_back(std::make_tuple(text, opcode));
233  }
234 
235  MulticastAll();
236  return true;
237 }
238 
239 template <class TServer, class TSession>
241 {
242  if (!IsStarted())
243  return false;
244 
245  {
246  std::lock_guard<std::mutex> locker(_multicast_lock);
247 
248  // Fill the multicast buffer
249  _multicast_messages.push_back(message);
250  }
251 
252  MulticastAll();
253  return true;
254 }
255 
256 template <class TServer, class TSession>
258 {
259  // Dispatch the multicast routine
260  auto self(this->shared_from_this());
261  _service->Dispatch([this, self]()
262  {
263  std::lock_guard<std::mutex> locker(_multicast_lock);
264 
265  // Multicast all sessions
266  for (auto& session : _sessions)
267  {
268  for (auto& message : _multicast_buffer)
269  session.second->Send(std::get<0>(message).data(), std::get<0>(message).size(), std::get<1>(message));
270  for (auto& text : _multicast_text)
271  session.second->Send(std::get<0>(text), std::get<1>(text));
272  for (auto& message : _multicast_messages)
273  session.second->Send(message);
274  }
275 
276  // Clear the multicast buffers
277  _multicast_buffer.clear();
278  _multicast_text.clear();
279  _multicast_messages.clear();
280  });
281 }
282 
283 template <class TServer, class TSession>
285 {
286  if (!IsStarted())
287  return false;
288 
289  // Dispatch the disconnect routine
290  auto self(this->shared_from_this());
291  _service->Dispatch([this, self]()
292  {
293  // Disconnect all sessions
294  for (auto& session : _sessions)
295  session.second->Disconnect();
296  });
297 
298  return true;
299 }
300 
301 template <class TServer, class TSession>
302 inline std::shared_ptr<TSession> WebSocketServer<TServer, TSession>::RegisterSession(websocketpp::connection_hdl connection)
303 {
304  // Create and register a new session
305  auto self(this->shared_from_this());
306  auto session = std::make_shared<TSession>(self);
307  _connections.insert(std::make_pair(connection, session));
308  _sessions.insert(std::make_pair(session->id(), session));
309 
310  // Connect a new session
311  session->Connect(connection);
312 
313  // Call a new session connected handler
314  onConnected(session);
315 
316  return session;
317 }
318 
319 template <class TServer, class TSession>
320 inline void WebSocketServer<TServer, TSession>::UnregisterSession(websocketpp::connection_hdl connection)
321 {
322  // Try to find the unregistered connection
323  auto it = _connections.find(connection);
324  if (it != _connections.end())
325  {
326  // Call the session disconnected handler
327  it->second->Disconnected();
328  }
329 }
330 
331 template <class TServer, class TSession>
332 inline void WebSocketServer<TServer, TSession>::UnregisterSession(const CppCommon::UUID& id)
333 {
334  // Try to find the unregistered session
335  auto it = _sessions.find(id);
336  if (it != _sessions.end())
337  {
338  // Call the session disconnected handler
339  onDisconnected(it->second);
340 
341  // Erase the connection
342  _connections.erase(_connections.find(it->second->connection()));
343 
344  // Erase the session
345  _sessions.erase(it);
346  }
347 }
348 
349 template <class TServer, class TSession>
350 inline void WebSocketServer<TServer, TSession>::ClearBuffers()
351 {
352  std::lock_guard<std::mutex> locker(_multicast_lock);
353 
354  _multicast_buffer.clear();
355  _multicast_text.clear();
356  _multicast_messages.clear();
357 }
358 
359 template <class TServer, class TSession>
360 inline void WebSocketServer<TServer, TSession>::SendError(std::error_code ec)
361 {
362  onError(ec.value(), ec.category().name(), ec.message());
363 }
364 
365 } // namespace Asio
366 } // namespace CppServer
bool Restart()
Restart the server.
bool DisconnectAll()
Disconnect all connected sessions.
bool Multicast(const void *buffer, size_t size, websocketpp::frame::opcode::value opcode=websocketpp::frame::opcode::binary)
Multicast data to all connected sessions.
InternetProtocol
Internet protocol.
Definition: asio.h:36
std::shared_ptr< Service > & service() noexcept
Get the Asio service.
Internet Protocol version 4.
C++ Server project definitions.
Definition: asio.h:24
bool Start()
Start the server.
WebSocketServer(std::shared_ptr< Service > service, InternetProtocol protocol, int port)
Initialize WebSocket server with a given Asio service, protocol and port number.
WebSocketConnection::message_ptr WebSocketMessage
WebSocket message.
Definition: websocket.h:31
Internet Protocol version 6.