diff options
Diffstat (limited to 'source/lib/control/include')
3 files changed, 276 insertions, 0 deletions
diff --git a/source/lib/control/include/wanda/control/commander.hpp b/source/lib/control/include/wanda/control/commander.hpp new file mode 100644 index 0000000..c993fc0 --- /dev/null +++ b/source/lib/control/include/wanda/control/commander.hpp @@ -0,0 +1,66 @@ +#ifndef WANDA_CONTROL_COMMANDER_HPP +#define WANDA_CONTROL_COMMANDER_HPP + +#include "wanda/control/connection.hpp" +#include "wanda/proto/command.hpp" +#include "wanda/proto/message.hpp" + +#include <asio.hpp> + +#include <filesystem> +#include <memory> +#include <optional> +#include <string> +#include <vector> + +namespace wanda::control +{ + /** + * @brief The remote control client + * + */ + struct commander : connection::listener + { + /** + * @brief The interface to be implemented by remote control listeners + */ + 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){}; + }; + + /** + * @brief Construct a new commander + */ + commander(asio::io_service & service, std::filesystem::path socket, listener & listener); + + /** + * @brief Start communication with the remote daemon endpoint + */ + void start(); + + /** + * @brief Stop communication with the remote daemon endpoint + */ + void stop(); + + /** + * @brief Send a command to the remote daemon endpoint + */ + void send(proto::command command); + + void on_error(connection::pointer connection, std::error_code error) override; + void on_received(connection::pointer connection, proto::message message) override; + + private: + asio::io_service & m_service; + wanda::control::connection::protocol::endpoint m_endpoint; + wanda::control::connection::protocol::socket m_socket; + wanda::control::connection::pointer m_connection; + listener & m_listener; + }; + +} // namespace wanda::control +#endif
\ No newline at end of file diff --git a/source/lib/control/include/wanda/control/connection.hpp b/source/lib/control/include/wanda/control/connection.hpp new file mode 100644 index 0000000..1ca451d --- /dev/null +++ b/source/lib/control/include/wanda/control/connection.hpp @@ -0,0 +1,114 @@ +#ifndef WANDA_CONTROL_CONNECTION_HPP +#define WANDA_CONTROL_CONNECTION_HPP + +#include "wanda/meta/keyed.hpp" +#include "wanda/proto/message.hpp" + +#include <asio.hpp> + +#include <istream> +#include <memory> +#include <ostream> +#include <set> +#include <string> +#include <system_error> + +namespace wanda::control +{ + /** + * @brief A connection to a remote control endpoint + */ + struct connection : meta::keyed<connection>, std::enable_shared_from_this<connection> + { + using protocol = asio::local::stream_protocol; + using pointer = std::shared_ptr<connection>; + + /** + * @brief The interface to be implemented by the control interface listener + */ + struct listener + { + virtual void on_close(pointer connection) {} + virtual void on_received(pointer connection, proto::message message) {} + virtual void on_error(pointer connection, std::error_code) {} + }; + + /** + * @brief A enum to describe different connection states + */ + enum struct state : std::underlying_type_t<std::byte> + { + unknown, //< Connection is in an unknown state + fresh, //< Connection is freshly created but not established + established, //< Connection has been established + }; + + /** + * @internal + * @brief Construct a new control connection object + * + * @note This constructor is keyed on a private key type so it can only be constructed using the #wanda::make_connection factory + */ + connection(key, protocol::socket socket); + + /** + * @brief Add the given listener to this control connection's listener set + * + * @returns <code>true</code> iff. the listener was not already in the listener set + */ + bool add(listener * listener); + + /** + * @brief Remove the given listener from this control connection's listener set + * + * @return <code>true</code> iff. the listener was previously registered with this control connection + */ + bool remove(listener * listener); + + /** + * @brief Start I/O processing for this control connection + */ + void start(); + + /** + * @brief Close this control connection + */ + void close(); + + /** + * @brief Send the given message to the remote endpoint + */ + void send(proto::message message); + + /** + * @brief Set the connection state to the provided state + */ + void update(state state); + + /** + * @brief Get the current connection state + */ + state current_state() const; + + private: + friend pointer make_connection(protocol::socket && socket); + + void perform_read(); + + protocol::socket m_socket; + asio::streambuf m_in{}; + asio::streambuf m_out{}; + std::istream m_input{&m_in}; + std::ostream m_output{&m_out}; + std::set<listener *> m_listeners{}; + state m_state{}; + }; + + /** + * @brief Create a new control connection + */ + connection::pointer make_connection(connection::protocol::socket && socket); + +} // namespace wanda::control + +#endif
\ No newline at end of file diff --git a/source/lib/control/include/wanda/control/interface.hpp b/source/lib/control/include/wanda/control/interface.hpp new file mode 100644 index 0000000..3dca85f --- /dev/null +++ b/source/lib/control/include/wanda/control/interface.hpp @@ -0,0 +1,96 @@ +/** + * @file interface.hpp + * @author Felix Morgner (felix.morgner@gmail.com) + * @since 1.0.0 + */ + +#ifndef WANDA_CONTROL_INTERFACE_HPP +#define WANDA_CONTROL_INTERFACE_HPP + +#include "wanda/control/connection.hpp" +#include "wanda/meta/keyed.hpp" +#include "wanda/proto/command.hpp" + +#include <asio.hpp> +#include <spdlog/spdlog.h> + +#include <cstddef> +#include <filesystem> +#include <istream> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <type_traits> + +namespace wanda::control +{ + /** + * @brief An RAII type to delete a socket file upon destruction + */ + struct socket_deleter + { + ~socket_deleter(); + + std::filesystem::path path; + }; + + /** + * @brief The daemon control interface + */ + struct interface : connection::listener, meta::keyed<interface>, std::enable_shared_from_this<interface> + { + using protocol = asio::local::stream_protocol; + using pointer = std::shared_ptr<interface>; + + /** + * @brief The interface to be implemented by the control interface listener + */ + struct listener + { + virtual void on_received(interface & interface, proto::command command){}; + }; + + /** + * @internal + * @brief Construct a new control interface object + * + * @note This constructor is keyed on a private key type so it can only be constructed using the #wanda::make_interface factory + */ + interface(key, asio::io_service & service, protocol::endpoint endpoint, listener & listener); + + /** + * @brief Start handling of controller connections + */ + std::error_code start(); + + /** + * @brief Stop the control interface + */ + std::error_code shutdown(); + + void on_close(connection::pointer connection) override; + void on_received(connection::pointer connection, proto::message message) override; + + private: + void perform_accept(); + + friend pointer make_interface(asio::io_service & service, std::filesystem::path file, interface::listener & listener); + + asio::io_service & m_service; + protocol::endpoint m_endpoint; + protocol::socket m_socket; + protocol::acceptor m_acceptor; + listener & m_listener; + socket_deleter m_deleter{m_endpoint.path()}; + std::set<connection::pointer> m_connections; + }; + + /** + * @brief A factory to create new #interface instances + */ + interface::pointer make_interface(asio::io_service & service, std::filesystem::path socket, interface::listener & listener); + +} // namespace wanda::control + +#endif
\ No newline at end of file |
