add ws_chat and ws_connect sub commands to ws
This commit is contained in:
		| @@ -14,6 +14,7 @@ set (CMAKE_CXX_STANDARD 14) | ||||
| option(USE_TLS "Add TLS support" ON) | ||||
|  | ||||
| include_directories(ws .) | ||||
| include_directories(ws ..) | ||||
| include_directories(ws ../third_party) | ||||
|  | ||||
| add_executable(ws  | ||||
| @@ -22,6 +23,8 @@ add_executable(ws | ||||
|   ixcrypto/IXHash.cpp | ||||
|   ixcrypto/IXUuid.cpp | ||||
|  | ||||
|   ws_chat.cpp | ||||
|   ws_connect.cpp | ||||
|   ws_transfer.cpp | ||||
|   ws_send.cpp | ||||
|   ws_receive.cpp | ||||
|   | ||||
| @@ -28,6 +28,8 @@ g++ --std=c++14 \ | ||||
|     ixcrypto/IXBase64.cpp \ | ||||
|     ixcrypto/IXHash.cpp \ | ||||
|     ixcrypto/IXUuid.cpp \ | ||||
|     ws_chat.cpp \ | ||||
|     ws_connect.cpp \ | ||||
|     ws_transfer.cpp \ | ||||
|     ws_send.cpp \ | ||||
|     ws_receive.cpp \ | ||||
|   | ||||
							
								
								
									
										27
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								ws/ws.cpp
									
									
									
									
									
								
							| @@ -16,13 +16,18 @@ | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     int ws_chat_main(const std::string& url, | ||||
|                      const std::string& user); | ||||
|  | ||||
|     int ws_connect_main(const std::string& url); | ||||
|  | ||||
|     int ws_receive_main(const std::string& url, | ||||
|                         bool enablePerMessageDeflate); | ||||
|  | ||||
|     extern int ws_transfer_main(int port); | ||||
|     int ws_transfer_main(int port); | ||||
|  | ||||
|     extern int ws_send_main(const std::string& url, | ||||
|                             const std::string& path); | ||||
|     int ws_send_main(const std::string& url, | ||||
|                      const std::string& path); | ||||
| } | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| @@ -32,6 +37,7 @@ int main(int argc, char** argv) | ||||
|  | ||||
|     std::string url; | ||||
|     std::string path; | ||||
|     std::string user; | ||||
|     int port = 8080; | ||||
|  | ||||
|     CLI::App* sendApp = app.add_subcommand("send", "Send a file"); | ||||
| @@ -44,6 +50,13 @@ int main(int argc, char** argv) | ||||
|     CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server"); | ||||
|     transferApp->add_option("--port", port, "Connection url"); | ||||
|  | ||||
|     CLI::App* connectApp = app.add_subcommand("connect", "Connect to a remote server"); | ||||
|     connectApp->add_option("url", url, "Connection url")->required(); | ||||
|  | ||||
|     CLI::App* chatApp = app.add_subcommand("chat", "Group chat"); | ||||
|     chatApp->add_option("url", url, "Connection url")->required(); | ||||
|     chatApp->add_option("user", user, "User name")->required(); | ||||
|  | ||||
|     CLI11_PARSE(app, argc, argv); | ||||
|  | ||||
|     if (app.got_subcommand("transfer")) | ||||
| @@ -59,6 +72,14 @@ int main(int argc, char** argv) | ||||
|         bool enablePerMessageDeflate = false; | ||||
|         return ix::ws_receive_main(url, enablePerMessageDeflate); | ||||
|     } | ||||
|     else if (app.got_subcommand("connect")) | ||||
|     { | ||||
|         return ix::ws_connect_main(url); | ||||
|     } | ||||
|     else if (app.got_subcommand("chat")) | ||||
|     { | ||||
|         return ix::ws_chat_main(url, user); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         assert(false); | ||||
|   | ||||
							
								
								
									
										201
									
								
								ws/ws_chat.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								ws/ws_chat.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | ||||
| /* | ||||
|  *  ws_chat.cpp | ||||
|  *  Author: Benjamin Sergeant | ||||
|  *  Copyright (c) 2017-2019 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| // | ||||
| // Simple chat program that talks to the node.js server at | ||||
| // websocket_chat_server/broacast-server.js | ||||
| // | ||||
|  | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <queue> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
|  | ||||
| #include "nlohmann/json.hpp" | ||||
|  | ||||
| // for convenience | ||||
| using json = nlohmann::json; | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     class WebSocketChat | ||||
|     { | ||||
|         public: | ||||
|             WebSocketChat(const std::string& url, | ||||
|                           const std::string& user); | ||||
|  | ||||
|             void subscribe(const std::string& channel); | ||||
|             void start(); | ||||
|             void stop(); | ||||
|             bool isReady() const; | ||||
|  | ||||
|             void sendMessage(const std::string& text); | ||||
|             size_t getReceivedMessagesCount() const; | ||||
|  | ||||
|             std::string encodeMessage(const std::string& text); | ||||
|             std::pair<std::string, std::string> decodeMessage(const std::string& str); | ||||
|  | ||||
|         private: | ||||
|             std::string _url; | ||||
|             std::string _user; | ||||
|             ix::WebSocket _webSocket; | ||||
|             std::queue<std::string> _receivedQueue; | ||||
|  | ||||
|             void log(const std::string& msg); | ||||
|     }; | ||||
|  | ||||
|     WebSocketChat::WebSocketChat(const std::string& url, | ||||
|                                  const std::string& user) : | ||||
|         _url(url), | ||||
|         _user(user) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     void WebSocketChat::log(const std::string& msg) | ||||
|     { | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     size_t WebSocketChat::getReceivedMessagesCount() const | ||||
|     { | ||||
|         return _receivedQueue.size(); | ||||
|     } | ||||
|  | ||||
|     bool WebSocketChat::isReady() const | ||||
|     { | ||||
|         return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open; | ||||
|     } | ||||
|  | ||||
|     void WebSocketChat::stop() | ||||
|     { | ||||
|         _webSocket.stop(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketChat::start() | ||||
|     { | ||||
|         _webSocket.setUrl(_url); | ||||
|  | ||||
|         std::stringstream ss; | ||||
|         log(std::string("Connecting to url: ") + _url); | ||||
|  | ||||
|         _webSocket.setOnMessageCallback( | ||||
|             [this](ix::WebSocketMessageType messageType, | ||||
|                const std::string& str, | ||||
|                size_t wireSize, | ||||
|                const ix::WebSocketErrorInfo& error, | ||||
|                const ix::WebSocketOpenInfo& openInfo, | ||||
|                const ix::WebSocketCloseInfo& closeInfo) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 if (messageType == ix::WebSocket_MessageType_Open) | ||||
|                 { | ||||
|                     ss << "cmd_websocket_chat: user " | ||||
|                        << _user | ||||
|                        << " Connected !"; | ||||
|                        log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Close) | ||||
|                 { | ||||
|                     ss << "cmd_websocket_chat: user " | ||||
|                        << _user | ||||
|                        << " disconnected !"; | ||||
|                        log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Message) | ||||
|                 { | ||||
|                     auto result = decodeMessage(str); | ||||
|  | ||||
|                     // Our "chat" / "broacast" node.js server does not send us | ||||
|                     // the messages we send, so we don't have to filter it out. | ||||
|  | ||||
|                     // store text | ||||
|                     _receivedQueue.push(result.second); | ||||
|  | ||||
|                     ss << std::endl | ||||
|                        << result.first << " > " << result.second | ||||
|                        << std::endl | ||||
|                        << _user << " > "; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Error) | ||||
|                 { | ||||
|                     ss << "Connection error: " << error.reason      << std::endl; | ||||
|                     ss << "#retries: "         << error.retries     << std::endl; | ||||
|                     ss << "Wait time(ms): "    << error.wait_time   << std::endl; | ||||
|                     ss << "HTTP Status: "      << error.http_status << std::endl; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ss << "Invalid ix::WebSocketMessageType"; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         _webSocket.start(); | ||||
|     } | ||||
|  | ||||
|     std::pair<std::string, std::string> WebSocketChat::decodeMessage(const std::string& str) | ||||
|     { | ||||
|         auto j = json::parse(str); | ||||
|  | ||||
|         std::string msg_user = j["user"]; | ||||
|         std::string msg_text = j["text"]; | ||||
|  | ||||
|         return std::pair<std::string, std::string>(msg_user, msg_text); | ||||
|     } | ||||
|  | ||||
|     std::string WebSocketChat::encodeMessage(const std::string& text) | ||||
|     { | ||||
|         json j; | ||||
|         j["user"] = _user; | ||||
|         j["text"] = text; | ||||
|  | ||||
|         std::string output = j.dump(); | ||||
|         return output; | ||||
|     } | ||||
|  | ||||
|     void WebSocketChat::sendMessage(const std::string& text) | ||||
|     { | ||||
|         _webSocket.send(encodeMessage(text)); | ||||
|     } | ||||
|  | ||||
|     void interactiveMain(const std::string& url, | ||||
|                          const std::string& user) | ||||
|     { | ||||
|         std::cout << "Type Ctrl-D to exit prompt..." << std::endl; | ||||
|         WebSocketChat webSocketChat(url, user); | ||||
|         webSocketChat.start(); | ||||
|  | ||||
|         while (true) | ||||
|         { | ||||
|             std::string text; | ||||
|             std::cout << user << " > " << std::flush; | ||||
|             std::getline(std::cin, text); | ||||
|  | ||||
|             if (!std::cin) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             webSocketChat.sendMessage(text); | ||||
|         } | ||||
|  | ||||
|         std::cout << std::endl; | ||||
|         webSocketChat.stop(); | ||||
|     } | ||||
|  | ||||
|     int ws_chat_main(const std::string& url, | ||||
|                      const std::string& user) | ||||
|     { | ||||
|         Socket::init(); | ||||
|         interactiveMain(url, user); | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										159
									
								
								ws/ws_connect.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								ws/ws_connect.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | ||||
| /* | ||||
|  *  ws_connect.cpp | ||||
|  *  Author: Benjamin Sergeant | ||||
|  *  Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <ixwebsocket/IXSocket.h> | ||||
|  | ||||
| namespace ix | ||||
| { | ||||
|     class WebSocketConnect | ||||
|     { | ||||
|         public: | ||||
|             WebSocketConnect(const std::string& _url); | ||||
|  | ||||
|             void subscribe(const std::string& channel); | ||||
|             void start(); | ||||
|             void stop(); | ||||
|  | ||||
|             void sendMessage(const std::string& text); | ||||
|  | ||||
|         private: | ||||
|             std::string _url; | ||||
|             ix::WebSocket _webSocket; | ||||
|  | ||||
|             void log(const std::string& msg); | ||||
|     }; | ||||
|  | ||||
|     WebSocketConnect::WebSocketConnect(const std::string& url) : | ||||
|         _url(url) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     void WebSocketConnect::log(const std::string& msg) | ||||
|     { | ||||
|         std::cout << msg << std::endl; | ||||
|     } | ||||
|  | ||||
|     void WebSocketConnect::stop() | ||||
|     { | ||||
|         _webSocket.stop(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketConnect::start() | ||||
|     { | ||||
|         _webSocket.setUrl(_url); | ||||
|  | ||||
|         ix::WebSocketPerMessageDeflateOptions webSocketPerMessageDeflateOptions( | ||||
|             true, false, false, 15, 15); | ||||
|         _webSocket.setPerMessageDeflateOptions(webSocketPerMessageDeflateOptions); | ||||
|  | ||||
|         std::stringstream ss; | ||||
|         log(std::string("Connecting to url: ") + _url); | ||||
|  | ||||
|         _webSocket.setOnMessageCallback( | ||||
|             [this](ix::WebSocketMessageType messageType, | ||||
|                const std::string& str, | ||||
|                size_t wireSize, | ||||
|                const ix::WebSocketErrorInfo& error, | ||||
|                const ix::WebSocketOpenInfo& openInfo, | ||||
|                const ix::WebSocketCloseInfo& closeInfo) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 if (messageType == ix::WebSocket_MessageType_Open) | ||||
|                 { | ||||
|                     log("ws_connect: connected"); | ||||
|                     std::cout << "Uri: " << openInfo.uri << std::endl; | ||||
|                     std::cout << "Handshake Headers:" << std::endl; | ||||
|                     for (auto it : openInfo.headers) | ||||
|                     { | ||||
|                         std::cout << it.first << ": " << it.second << std::endl; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Close) | ||||
|                 { | ||||
|                     ss << "ws_connect: connection closed:"; | ||||
|                     ss << " code " << closeInfo.code; | ||||
|                     ss << " reason " << closeInfo.reason << std::endl; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Message) | ||||
|                 { | ||||
|                     ss << "ws_connect: received message: " | ||||
|                        << str; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocket_MessageType_Error) | ||||
|                 { | ||||
|                     ss << "Connection error: " << error.reason      << std::endl; | ||||
|                     ss << "#retries: "         << error.retries     << std::endl; | ||||
|                     ss << "Wait time(ms): "    << error.wait_time   << std::endl; | ||||
|                     ss << "HTTP Status: "      << error.http_status << std::endl; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ss << "Invalid ix::WebSocketMessageType"; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         _webSocket.start(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketConnect::sendMessage(const std::string& text) | ||||
|     { | ||||
|         _webSocket.send(text); | ||||
|     } | ||||
|  | ||||
|     void interactiveMain(const std::string& url) | ||||
|     { | ||||
|         std::cout << "Type Ctrl-D to exit prompt..." << std::endl; | ||||
|         WebSocketConnect webSocketChat(url); | ||||
|         webSocketChat.start(); | ||||
|  | ||||
|         while (true) | ||||
|         { | ||||
|             std::string text; | ||||
|             std::cout << "> " << std::flush; | ||||
|             std::getline(std::cin, text); | ||||
|  | ||||
|             if (text == "/stop") | ||||
|             { | ||||
|                 std::cout << "Stopping connection..." << std::endl; | ||||
|                 webSocketChat.stop(); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (text == "/start") | ||||
|             { | ||||
|                 std::cout << "Starting connection..." << std::endl; | ||||
|                 webSocketChat.start(); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (!std::cin) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             webSocketChat.sendMessage(text); | ||||
|         } | ||||
|  | ||||
|         std::cout << std::endl; | ||||
|         webSocketChat.stop(); | ||||
|     } | ||||
|  | ||||
|     int ws_connect_main(const std::string& url) | ||||
|     { | ||||
|         Socket::init(); | ||||
|         interactiveMain(url); | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user