summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorilotterytea <iltsu@alright.party>2025-07-03 18:06:10 +0500
committerilotterytea <iltsu@alright.party>2025-07-03 18:06:10 +0500
commitada1621a841de3e86fdd2d2ef930d595fea1f714 (patch)
treeec2ff3bfad3541005498f3673f84601e3417b48d
parente23ccfb00c8fa39926b32e94be6bc379e70ba11d (diff)
feat: interactive commands
-rw-r--r--bot/src/commands/lua.hpp22
-rw-r--r--bot/src/handlers.cpp148
2 files changed, 131 insertions, 39 deletions
diff --git a/bot/src/commands/lua.hpp b/bot/src/commands/lua.hpp
index 2516bab..05e9490 100644
--- a/bot/src/commands/lua.hpp
+++ b/bot/src/commands/lua.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
+#include <optional>
#include <sol/sol.hpp>
#include <sol/state.hpp>
#include <sol/table.hpp>
@@ -15,6 +16,7 @@
#include "config.hpp"
#include "cpr/api.h"
#include "schemas/user.hpp"
+#include "utils/string.hpp"
void print_lua_object_type(const sol::object &obj);
@@ -112,7 +114,22 @@ namespace bot::command::lua {
request, bundle.localization, command::CommandArgument::VALUE);
}
- std::string url = request.message.value();
+ std::vector<std::string> parts =
+ utils::string::split_text(request.message.value(), ' ');
+
+ std::string url = parts[0];
+
+ parts.erase(parts.begin());
+
+ std::string m = utils::string::join_vector(parts, ' ');
+
+ command::Request r = request;
+
+ if (m.empty()) {
+ r.message = std::nullopt;
+ } else {
+ r.message = m;
+ }
std::vector<std::string> mimeTypes = {"text/plain", "text/x-lua",
"text/plain; charset=utf-8",
@@ -139,8 +156,7 @@ namespace bot::command::lua {
std::string script = response.text;
- return command::lua::run_safe_lua_script(request, bundle, script,
- url);
+ return command::lua::run_safe_lua_script(r, bundle, script, url);
}
};
}
diff --git a/bot/src/handlers.cpp b/bot/src/handlers.cpp
index c7bdc36..46ae51d 100644
--- a/bot/src/handlers.cpp
+++ b/bot/src/handlers.cpp
@@ -5,12 +5,14 @@
#include <memory>
#include <optional>
#include <random>
+#include <regex>
#include <string>
#include <vector>
#include "bundle.hpp"
#include "commands/command.hpp"
#include "commands/request.hpp"
+#include "commands/response.hpp"
#include "commands/response_error.hpp"
#include "constants.hpp"
#include "cpr/api.h"
@@ -25,62 +27,136 @@
#include "utils/string.hpp"
namespace bot::handlers {
- void handle_private_message(
+ std::optional<command::Response> run_command(
const InstanceBundle &bundle, command::CommandLoader &command_loader,
- const irc::Message<irc::MessageType::Privmsg> &message) {
- std::unique_ptr<db::BaseDatabase> conn =
- db::create_connection(bundle.configuration);
-
+ const irc::Message<irc::MessageType::Privmsg> &message,
+ const command::Requester &requester,
+ std::unique_ptr<db::BaseDatabase> &conn) {
std::optional<command::Request> request =
- command::generate_request(command_loader, message, conn);
+ command::generate_request(command_loader, message, requester, conn);
if (request.has_value()) {
try {
auto response = command_loader.run(bundle, request.value());
- if (response.has_value()) {
- if (response->is_single()) {
- bundle.irc_client.say(message.source.login, response->get_single());
- } else if (response->is_multiple()) {
- for (const std::string &msg : response->get_multiple()) {
- bundle.irc_client.say(message.source.login, msg);
- }
- }
-
- return;
- }
+ return response;
} catch (const std::exception &e) {
bundle.irc_client.say(message.source.login, e.what());
log::error("PrivMsg/" + request->command_id, e.what());
}
}
- db::DatabaseRows channels =
- conn->exec("SELECT * FROM channels WHERE alias_id = $1",
- {std::to_string(message.source.id)});
+ return std::nullopt;
+ }
+
+ std::optional<std::string> handle_custom_commands(
+ const InstanceBundle &bundle, command::CommandLoader &command_loader,
+ std::unique_ptr<db::BaseDatabase> &conn,
+ const command::Requester &requester,
+ const irc::Message<irc::MessageType::Privmsg> &message) {
+ std::vector<std::string> parts =
+ utils::string::split_text(message.message, ' ');
+
+ if (parts.empty()) {
+ return std::nullopt;
+ }
+
+ std::string cid = parts[0];
+
+ db::DatabaseRows cmds = conn->exec(
+ "SELECT message FROM custom_commands WHERE name = $1 AND (channel_id "
+ "= $2 OR is_global = TRUE)",
+ {cid, std::to_string(requester.channel.get_id())});
+
+ if (cmds.empty()) {
+ return std::nullopt;
+ }
+
+ parts.erase(parts.begin());
+
+ std::string initial_message = utils::string::join_vector(parts, ' ');
+
+ db::DatabaseRow cmd = cmds[0];
+ std::string msg = cmd.at("message");
+
+ // parsing values
+ std::regex pattern(R"(\{([^}]*)\})");
+ std::string output;
+ std::sregex_iterator iter(msg.begin(), msg.end(), pattern);
+ std::sregex_iterator end;
+
+ int last_pos = 0;
+ for (; iter != end; ++iter) {
+ auto m = *iter;
+ output += msg.substr(last_pos, m.position() - last_pos);
+
+ std::string inside = m[1].str();
+
+ int placeholder_pos = inside.find("$1");
+ if (placeholder_pos != std::string::npos) {
+ inside.replace(placeholder_pos, 3, initial_message);
+ }
+
+ irc::Message<irc::MessageType::Privmsg> msg2 = message;
+ msg2.message = inside;
+
+ std::optional<command::Response> response =
+ run_command(bundle, command_loader, msg2, requester, conn);
+
+ std::string answer = inside;
+
+ if (response.has_value()) {
+ if (response->is_single()) {
+ answer = response->get_single();
+ } else if (response->is_multiple()) {
+ answer = "[multiple strings]";
+ }
+ }
+
+ output += answer;
+
+ last_pos = m.position() + m.length();
+ }
+
+ output += msg.substr(last_pos);
- if (!channels.empty()) {
- schemas::Channel channel(channels[0]);
+ return output;
+ }
- db::DatabaseRows channel_preferences = conn->exec(
- "SELECT * FROM channel_preferences WHERE "
- "id = $1",
- {std::to_string(channel.get_id())});
+ void handle_private_message(
+ const InstanceBundle &bundle, command::CommandLoader &command_loader,
+ const irc::Message<irc::MessageType::Privmsg> &message) {
+ std::unique_ptr<db::BaseDatabase> conn =
+ db::create_connection(bundle.configuration);
- schemas::ChannelPreferences preference(channel_preferences[0]);
+ std::optional<command::Requester> requester =
+ command::get_requester(message, conn);
- db::DatabaseRows cmds = conn->exec(
- "SELECT message FROM custom_commands WHERE name = $1 AND channel_id "
- "= $2",
- {message.message, std::to_string(channel.get_id())});
+ if (!requester.has_value()) {
+ return;
+ }
- if (!cmds.empty()) {
- std::string msg = cmds[0].at("message");
+ std::optional<command::Response> response =
+ run_command(bundle, command_loader, message, *requester, conn);
- bundle.irc_client.say(message.source.login, msg);
- } else {
- make_markov_response(bundle, message, channel, preference);
+ if (response.has_value()) {
+ if (response->is_single()) {
+ bundle.irc_client.say(message.source.login, response->get_single());
+ } else if (response->is_multiple()) {
+ for (const std::string &msg : response->get_multiple()) {
+ bundle.irc_client.say(message.source.login, msg);
+ }
}
+
+ return;
+ }
+
+ std::optional<std::string> custom_command_response = handle_custom_commands(
+ bundle, command_loader, conn, *requester, message);
+
+ if (custom_command_response.has_value()) {
+ bundle.irc_client.say(message.source.login, *custom_command_response);
+ return;
}
conn->close();