(ws) add bare bone redis-cli like sub-command, with command line editing powered by libnoise
This commit is contained in:
		@@ -1,6 +1,10 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
All changes to this project will be documented in this file.
 | 
					All changes to this project will be documented in this file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [9.7.2] - 2020-06-11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(ws) add bare bone redis-cli like sub-command, with command line editing powered by libnoise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [9.7.1] - 2020-06-11
 | 
					## [9.7.1] - 2020-06-11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(redis cobra bots) ws cobra metrics to redis / hostname invalid parsing
 | 
					(redis cobra bots) ws cobra metrics to redis / hostname invalid parsing
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -354,4 +354,104 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return success;
 | 
					        return success;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::pair<RespType, std::string> RedisClient::send(
 | 
				
			||||||
 | 
					        const std::vector<std::string>& args,
 | 
				
			||||||
 | 
					        std::string& errMsg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        std::stringstream ss;
 | 
				
			||||||
 | 
					        ss << "*";
 | 
				
			||||||
 | 
					        ss << std::to_string(args.size());
 | 
				
			||||||
 | 
					        ss << "\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (auto&& arg : args)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ss << writeString(arg);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool sent = _socket->writeBytes(ss.str(), nullptr);
 | 
				
			||||||
 | 
					        if (!sent)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errMsg = "Cannot write bytes to socket";
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Error, "");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return readResponse(errMsg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::pair<RespType, std::string> RedisClient::readResponse(std::string& errMsg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Read result
 | 
				
			||||||
 | 
					        auto pollResult = _socket->isReadyToRead(-1);
 | 
				
			||||||
 | 
					        if (pollResult == PollResultType::Error)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errMsg = "Error while polling for result";
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Error, "");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // First line is the string length
 | 
				
			||||||
 | 
					        auto lineResult = _socket->readLine(nullptr);
 | 
				
			||||||
 | 
					        auto lineValid = lineResult.first;
 | 
				
			||||||
 | 
					        auto line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!lineValid)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errMsg = "Error while polling for result";
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Error, "");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (line[0] == '+') // Simple string
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::stringstream ss;
 | 
				
			||||||
 | 
					            response = line.substr(1, line.size() - 3);
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::String, response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (line[0] == '-') // Errors
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::stringstream ss;
 | 
				
			||||||
 | 
					            response = line.substr(1, line.size() - 3);
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Error, response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (line[0] == ':') // Integers
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            std::stringstream ss;
 | 
				
			||||||
 | 
					            response = line.substr(1, line.size() - 3);
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Integer, response);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (line[0] == '$') // Bulk strings
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int stringSize;
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                std::stringstream ss;
 | 
				
			||||||
 | 
					                ss << line.substr(1, line.size() - 1);
 | 
				
			||||||
 | 
					                ss >> stringSize;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Read the result, which is the stream id computed by the redis server
 | 
				
			||||||
 | 
					            lineResult = _socket->readLine(nullptr);
 | 
				
			||||||
 | 
					            lineValid = lineResult.first;
 | 
				
			||||||
 | 
					            line = lineResult.second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string str = line.substr(0, stringSize);
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::String, str);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            errMsg = "Unhandled response type";
 | 
				
			||||||
 | 
					            return std::make_pair(RespType::Unknown, std::string());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string RedisClient::getRespTypeDescription(RespType respType)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (respType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case RespType::Integer: return "integer";
 | 
				
			||||||
 | 
					            case RespType::Error: return "error";
 | 
				
			||||||
 | 
					            case RespType::String: return "string";
 | 
				
			||||||
 | 
					            default: return "unknown";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
} // namespace ix
 | 
					} // namespace ix
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    enum class RespType : int
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        String = 0,
 | 
				
			||||||
 | 
					        Error = 1,
 | 
				
			||||||
 | 
					        Integer = 2,
 | 
				
			||||||
 | 
					        Unknown = 3
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class RedisClient
 | 
					    class RedisClient
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
    public:
 | 
					    public:
 | 
				
			||||||
