(ws) add bare bone redis-cli like sub-command, with command line editing powered by libnoise
This commit is contained in:
parent
35d76c20dc
commit
ac9710d5d6
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user