diff --git a/CMakeLists.txt b/CMakeLists.txt index dbfd39f..16305a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,10 @@ include(GNUInstallDirs) # dtranslatebot Source files set(DTRANSLATEBOT_HEADERS src/database_core.h + src/database_file.h src/message_queue.h src/settings.h + src/settings_types.h src/slashcommands.h src/submit_queue.h src/translator_core.h @@ -33,6 +35,7 @@ set(DTRANSLATEBOT_HEADERS ) set(DTRANSLATEBOT_SOURCES src/database_core.cpp + src/database_file.cpp src/main.cpp src/message_queue.cpp src/settings.cpp @@ -55,7 +58,7 @@ find_package(Threads REQUIRED) # dtranslatebot Target + Installs add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES}) -target_link_libraries(dtranslatebot Threads::Threads ${DPP_LIBRARIES}) +target_link_libraries(dtranslatebot PRIVATE Threads::Threads ${DPP_LIBRARIES}) target_include_directories(dtranslatebot PRIVATE ${DPP_INCLUDE_DIR}) set_target_properties(dtranslatebot PROPERTIES CXX_STANDARD 17 diff --git a/src/database_core.h b/src/database_core.h index e47724e..4971b72 100644 --- a/src/database_core.h +++ b/src/database_core.h @@ -19,8 +19,7 @@ #ifndef DATABASE_CORE_H #define DATABASE_CORE_H -#include -#include "settings.h" +#include "settings_types.h" namespace bot { namespace database { diff --git a/src/database_file.cpp b/src/database_file.cpp new file mode 100644 index 0000000..54bbc40 --- /dev/null +++ b/src/database_file.cpp @@ -0,0 +1,118 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2024 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#ifdef __unix__ +#include +#include +#include +#endif +#include +#include "database_file.h" +using namespace bot::database; + +file::file(const std::filesystem::path &storage_path) : m_storagePath(storage_path) +{ + std::cout << "[Launch] Checking working directory..." << std::endl; + if (!std::filesystem::exists(storage_path)) { + std::cerr << "[Error] Storage directory " << storage_path << " can not be found" << std::endl; + throw std::runtime_error("Storage directory can not be found"); + } + +#ifdef __unix__ + struct flock lock; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + + const std::string lock_file = storage_path / ".lock"; + fd = open(lock_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) { + std::cerr << "[Error] Storage directory " << storage_path << " can not be locked" << std::endl; + throw std::system_error(errno, std::system_category()); + } + if (fcntl(fd, F_SETLK, &lock) == -1) { + std::cerr << "[Error] Storage directory " << storage_path << " can not be locked" << std::endl; + throw std::system_error(errno, std::system_category()); + } +#endif +} + +file::~file() +{ +#ifdef __unix__ + close(fd); +#endif +} + +bool file::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::add_channel_target(dpp::snowflake, dpp::snowflake, const bot::settings::target&) have being called." << std::endl; +#endif + return false; +} + +std::variant file::find_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::find_channel_target(dpp::snowflake, dpp::snowflake, const std::string&) have being called." << std::endl; +#endif + return {}; +} + +std::vector file::get_channels(dpp::snowflake guild_id) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::get_channels(dpp::snowflake) have being called." << std::endl; +#endif + return {}; +} + +std::string file::get_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::get_channel_source(dpp::snowflake, dpp::snowflake) have being called." << std::endl; +#endif + return {}; +} + +std::vector file::get_channel_targets(dpp::snowflake guild_id, dpp::snowflake channel_id) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::get_channel_targets(dpp::snowflake, dpp::snowflake) have being called." << std::endl; +#endif + return {}; +} + +std::vector file::get_guilds() +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::get_guilds() have being called." << std::endl; +#endif + return {}; +} + +bool file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &source) +{ +#ifndef NDEBUG + std::cerr << "[Debug] database::set_channel_source(dpp::snowflake, dpp::snowflake, const std::string&) have being called." << std::endl; +#endif + return false; +} diff --git a/src/database_file.h b/src/database_file.h new file mode 100644 index 0000000..5409862 --- /dev/null +++ b/src/database_file.h @@ -0,0 +1,50 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2024 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#ifndef DATABASE_FILE_H +#define DATABASE_FILE_H + +#include +#include +#include "database_core.h" + +namespace bot { + namespace database { + class file : public database { + public: + explicit file(const std::filesystem::path &storage_path); + ~file(); + bool add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target) override; + std::variant find_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target) override; + std::vector get_channels(dpp::snowflake guild_id) override; + std::string get_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id) override; + std::vector get_channel_targets(dpp::snowflake guild_id, dpp::snowflake channel_id) override; + std::vector get_guilds() override; + bool set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &source) override; + + private: +#ifdef __unix__ + int fd; +#endif + std::mutex m_mutex; + std::filesystem::path m_storagePath; + }; + } +} + +#endif // DATABASE_FILE_H diff --git a/src/main.cpp b/src/main.cpp index 648bd9f..87bd82e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,12 +42,6 @@ int main(int argc, char* argv[]) { return 2; } - std::cout << "[Launch] Checking working directory..." << std::endl; - if (!std::filesystem::exists(settings.storage_path())) { - std::cerr << "[Error] Storage directory " << settings.storage_path() << " can not be found" << std::endl; - return 2; - } - dpp::cluster bot(settings.token(), dpp::i_default_intents | dpp::i_message_content); bot.on_log([&bot](const dpp::log_t &event) { std::cerr << "[Log] " << event.message << std::endl; diff --git a/src/settings.cpp b/src/settings.cpp index 96d34e4..abe7e3f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -17,10 +17,9 @@ *****************************************************************************/ #include -#include -#include #include #include +#include "database_file.h" #include "settings.h" #include "translator_libretranslate.h" using namespace bot::settings; @@ -260,18 +259,15 @@ const std::vector settings::preferred_languages() const return m_prefLangs; } -const std::filesystem::path settings::storage_path() const +std::shared_ptr settings::get_database() const { - const std::lock_guard guard(m_mutex); - return m_storagePath; + return m_database; } std::unique_ptr settings::get_translator() const { const std::lock_guard guard(m_mutex); - std::unique_ptr libretranslate( - new bot::translator::libretranslate(m_translator.hostname, m_translator.port, m_translator.url, m_translator.tls, m_translator.apiKey)); - return libretranslate; + return std::make_unique(m_translator.hostname, m_translator.port, m_translator.url, m_translator.tls, m_translator.apiKey); } const std::string settings::token() const @@ -318,14 +314,18 @@ bool settings::parse(const std::string &data) const std::lock_guard guard(m_mutex); m_token = *json_token; + // Support more Database systems in the future + std::filesystem::path storage_path; auto json_storage = json.find("storage"); if (json_storage != json.end()) - m_storagePath = std::string(*json_storage); + storage_path = std::string(*json_storage); else if (char *storagepath = getenv("DTRANSLATEBOT_STORAGE")) - m_storagePath = storagepath; + storage_path = storagepath; - if (m_storagePath.empty()) - m_storagePath = std::filesystem::current_path(); + if (storage_path.empty()) + storage_path = std::filesystem::current_path(); + + m_database = std::make_shared(storage_path); auto json_translator = json.find("translator"); if (json_translator == json.end()) { diff --git a/src/settings.h b/src/settings.h index df5723f..5a58629 100644 --- a/src/settings.h +++ b/src/settings.h @@ -18,38 +18,13 @@ #ifndef SETTINGS_H #define SETTINGS_H -#include -#include -#include -#include #include -#include -#include +#include "database_core.h" +#include "settings_types.h" #include "translator_core.h" namespace bot { namespace settings { - struct target { - std::string target; - dpp::webhook webhook; - }; - struct channel { - dpp::snowflake id; - std::string source; - std::vector targets; - }; - struct guild { - dpp::snowflake id; - std::vector channel; - }; - struct translator { - std::string hostname; - uint16_t port; - std::string url; - bool tls; - std::string apiKey; - }; - class settings { public: /* add functions */ @@ -63,7 +38,7 @@ namespace bot { const channel* get_channel(dpp::snowflake guild_id, dpp::snowflake channel_id) const; const guild* get_guild(dpp::snowflake guild_id) const; const std::vector preferred_languages() const; - const std::filesystem::path storage_path() const; + std::shared_ptr get_database() const; std::unique_ptr get_translator() const; const std::string token() const; @@ -82,9 +57,9 @@ namespace bot { mutable std::recursive_mutex m_mutex; size_t m_externallyLockedCount; uint16_t m_avatarSize; + std::shared_ptr m_database; std::vector m_guilds; std::vector m_prefLangs; - std::filesystem::path m_storagePath; bot::settings::translator m_translator; std::string m_token; std::vector m_webhookIds; diff --git a/src/settings_types.h b/src/settings_types.h new file mode 100644 index 0000000..e1c5b3c --- /dev/null +++ b/src/settings_types.h @@ -0,0 +1,53 @@ +/***************************************************************************** +* dtranslatebot Discord Translate Bot +* Copyright (C) 2023-2024 Syping +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* This software is provided as-is, no warranties are given to you, we are not +* responsible for anything with use of the software, you are self responsible. +*****************************************************************************/ + +#ifndef SETTINGS_TYPES_H +#define SETTINGS_TYPES_H + +#include +#include +#include +#include +#include + +namespace bot { + namespace settings { + struct target { + std::string target; + dpp::webhook webhook; + }; + struct channel { + dpp::snowflake id; + std::string source; + std::vector targets; + }; + struct guild { + dpp::snowflake id; + std::vector channel; + }; + struct translator { + std::string hostname; + uint16_t port; + std::string url; + bool tls; + std::string apiKey; + }; + } +} + +#endif // SETTINGS_TYPES_H