@@ -42,14 +50,20 @@ namespace ix
 | 
				
			|||||||
                         const std::string& message,
 | 
					                         const std::string& message,
 | 
				
			||||||
                         int maxLen,
 | 
					                         int maxLen,
 | 
				
			||||||
                         std::string& errMsg);
 | 
					                         std::string& errMsg);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string prepareXaddCommand(const std::string& stream,
 | 
					        std::string prepareXaddCommand(const std::string& stream,
 | 
				
			||||||
                                       const std::string& message,
 | 
					                                       const std::string& message,
 | 
				
			||||||
                                       int maxLen);
 | 
					                                       int maxLen);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string readXaddReply(std::string& errMsg);
 | 
					        std::string readXaddReply(std::string& errMsg);
 | 
				
			||||||
 | 
					        bool sendCommand(
 | 
				
			||||||
 | 
					            const std::string& commands, int commandsCount, std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        bool sendCommand(const std::string& commands, int commandsCount, std::string& errMsg);
 | 
					        // Arbitrary commands
 | 
				
			||||||
 | 
					        std::pair<RespType, std::string> send(
 | 
				
			||||||
 | 
					            const std::vector<std::string>& args,
 | 
				
			||||||
 | 
					            std::string& errMsg);
 | 
				
			||||||
 | 
					        std::pair<RespType, std::string> readResponse(std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        std::string getRespTypeDescription(RespType respType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void stop();
 | 
					        void stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IX_WEBSOCKET_VERSION "9.7.1"
 | 
					#define IX_WEBSOCKET_VERSION "9.7.2"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								makefile
									
									
									
									
									
								
							@@ -233,6 +233,9 @@ install_cmake_for_linux:
 | 
				
			|||||||
doc:
 | 
					doc:
 | 
				
			||||||
	mkdocs gh-deploy
 | 
						mkdocs gh-deploy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					change:
 | 
				
			||||||
 | 
						vi ixwebsocket/IXWebSocketVersion.h docs/CHANGELOG.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: test
 | 
					.PHONY: test
 | 
				
			||||||
.PHONY: build
 | 
					.PHONY: build
 | 
				
			||||||
.PHONY: ws
 | 
					.PHONY: ws
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ add_executable(ws
 | 
				
			|||||||
  ws_transfer.cpp
 | 
					  ws_transfer.cpp
 | 
				
			||||||
  ws_send.cpp
 | 
					  ws_send.cpp
 | 
				
			||||||
  ws_receive.cpp
 | 
					  ws_receive.cpp
 | 
				
			||||||
 | 
					  ws_redis_cli.cpp
 | 
				
			||||||
  ws_redis_publish.cpp
 | 
					  ws_redis_publish.cpp
 | 
				
			||||||
  ws_redis_subscribe.cpp
 | 
					  ws_redis_subscribe.cpp
 | 
				
			||||||
  ws_redis_server.cpp
 | 
					  ws_redis_server.cpp
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								ws/ws.cpp
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								ws/ws.cpp
									
									
									
									
									
								
							@@ -281,6 +281,12 @@ int main(int argc, char** argv)
 | 
				
			|||||||
    httpClientApp->add_option("--transfer-timeout", transferTimeout, "Transfer timeout");
 | 
					    httpClientApp->add_option("--transfer-timeout", transferTimeout, "Transfer timeout");
 | 
				
			||||||
    addTLSOptions(httpClientApp);
 | 
					    addTLSOptions(httpClientApp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CLI::App* redisCliApp = app.add_subcommand("redis_cli", "Redis cli");
 | 
				
			||||||
 | 
					    redisCliApp->fallthrough();
 | 
				
			||||||
 | 
					    redisCliApp->add_option("--port", redisPort, "Port");
 | 
				
			||||||
 | 
					    redisCliApp->add_option("--host", hostname, "Hostname");
 | 
				
			||||||
 | 
					    redisCliApp->add_option("--password", password, "Password");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    CLI::App* redisPublishApp = app.add_subcommand("redis_publish", "Redis publisher");
 | 
					    CLI::App* redisPublishApp = app.add_subcommand("redis_publish", "Redis publisher");
 | 
				
			||||||
    redisPublishApp->fallthrough();
 | 
					    redisPublishApp->fallthrough();
 | 
				
			||||||
    redisPublishApp->add_option("--port", redisPort, "Port");
 | 
					    redisPublishApp->add_option("--port", redisPort, "Port");
 | 
				
			||||||
@@ -531,6 +537,10 @@ int main(int argc, char** argv)
 | 
				
			|||||||
                                      compress,
 | 
					                                      compress,
 | 
				
			||||||
                                      tlsOptions);
 | 
					                                      tlsOptions);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    else if (app.got_subcommand("redis_cli"))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ret = ix::ws_redis_cli_main(hostname, redisPort, password);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    else if (app.got_subcommand("redis_publish"))
 | 
					    else if (app.got_subcommand("redis_publish"))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ret = ix::ws_redis_publish_main(hostname, redisPort, password, channel, message, count);
 | 
					        ret = ix::ws_redis_publish_main(hostname, redisPort, password, channel, message, count);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								ws/ws.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								ws/ws.h
									
									
									
									
									
								
							@@ -64,6 +64,10 @@ namespace ix
 | 
				
			|||||||
                     bool disablePerMessageDeflate,
 | 
					                     bool disablePerMessageDeflate,
 | 
				
			||||||
                     const ix::SocketTLSOptions& tlsOptions);
 | 
					                     const ix::SocketTLSOptions& tlsOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int ws_redis_cli_main(const std::string& hostname,
 | 
				
			||||||
 | 
					                          int port,
 | 
				
			||||||
 | 
					                          const std::string& password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int ws_redis_publish_main(const std::string& hostname,
 | 
					    int ws_redis_publish_main(const std::string& hostname,
 | 
				
			||||||
                              int port,
 | 
					                              int port,
 | 
				
			||||||
                              const std::string& password,
 | 
					                              const std::string& password,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@
 | 
				
			|||||||
#include <spdlog/spdlog.h>
 | 
					#include <spdlog/spdlog.h>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					#include "linenoise.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -36,17 +37,50 @@ namespace ix
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        while (true)
 | 
					        while (true)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::string text;
 | 
					            // Read line
 | 
				
			||||||
            std::cout << "> " << std::flush;
 | 
					            std::string line;
 | 
				
			||||||
            std::getline(std::cin, text);
 | 
					            std::string prompt;
 | 
				
			||||||
 | 
					            prompt += hostname;
 | 
				
			||||||
 | 
					            prompt += ":";
 | 
				
			||||||
 | 
					            prompt += std::to_string(port);
 | 
				
			||||||
 | 
					            prompt += "> ";
 | 
				
			||||||
 | 
					            auto quit = linenoise::Readline(prompt.c_str(), line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					            if (quit)
 | 
				
			||||||
            if (!redisClient.send(args, errMsg))
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                spdlog::error("Error", channel, errMsg);
 | 
					                break;
 | 
				
			||||||
                return 1;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
 | 
					            std::stringstream ss(line);
 | 
				
			||||||
 | 
					            std::vector<std::string> args;
 | 
				
			||||||
 | 
					            std::string arg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            while (ss.good())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ss >> arg;
 | 
				
			||||||
 | 
					                args.push_back(arg);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            std::string errMsg;
 | 
				
			||||||
 | 
					            auto response = redisClient.send(args, errMsg);
 | 
				
			||||||
 | 
					            if (!errMsg.empty())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                spdlog::error("(error) {}", errMsg);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (response.first != RespType::String)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    std::cout << "("
 | 
				
			||||||
 | 
					                              << redisClient.getRespTypeDescription(response.first)
 | 
				
			||||||
 | 
					                              << ")"
 | 
				
			||||||
 | 
					                              << " ";
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                std::cout << response.second << std::endl;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            linenoise::AddHistory(line.c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user