Giri's C++ Support Library
C++ library providing everything you need to quickly create awesome applications.
WebSocketClient.h
Go to the documentation of this file.
1 
10 #ifndef SUPPORTLIB_WEBSOCKETCLIENT_H
11 #define SUPPORTLIB_WEBSOCKETCLIENT_H
12 #include "Observer.h"
13 #include "Exception.h"
14 #include <boost/asio/ip/tcp.hpp>
15 #include <boost/beast/core.hpp>
16 #include <boost/beast/websocket.hpp>
17 #include <boost/beast/websocket/ssl.hpp>
18 #include <boost/asio/connect.hpp>
19 #include <boost/asio/ssl/stream.hpp>
20 #include <cstdlib>
21 #include <iostream>
22 #include <string>
23 #include <thread>
24 
25 namespace giri {
26  using tcp = boost::asio::ip::tcp;
27  namespace ssl = boost::asio::ssl;
28  namespace websocket = boost::beast::websocket;
29 
34  {
35  public:
36  WebSocketClientException(const std::string &msg) : ExceptionBase(msg) {};
37  using SPtr = std::shared_ptr<WebSocketClientException>;
38  using UPtr = std::unique_ptr<WebSocketClientException>;
39  using WPtr = std::weak_ptr<WebSocketClientException>;
40  };
41 
91  class WebSocketClient : public Observable<WebSocketClient>
92  {
93  public:
102  WebSocketClient(const std::string& host, const std::string& port, bool ssl = false, const size_t numThreads = 1, const std::string& resource = "/") :
103  m_Host(host),
104  m_Port(port),
105  m_Resource(resource),
106  m_SSL(ssl),
107  m_Ioc(numThreads)
108  {
109  auto const results = m_Resolver.resolve(m_Host, m_Port);
110  if(m_SSL)
111  {
112  boost::asio::connect(m_Wss.next_layer().next_layer(), results.begin(), results.end());
113  m_Wss.next_layer().handshake(ssl::stream_base::client);
114  m_Wss.handshake(host, m_Resource);
115  m_Wss.text(true);
116  }
117  else
118  {
119  boost::asio::connect(m_Ws.next_layer(), results.begin(), results.end());
120  m_Ws.handshake(host, m_Resource);
121  m_Ws.text(true);
122  }
123  m_Threads.reserve(numThreads);
124  for(auto i = numThreads; i > 0; --i)
125  m_Threads.emplace_back(std::thread([this]{ m_Ioc.run();}));
126  }
131  void send(const std::string& msg){
132  if(!m_Ec)
133  if(m_SSL)
134  {if(m_Wss.is_open()){m_Wss.write(boost::asio::buffer(msg));}}
135  else
136  {if(m_Ws.is_open()){m_Ws.write(boost::asio::buffer(msg));}}
137  }
141  std::string getMessage(){
142  return m_Message;
143  }
147  std::string getHost(){
148  return m_Host;
149  }
153  std::string getPort(){
154  return m_Port;
155  }
159  bool getSSL(){
160  return m_SSL;
161  }
165  boost::system::error_code getError(){
166  return m_Ec;
167  }
172  void run(){
173  if(m_SSL)
174  {if(m_Wss.is_open()){m_Wss.async_read(m_Buffer, std::bind(&WebSocketClient::on_read, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));}}
175  else
176  {if(m_Ws.is_open()){m_Ws.async_read(m_Buffer, std::bind(&WebSocketClient::on_read, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));}}
177  }
182  std::string receive(){
183  if(!m_Ec)
184  if(m_SSL)
185  {if(m_Wss.is_open()){m_Wss.read(m_Buffer);}}
186  else
187  {if(m_Ws.is_open()){m_Ws.read(m_Buffer);}}
188  m_Message = boost::beast::buffers_to_string(m_Buffer.data());
189  return m_Message;
190  }
194  void close() {
195  if(!m_Ec)
196  if(m_SSL)
197  {if(m_Wss.is_open()){m_Wss.close(websocket::close_code::normal);}}
198  else
199  {if(m_Ws.is_open()){m_Ws.close(websocket::close_code::normal);}}
200  }
201  using SPtr = std::shared_ptr<WebSocketClient>;
202  using UPtr = std::unique_ptr<WebSocketClient>;
203  private:
204  void on_read(boost::system::error_code ec, std::size_t bytes_transferred) {
205  m_Ec = ec;
206  m_Message.clear();
207  if(!ec){
208  m_Message = boost::beast::buffers_to_string(m_Buffer.data());
209  }
210  m_Buffer.consume(m_Buffer.size()); // clear buffer
211  notify(); // notify all subscribed observers
212  if(!ec)
213  run(); // wait for new message
214  }
215  std::string m_Host;
216  std::string m_Port;
217  std::string m_Resource;
218  std::string m_Message;
219  bool m_SSL;
220  boost::asio::io_context m_Ioc;
221  tcp::resolver m_Resolver{m_Ioc};
222  ssl::context m_Ctx{ssl::context::sslv23_client};
223  websocket::stream<tcp::socket> m_Ws{m_Ioc};
224  websocket::stream<ssl::stream<tcp::socket>> m_Wss{m_Ioc, m_Ctx};
225  boost::beast::multi_buffer m_Buffer;
226  boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_WG = boost::asio::make_work_guard(m_Ioc);
227  std::vector<std::thread> m_Threads;
228  boost::system::error_code m_Ec;
229  };
230 }
231 #endif //SUPPORTLIB_WEBSOCKETCLIENT_H
Base exception to inherit custom exceptions from.
Observer/Obersvable Pattern implementation.
Base exception to inherit custom exceptions from.
Definition: Exception.h:48
ExceptionBase(const std::string &msg="")
Definition: Exception.h:54
Observable class. Inherited classes can notify all classes which inherit from Observer.
Definition: Observer.h:99
void notify()
Definition: Observer.h:130
Exception to be thrown on websocket client errors.
Definition: WebSocketClient.h:34
Simple Websocket Client.
Definition: WebSocketClient.h:92
void close()
Definition: WebSocketClient.h:194
void run()
Definition: WebSocketClient.h:172
WebSocketClient(const std::string &host, const std::string &port, bool ssl=false, const size_t numThreads=1, const std::string &resource="/")
Definition: WebSocketClient.h:102
std::string getHost()
Definition: WebSocketClient.h:147
std::string getMessage()
Definition: WebSocketClient.h:141
bool getSSL()
Definition: WebSocketClient.h:159
std::string receive()
Definition: WebSocketClient.h:182
void send(const std::string &msg)
msg Message to send
Definition: WebSocketClient.h:131
boost::system::error_code getError()
Definition: WebSocketClient.h:165
std::string getPort()
Definition: WebSocketClient.h:153
Namespace for giri's C++ support library.
Definition: Base64.h:47