From d44574c284d6dfe316019c95c6baf2fc39b23abd Mon Sep 17 00:00:00 2001 From: Green Sky Date: Sun, 3 Dec 2023 16:01:33 +0100 Subject: [PATCH] lower cmake version, static flake build and mcd getting along --- flake.nix | 70 +++++++----- src/CMakeLists.txt | 3 + src/main.cpp | 14 +++ src/message_command_dispatcher.cpp | 178 ++++++++++++++++++++++++++++- src/message_command_dispatcher.hpp | 23 +++- 5 files changed, 255 insertions(+), 33 deletions(-) diff --git a/flake.nix b/flake.nix index fc56154..a4e3c9c 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,8 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; + + # get deps toxcore-src = pkgs.fetchFromGitHub { owner = "Green-Sky"; repo = "c-toxcore"; fetchSubmodules = true; @@ -53,44 +55,52 @@ rev = "89e74b35f83d888f8aa2e5230811b8a5e2b101a7"; hash = "sha256-PQw2290ahYfU13tHGzBttwrvZBXK+wKh6UF4xfUaRWQ="; }; + + pname = "totato"; + version = "0.0.0-dev"; + + src = ./.; + + nativeBuildInputs = with pkgs; [ + cmake + ninja + pkg-config + git # cmake FetchContent + ]; + + cmakeFlags = [ + #"-DFETCHCONTENT_SOURCE_DIR_TOXCORE=${pkgs.libtoxcore.src}" + "-DFETCHCONTENT_SOURCE_DIR_TOXCORE=${toxcore-src}" + "-DFETCHCONTENT_SOURCE_DIR_ENTT=${entt-src}" # the version is important + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_UTIL=${solanaceae_util-src}" + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_CONTACT=${solanaceae_contact-src}" + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_MESSAGE3=${solanaceae_message3-src}" + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_PLUGIN=${solanaceae_plugin-src}" + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_TOXCORE=${solanaceae_toxcore-src}" + "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_TOX=${solanaceae_tox-src}" + "-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}" # we care less about version here + ]; + + # TODO: replace with install command + installPhase = '' + mkdir -p $out/bin + mv bin/totato $out/bin + ''; in { packages.default = pkgs.stdenv.mkDerivation { - pname = "totato"; - version = "0.0.0-dev"; - - src = ./.; - - nativeBuildInputs = with pkgs; [ - cmake - ninja - pkg-config - git # cmake FetchContent - ]; - - cmakeFlags = [ - #"-DFETCHCONTENT_SOURCE_DIR_TOXCORE=${pkgs.libtoxcore.src}" - "-DFETCHCONTENT_SOURCE_DIR_TOXCORE=${toxcore-src}" - "-DFETCHCONTENT_SOURCE_DIR_ENTT=${entt-src}" # the version is important - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_UTIL=${solanaceae_util-src}" - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_CONTACT=${solanaceae_contact-src}" - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_MESSAGE3=${solanaceae_message3-src}" - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_PLUGIN=${solanaceae_plugin-src}" - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_TOXCORE=${solanaceae_toxcore-src}" - "-DFETCHCONTENT_SOURCE_DIR_SOLANACEAE_TOX=${solanaceae_tox-src}" - "-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}" # we care less about version here - ]; - + inherit pname version src nativeBuildInputs cmakeFlags installPhase; buildInputs = with pkgs; [ #(libsodium.override { stdenv = pkgs.pkgsStatic.stdenv; }) #pkgsStatic.libsodium libsodium ]; + }; - # TODO: replace with install command - installPhase = '' - mkdir -p $out/bin - mv bin/totato $out/bin - ''; + packages.static = pkgs.pkgsStatic.stdenv.mkDerivation { + inherit pname version src nativeBuildInputs cmakeFlags installPhase; + buildInputs = with pkgs.pkgsStatic; [ + libsodium + ]; }; #apps.default = { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d030c79..22ddd25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,9 @@ add_executable(totato ./message_cleanser.hpp ./message_cleanser.cpp + + ./message_command_dispatcher.hpp + ./message_command_dispatcher.cpp ) target_compile_features(totato PUBLIC cxx_std_17) diff --git a/src/main.cpp b/src/main.cpp index f6a7f45..da80650 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "./tox_client.hpp" #include "./auto_dirty.hpp" #include "./message_cleanser.hpp" +#include "./message_command_dispatcher.hpp" #include @@ -158,6 +159,19 @@ int main(int argc, char** argv) { RegistryMessageModel rmm{cr}; MessageTimeSort mts{rmm}; MessageCleanser mc{cr, rmm}; + MessageCommandDispatcher mcd{cr, rmm, conf}; + + { // setup basic commands for bot + mcd.registerCommand( + "host", "", + "info", + [](std::string_view) -> bool { + std::cout << "INFO got called :)\n"; + return true; + }, + "Get basic information about this bot" + ); + } PluginManager pm; diff --git a/src/message_command_dispatcher.cpp b/src/message_command_dispatcher.cpp index 4091e7d..89d4205 100644 --- a/src/message_command_dispatcher.cpp +++ b/src/message_command_dispatcher.cpp @@ -1,6 +1,20 @@ #include "./message_command_dispatcher.hpp" #include +#include + +#include +#include + +//MessageCommandDispatcher::Command::Command(Command&& other) : + //m(std::move(other.m)), + //m_prefix(std::move(other.m_prefix)), + //command(std::move(other.command)), + //fn(std::move(other.fn)), + //help_text(std::move(other.help_text)) +//{ + //// is this really needed? +//} MessageCommandDispatcher::MessageCommandDispatcher( Contact3Registry& cr, @@ -9,6 +23,18 @@ MessageCommandDispatcher::MessageCommandDispatcher( ) : _cr(cr), _rmm(rmm), _conf(conf) { + _rmm.subscribe(this, RegistryMessageModel_Event::message_construct); + + { // setup basic commands for bot + registerCommand( + "host", "", + "help", + [this](std::string_view params) -> bool { + return helpCommand(params); + }, + "Get help" + ); + } } MessageCommandDispatcher::~MessageCommandDispatcher(void) { @@ -17,11 +43,161 @@ MessageCommandDispatcher::~MessageCommandDispatcher(void) { void MessageCommandDispatcher::iterate(float time_delta) { } +static std::string_view get_first_word(std::string_view text) { + if (text.empty()) { + return text; + } + + // trim + const auto pos_first_non_space = text.find_first_not_of(' '); + if (pos_first_non_space == std::string_view::npos) { + // only contains spaces o.o + return ""; // should return text as is? + } + + text = text.substr(pos_first_non_space); + + const auto pos_first_space = text.find_first_of(' '); + if (pos_first_space == 0 || pos_first_space == std::string_view::npos) { + // does not contain spaces + // command is whole message + return text; + } else { + return text.substr(0, pos_first_space); + } +} + +void MessageCommandDispatcher::registerCommand( + std::string_view m, // module + std::string_view m_prefix, // module prefix (if any) + std::string_view command, // command + std::function&& fn, + std::string_view help_text +) { + std::string full_command_string = std::string{m_prefix} + std::string{command}; + + if (_command_map.count(full_command_string)) { + std::cout << "MCD warning: overwriting existing '" << full_command_string << "'\n"; + } + + _command_map[full_command_string] = Command{ + std::string{m}, + std::string{m_prefix}, + std::string{command}, + std::move(fn), + std::string{help_text} + }; +} + +bool MessageCommandDispatcher::helpCommand(std::string_view params) { + std::cout << "MCD: help got called '" << params << "'\n"; + return true; +} + bool MessageCommandDispatcher::onEvent(const Message::Events::MessageConstruct& e) { + if (!e.e.all_of()) { + std::cout << "MCD: got message that is not"; + + if (!e.e.all_of()) { + std::cout << " text"; + } + if (!e.e.all_of()) { + std::cout << " unread"; + } + + std::cout << "\n"; + return false; + } + + if (e.e.any_of()) { + std::cout << "MCD: got message that is"; + if (e.e.all_of()) { + std::cout << " action"; + } + std::cout << "\n"; + return false; + } + + std::string_view message_text = e.e.get().text; + + if (message_text.empty()) { + // empty message? + return false; + } + + // TODO: skip unrelyable synced + + // TODO: is private + + // TODO: has the permissions + + + if (false) { // is private + } else { + // check for command prefix + if ( + message_text.at(0) != '!' && + message_text.at(0) != '/' + ) { + // does not start with command prefix, not for us + return false; + } + + // remove c prefix + message_text = message_text.substr(1); + } + + if (message_text.empty()) { + // empty message? + std::cout << "MCD: got empty command\n"; + return false; + } + + std::cout << "MCD: got command '" << message_text << "'\n"; + + + std::string_view first_word; + std::string_view second_word; + + first_word = get_first_word(message_text); + std::cout << "------- first_word:'" << first_word << "'\n"; + if (first_word.size() != message_text.size()) { + second_word = get_first_word( + message_text.substr( + // TODO: optimize this + message_text.find(first_word) + + first_word.size() + ) + ); + } + + std::cout << "------- second_word:'" << second_word << "' empty:" << second_word.empty() << "\n"; + + // first search first + space + second word + if (!second_word.empty()) { + std::string query {first_word}; + query += " "; + query += second_word; + + const auto command_it = _command_map.find(query); + if (command_it != _command_map.cend()) { + command_it->second.fn(message_text); + return true; + } + } + + // then seach first word only + const auto command_it = _command_map.find(std::string{first_word}); + if (command_it != _command_map.cend()) { + command_it->second.fn(message_text); + return true; + } + return false; } -bool MessageCommandDispatcher::onEvent(const Message::Events::MessageUpdated& e) { +bool MessageCommandDispatcher::onEvent(const Message::Events::MessageUpdated&) { + // do i need this? return false; } diff --git a/src/message_command_dispatcher.hpp b/src/message_command_dispatcher.hpp index 277c767..d38da01 100644 --- a/src/message_command_dispatcher.hpp +++ b/src/message_command_dispatcher.hpp @@ -10,6 +10,17 @@ class MessageCommandDispatcher : public RegistryMessageModelEventI { RegistryMessageModel& _rmm; ConfigModelI& _conf; + struct Command { + std::string m; // module + std::string m_prefix; // module prefix (if any) + std::string command; // command + std::function fn; + std::string help_text; + + //Command(const Command&) = delete; + }; + std::unordered_map _command_map; + public: MessageCommandDispatcher(Contact3Registry& cr, RegistryMessageModel& rmm, ConfigModelI& conf); ~MessageCommandDispatcher(void); @@ -23,11 +34,19 @@ class MessageCommandDispatcher : public RegistryMessageModelEventI { // - everyone else? // callable // help text? + + void registerCommand( - std::string_view module, - std::string_view command + std::string_view m, // module + std::string_view m_prefix, // module prefix (if any) + std::string_view command, // command + std::function&& fn, + std::string_view help_text ); + // generates a help + bool helpCommand(std::string_view params); + protected: // mm bool onEvent(const Message::Events::MessageConstruct& e) override; bool onEvent(const Message::Events::MessageUpdated& e) override;