aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2018-12-01 19:03:33 +0100
committerFelix Morgner <felix.morgner@gmail.com>2018-12-01 19:03:33 +0100
commit2be129ac64d2540dc42f89bac85d24d4557aa59f (patch)
tree1df65973d162a1c36ab75c06b7101a81285160ea /src
parent927caf94ad0d7b98d4b2c3833da8f0f2707d4f87 (diff)
downloadwanda-2be129ac64d2540dc42f89bac85d24d4557aa59f.tar.xz
wanda-2be129ac64d2540dc42f89bac85d24d4557aa59f.zip
wandac: implement very basic command line interface
Diffstat (limited to 'src')
-rw-r--r--src/commander.cpp50
-rw-r--r--src/commander.hpp26
-rw-r--r--src/wandac.cpp79
3 files changed, 149 insertions, 6 deletions
diff --git a/src/commander.cpp b/src/commander.cpp
index 6cb1996..21bf4f5 100644
--- a/src/commander.cpp
+++ b/src/commander.cpp
@@ -1,14 +1,44 @@
#include "commander.hpp"
#include "message.hpp"
+#include "optional.hpp"
#include <spdlog/fmt/ostr.h>
namespace wanda
{
-commander::commander(asio::io_service &service, std::filesystem::path socket, std::shared_ptr<spdlog::logger> logger)
+
+std::optional<message> commander::command::message() const
+{
+ using namespace std::string_literals;
+ auto const command = [this] {
+ switch (id)
+ {
+ case command_id::change:
+ return "CHANGE"s;
+ default:
+ return ""s;
+ }
+ }();
+
+ auto argument_string = std::string{};
+ for(int index = 0ul; index < arguments.size(); ++index)
+ {
+ argument_string += (index) ? "," + arguments[index] : arguments[index];
+ }
+
+ if(command.empty())
+ {
+ return std::nullopt;
+ }
+
+ return wanda::message{"C", command, argument_string};
+}
+
+commander::commander(asio::io_service &service, std::filesystem::path socket, listener &listener, std::shared_ptr<spdlog::logger> logger)
: m_service{service},
m_endpoint{socket.string()},
m_socket{service},
+ m_listener{listener},
m_logger{logger}
{
}
@@ -31,6 +61,22 @@ void commander::start()
});
}
+void commander::send(command command)
+{
+ using namespace wanda::std_ext;
+
+ if (!m_connection || m_connection->current_state() != control_connection::state::established)
+ {
+ m_logger->error("tried to send command without an established connection");
+ m_listener.on_error(*this, "tried to send command without an established connection");
+ return;
+ }
+
+ with(command.message(), [&](auto const & message){
+ m_connection->send(message);
+ }) || [&]{ m_logger->error("unknown command"); };
+}
+
void commander::on_error(control_connection::pointer connection, std::error_code error)
{
m_logger->error("control interface communication error: '{}'", error.message());
@@ -42,10 +88,12 @@ void commander::on_received(wanda::control_connection::pointer connection, messa
{
m_logger->info("connection to wanda deamon successfully established");
connection->update(control_connection::state::established);
+ m_listener.on_connected(*this);
}
else
{
m_logger->error("unexpected message: '{}'", message);
+ m_listener.on_error(*this, "unexpected message '" + static_cast<std::string>(message) + '\'');
}
}
diff --git a/src/commander.hpp b/src/commander.hpp
index e7d68af..abc7643 100644
--- a/src/commander.hpp
+++ b/src/commander.hpp
@@ -9,16 +9,39 @@
#include <filesystem>
#include <memory>
+#include <optional>
#include <string>
+#include <vector>
namespace wanda
{
struct commander : wanda::control_connection::listener
{
- commander(asio::io_service &service, std::filesystem::path socket, std::shared_ptr<spdlog::logger> logger);
+ enum struct command_id : char
+ {
+ change,
+ };
+
+ struct command
+ {
+ command_id const id;
+ std::vector<std::string> const arguments;
+
+ std::optional<wanda::message> message() const;
+ };
+
+ struct listener
+ {
+ virtual void on_connected(commander & commander) { };
+ virtual void on_response(commander & commander, std::string response) { };
+ virtual void on_error(commander & commander, std::string error) { };
+ };
+
+ commander(asio::io_service &service, std::filesystem::path socket, listener & listener, std::shared_ptr<spdlog::logger> logger);
void start();
+ void send(command command);
void on_error(control_connection::pointer connection, std::error_code error) override;
void on_received(control_connection::pointer connection, message message) override;
@@ -28,6 +51,7 @@ private:
wanda::control_connection::protocol::endpoint m_endpoint;
wanda::control_connection::protocol::socket m_socket;
wanda::control_connection::pointer m_connection;
+ listener & m_listener;
std::shared_ptr<spdlog::logger> m_logger;
};
diff --git a/src/wandac.cpp b/src/wandac.cpp
index 24b529e..dee86f0 100644
--- a/src/wandac.cpp
+++ b/src/wandac.cpp
@@ -3,19 +3,90 @@
#include "xdg.hpp"
#include <asio.hpp>
+#include <clara.hpp>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
+#include <cstdlib>
#include <filesystem>
+#include <iostream>
#include <memory>
-int main()
+struct cli
{
- auto environment = wanda::environment{};
+ std::string command{};
+ bool help{};
+
+ clara::Parser parser;
+
+ auto parse(int argc, char const *const *argv, std::ostream &error)
+ {
+ parser = clara::Arg{command, "command"}("The command to send to the deamon").required() |
+ clara::Help(help);
+
+ auto result = parser.parse(clara::Args{argc, argv});
+
+ if (!result)
+ {
+ error << "Error while processing command line arguments: "
+ << result.errorMessage()
+ << '\n'
+ << parser
+ << '\n';
+ return false;
+ }
+ else if (command.empty())
+ {
+ error << "Missing required argument 'command'\n"
+ << parser
+ << '\n';
+ return false;
+ }
+
+ return true;
+ }
+};
+
+struct listener : wanda::commander::listener
+{
+ listener(::cli &cli, std::shared_ptr<spdlog::logger> logger)
+ : m_logger{logger},
+ m_cli{cli}
+ {
+ }
+
+ void on_connected(wanda::commander &commander) override
+ {
+ if (m_cli.command == "change")
+ {
+ commander.send({wanda::commander::command_id::change});
+ }
+ }
+
+ private:
+ std::shared_ptr<spdlog::logger> m_logger;
+ ::cli &m_cli;
+};
+
+int main(int argc, char const *const *argv)
+{
+ auto cli = ::cli{};
+ if (!cli.parse(argc, argv, std::cerr))
+ {
+ return EXIT_FAILURE;
+ }
+ else if (cli.help)
+ {
+ std::cout << cli.parser << '\n';
+ return EXIT_SUCCESS;
+ }
+
auto log = spdlog::stdout_color_mt("wandac");
- auto interface = wanda::xdg_path_for(wanda::xdg_directory::runtime_dir, environment) / ".wanda_interface";
+ auto interface = wanda::xdg_path_for(wanda::xdg_directory::runtime_dir, wanda::environment{}) / ".wanda_interface";
auto service = asio::io_service{};
- auto commander = wanda::commander{service, interface, log};
+ auto listener = ::listener{cli, log};
+
+ auto commander = wanda::commander{service, interface, listener, log};
log->info("trying to connect to wanda control interface on '{}'", interface.native());
commander.start();