diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 9a45441..0000000 --- a/.gitattributes +++ /dev/null @@ -1,16 +0,0 @@ -* text=auto eol=lf - -# Configuration files -*.json text eol=crlf - -# Development files -CMakeLists.txt text eol=lf -*.cmake text eol=lf -*.cpp text eol=lf -*.h text eol=lf - -# BSD and Linux development files -*.pc.in text eol=lf - -# Windows development files -*.rc.in text encoding=cp1252 eol=crlf diff --git a/.github/workflows/linux-rpm.yml b/.github/workflows/linux-rpm.yml deleted file mode 100644 index b51f55d..0000000 --- a/.github/workflows/linux-rpm.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Linux -on: push -jobs: - Release: - runs-on: ubuntu-latest - strategy: - matrix: - include: - - name: Enterprise Linux 7 - version: el7 - - name: Enterprise Linux 8 - version: el8 - - name: Enterprise Linux 9 - version: el9 - - name: openSUSE Leap 15.5 - version: lp155 - steps: - - name: Cloning - uses: actions/checkout@v4 - - name: Preparing - run: mkdir -m 777 ${{github.workspace}}/rpms - - name: Build RPM - uses: addnab/docker-run-action@v3 - with: - image: docker.io/syping/dtranslatebot-build:${{matrix.version}} - options: -v ${{github.workspace}}:/home/rpmbuild/dtranslatebot -v ${{github.workspace}}/rpms:/home/rpmbuild/rpmbuild/RPMS - run: | - VERSION=$(cat dtranslatebot/CMakeLists.txt | grep -oP "project\(dtranslatebot VERSION \K(\S*)(?= LANGUAGES CXX\))") - mkdir -p dtranslatebot-$VERSION - shopt -s extglob - cp -R dtranslatebot/!(rpms|rpmsrc) \ - dtranslatebot-$VERSION - tar cfz dtranslatebot-$VERSION.tar.gz dtranslatebot-$VERSION - cp dtranslatebot-$VERSION.tar.gz \ - dtranslatebot/rpmsrc/!(*.spec) \ - rpmbuild/SOURCES - cp dtranslatebot/rpmsrc/*.spec \ - rpmbuild/SPECS - rpmbuild -ba rpmbuild/SPECS/dtranslatebot.spec - - name: Upload - uses: actions/upload-artifact@v4 - with: - name: ${{matrix.name}} - path: | - ${{github.workspace}}/rpms/x86_64/*.rpm diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index c0607fc..0000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Windows -on: push -jobs: - Release: - runs-on: windows-latest - env: - BUILD_TYPE: Release - defaults: - run: - shell: msys2 {0} - steps: - - name: Setup MSYS2 - uses: msys2/setup-msys2@v2 - with: - msystem: clang64 - update: true - install: >- - git - make - mingw-w64-clang-x86_64-clang - mingw-w64-clang-x86_64-cmake - mingw-w64-clang-x86_64-ninja - perl - - name: Cloning - uses: actions/checkout@v4 - - name: Configure CMake - run: cmake -B dtranslatebot-build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_EXE_LINKER_FLAGS="-static -lc++" -DWITH_DPP_STATIC_BUNDLE=TRUE -GNinja - - name: Download and build OpenSSL - run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target OpenSSL - - name: Download and build zlib - run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target ZLIB - - name: Download and build DPP - run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} --target DPP - - name: Build dtranslatebot - run: cmake --build dtranslatebot-build --config ${{env.BUILD_TYPE}} - - name: Install - run: cmake --install dtranslatebot-build --config ${{env.BUILD_TYPE}} --prefix dtranslatebot-install --strip - - name: Upload - uses: actions/upload-artifact@v4 - with: - name: Windows - path: | - dtranslatebot-install/bin/dtranslatebot.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index 29bf456..59e34f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,43 +17,34 @@ ****************************************************************************]] cmake_minimum_required(VERSION 3.16) -cmake_policy(VERSION 3.16...3.27) -project(dtranslatebot VERSION 0.2.0 LANGUAGES CXX) +project(dtranslatebot VERSION 0.1 LANGUAGES CXX) include(GNUInstallDirs) # dtranslatebot Source files set(DTRANSLATEBOT_HEADERS - src/core/database.h - src/core/message_queue.h - src/core/regex.h - src/core/settings.h - src/core/settings_types.h - src/core/slashcommands.h - src/core/submit_queue.h - src/core/translator.h - src/core/webhook_push.h - src/database/file/file.h - src/translator/deepl/deepl.h - src/translator/mozhi/mozhi.h - src/translator/libretranslate/libretranslate.h - src/translator/lingvatranslate/lingvatranslate.h - src/translator/stub/stub.h + src/database_core.h + src/database_file.h + src/message_queue.h + src/regex.h + src/settings.h + src/settings_types.h + src/slashcommands.h + src/submit_queue.h + src/translator_core.h + src/translator_libretranslate.h + src/webhook_push.h ) set(DTRANSLATEBOT_SOURCES - src/core/database.cpp - src/core/main.cpp - src/core/message_queue.cpp - src/core/settings.cpp - src/core/slashcommands.cpp - src/core/submit_queue.cpp - src/core/translator.cpp - src/core/webhook_push.cpp - src/database/file/file.cpp - src/translator/deepl/deepl.cpp - src/translator/mozhi/mozhi.cpp - src/translator/libretranslate/libretranslate.cpp - src/translator/lingvatranslate/lingvatranslate.cpp - src/translator/stub/stub.cpp + src/database_core.cpp + src/database_file.cpp + src/main.cpp + src/message_queue.cpp + src/settings.cpp + src/slashcommands.cpp + src/submit_queue.cpp + src/translator_core.cpp + src/translator_libretranslate.cpp + src/webhook_push.cpp ) # dtranslatebot Module Path @@ -72,59 +63,21 @@ if (WITH_BOOST) endif() # D++ Discord API Library for Bots -option(WITH_DPP_STATIC_BUNDLE "Build with DPP Static Bundle" OFF) -if (WITH_DPP_STATIC_BUNDLE) - include(DPPStaticBundle) -else() - find_package(DPP REQUIRED) -endif() +find_package(DPP REQUIRED) # pthread Support set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -# dtranslatebot Win32 Shared Resources -if (WIN32) - configure_file(src/resources/win32/dtranslatebot.rc.in "${dtranslatebot_BINARY_DIR}/resources/win32/dtranslatebot.rc" @ONLY) - list(APPEND DTRANSLATEBOT_RESOURCES - "${dtranslatebot_BINARY_DIR}/resources/win32/dtranslatebot.rc" - ) -endif() - -# dtranslatebot systemd Service -if (UNIX AND NOT APPLE) - option(WITH_SYSTEMD "Build with systemd Support" OFF) - if (WITH_SYSTEMD) - find_program(SYSTEMD_ESCAPE_EXECUTABLE NAMES systemd-escape) - if (DEFINED SYSTEMD_ESCAPE_EXECUTABLE) - execute_process( - COMMAND "${SYSTEMD_ESCAPE_EXECUTABLE}" "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/dtranslatebot" - OUTPUT_VARIABLE dtranslatebot_SERVICE_WORKDIR - ) - string(STRIP "${dtranslatebot_SERVICE_WORKDIR}" dtranslatebot_SERVICE_WORKDIR) - else() - set(dtranslatebot_SERVICE_WORKDIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/dtranslatebot") - endif() - configure_file(src/systemd/dtranslatebot.service.in "${dtranslatebot_BINARY_DIR}/systemd/service/dtranslatebot.service" @ONLY) - configure_file(src/systemd/dtranslatebot.sysusersd.in "${dtranslatebot_BINARY_DIR}/systemd/sysusers.d/dtranslatebot.conf" @ONLY) - install(FILES "${dtranslatebot_BINARY_DIR}/systemd/service/dtranslatebot.service" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/systemd/system") - install(FILES "${dtranslatebot_BINARY_DIR}/systemd/sysusers.d/dtranslatebot.conf" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/sysusers.d") - endif() -endif() - # dtranslatebot Target + Installs -add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES} ${DTRANSLATEBOT_RESOURCES}) -if (WITH_DPP_STATIC_BUNDLE) - add_dependencies(dtranslatebot DPP) -endif() +add_executable(dtranslatebot ${DTRANSLATEBOT_HEADERS} ${DTRANSLATEBOT_SOURCES}) target_compile_definitions(dtranslatebot PRIVATE - ${DPP_DEFINITIONS} $<$:DTRANSLATEBOT_USE_BOOST_REGEX> ) if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) target_compile_options(dtranslatebot PRIVATE $<$:/Zc:__cplusplus>) endif() -target_link_libraries(dtranslatebot PRIVATE ${DTRANSLATEBOT_LIBRARIES} ${DPP_LIBRARIES} Threads::Threads) +target_link_libraries(dtranslatebot PRIVATE Threads::Threads ${DPP_LIBRARIES} ${DTRANSLATEBOT_LIBRARIES}) target_include_directories(dtranslatebot PRIVATE ${DPP_INCLUDE_DIR}) set_target_properties(dtranslatebot PROPERTIES CXX_STANDARD 17 diff --git a/README.md b/README.md index 0e3049c..de6ccdc 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Open Source Discord Translation Bot - Translate incoming channel messages to a Webhook -- Support configuration through slash commands and JSON +- Support configuration through slashcommands and JSON - Cross-Platform #### Build Dependencies @@ -10,11 +10,8 @@ Open Source Discord Translation Bot - Compiler with C++17 Support - [D++: A C++ Discord API Library for Bots](https://dpp.dev/) -#### Supported Translation Engines -- [LibreTranslate](https://libretranslate.com/) (Default) -- [Lingva Translate](https://lingva.ml/) -- [Mozhi](https://codeberg.org/aryak/mozhi) -- [DeepL](https://deepl.com/) (Experimental) +#### Runtime Dependencies +- [LibreTranslate](https://libretranslate.com/) #### Build dtranslatebot @@ -26,6 +23,4 @@ sudo cmake --install dtranslatebot-build ``` ##### Optional CMake flags -`-DWITH_BOOST=TRUE` -`-DWITH_DPP_STATIC_BUNDLE=TRUE` -`-DWITH_SYSTEMD=TRUE` +`-DWITH_BOOST=TRUE` diff --git a/cmake/ArgumentPassthrough.cmake b/cmake/ArgumentPassthrough.cmake deleted file mode 100644 index a0367d2..0000000 --- a/cmake/ArgumentPassthrough.cmake +++ /dev/null @@ -1,65 +0,0 @@ -#[[************************************************************************** -* 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. -****************************************************************************]] - -if (DEFINED CMAKE_BUILD_TYPE) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") -endif() -if (DEFINED CMAKE_C_COMPILER) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}") - list(APPEND CMAKE_PASSTHROUGH_ENV "CC=${CMAKE_C_COMPILER}") -elseif ("$ENV{MSYSTEM}" STREQUAL "CLANG64") - list(APPEND CMAKE_PASSTHROUGH_ENV "CC=clang") -endif() -if (DEFINED CMAKE_C_COMPILER_TARGET) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_C_COMPILER_TARGET=${CMAKE_C_COMPILER_TARGET}") -endif() -if (DEFINED CMAKE_CXX_COMPILER) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}") - list(APPEND CMAKE_PASSTHROUGH_ENV "CXX=${CMAKE_CXX_COMPILER}") -elseif ("$ENV{MSYSTEM}" STREQUAL "CLANG64") - list(APPEND CMAKE_PASSTHROUGH_ENV "CXX=clang++") -endif() -if (DEFINED CMAKE_CXX_COMPILER_TARGET) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_CXX_COMPILER_TARGET=${CMAKE_CXX_COMPILER_TARGET}") -endif() -if (DEFINED CMAKE_RC_COMPILER) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}") -endif() -if (DEFINED CMAKE_STRIP) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_STRIP=${CMAKE_STRIP}") -endif() -if (DEFINED CMAKE_SYSROOT) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSROOT=${CMAKE_SYSROOT}") -endif() -if (DEFINED CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}") -endif() -if (DEFINED CMAKE_SYSTEM_PROCESSOR AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}") -endif() -if (DEFINED CMAKE_SYSTEM_VERSION AND NOT CMAKE_SYSTEM_VERSION STREQUAL CMAKE_HOST_SYSTEM_VERSION) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION}") -endif() -if (DEFINED CMAKE_TOOLCHAIN_FILE) - list(APPEND CMAKE_PASSTHROUGH_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}") -endif() -if (DEFINED CMAKE_PASSTHROUGH_ENV) - set(CMAKE_PASSTHROUGH_ENV - "${CMAKE_COMMAND}" -E env ${CMAKE_PASSTHROUGH_ENV} - ) -endif() diff --git a/cmake/DPPStaticBundle.cmake b/cmake/DPPStaticBundle.cmake deleted file mode 100644 index 3c214ed..0000000 --- a/cmake/DPPStaticBundle.cmake +++ /dev/null @@ -1,119 +0,0 @@ -#[[************************************************************************** -* 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. -****************************************************************************]] - -include(ArgumentPassthrough) - -# OpenSSL needs to be configured with perl and build with make -find_program(MAKE_EXECUTABLE NAMES make gmake) -if (NOT DEFINED MAKE_EXECUTABLE) - message(SEND_ERROR "make not found") -endif() - -find_program(NPROC_EXECUTABLE nproc) -if (DEFINED NPROC_EXECUTABLE) - execute_process( - COMMAND "${NPROC_EXECUTABLE}" - OUTPUT_VARIABLE NPROC - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - set(MAKE_JOBS_ARG "-j${NPROC}") -endif() - -find_program(PERL_EXECUTABLE NAMES perl) -if (NOT DEFINED PERL_EXECUTABLE) - message(SEND_ERROR "perl not found") -endif() - -include(ExternalProject) -ExternalProject_Add(ZLIB - URL https://www.zlib.net/zlib-1.3.1.tar.xz - URL_HASH SHA256=38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32 - CMAKE_ARGS - -DBUILD_SHARED_LIBS=OFF - ${CMAKE_PASSTHROUGH_ARGS} - "-DCMAKE_INSTALL_PREFIX=" - -DZLIB_BUILD_EXAMPLES=OFF - ${ZLIB_CONFIGURE_ARGS} -) -ExternalProject_Get_Property(ZLIB INSTALL_DIR) -set(ZLIB_INSTALL_DIR "${INSTALL_DIR}") - -set(OPENSSL_PLATFORM_ARG $<$:mingw64>) -ExternalProject_Add(OpenSSL - URL https://github.com/openssl/openssl/releases/download/openssl-3.0.17/openssl-3.0.17.tar.gz - URL_HASH SHA256=dfdd77e4ea1b57ff3a6dbde6b0bdc3f31db5ac99e7fdd4eaf9e1fbb6ec2db8ce - CONFIGURE_COMMAND - ${CMAKE_PASSTHROUGH_ENV} - "${PERL_EXECUTABLE}" - "/Configure" - "--prefix=" - $<$:-d> - no-dso - no-dtls - no-engine - no-shared - no-zlib - ${OPENSSL_PLATFORM_ARG} - ${OPENSSL_CONFIGURE_ARGS} - BUILD_COMMAND "${MAKE_EXECUTABLE}" ${MAKE_JOBS_ARG} build_libs - INSTALL_COMMAND "${MAKE_EXECUTABLE}" ${MAKE_JOBS_ARG} install_dev -) -ExternalProject_Get_Property(OpenSSL INSTALL_DIR) -set(OpenSSL_INSTALL_DIR "${INSTALL_DIR}") - -ExternalProject_Add(DPP - URL https://github.com/brainboxdotcc/DPP/archive/refs/tags/v10.1.3.tar.gz - URL_HASH SHA256=a32d94dcd6b23430afff82918234e4e28e0616bd2ddf743c5ab2f1778c5a600b - CMAKE_ARGS - -DAVX_TYPE=AVX0 - -DBUILD_SHARED_LIBS=OFF - -DBUILD_VOICE_SUPPORT=OFF - ${CMAKE_PASSTHROUGH_ARGS} - "-DCMAKE_INSTALL_PREFIX=" - -DDPP_BUILD_TEST=OFF - -DDPP_NO_CORO=ON - -DDPP_NO_VCPKG=ON - -DRUN_LDCONFIG=OFF - "-DOpenSSL_ROOT=${OpenSSL_INSTALL_DIR}" - "-DZLIB_ROOT=${ZLIB_INSTALL_DIR}" - ${DPP_CONFIGURE_ARGS} - DEPENDS OpenSSL ZLIB -) -ExternalProject_Get_Property(DPP INSTALL_DIR) -set(DPP_INSTALL_DIR "${INSTALL_DIR}") -set(DPP_INCLUDE_DIR "${DPP_INSTALL_DIR}/include") -set(DPP_LIBRARIES - -Wl,-Bstatic - "-L${DPP_INSTALL_DIR}/lib" - "-L${DPP_INSTALL_DIR}/lib64" - dpp - "-L${OpenSSL_INSTALL_DIR}/lib" - "-L${OpenSSL_INSTALL_DIR}/lib64" - ssl - crypto - "-L${ZLIB_INSTALL_DIR}/lib" - "-L${ZLIB_INSTALL_DIR}/lib64" - $,zlibstatic,z> - -Wl,-Bdynamic -) -if (WIN32) - set(DPP_DEFINITIONS DPP_STATIC) - list(APPEND DPP_LIBRARIES - ws2_32 - ) -endif() diff --git a/cmake/FindDPP.cmake b/cmake/FindDPP.cmake index 55c928e..a555a7f 100644 --- a/cmake/FindDPP.cmake +++ b/cmake/FindDPP.cmake @@ -1,4 +1,4 @@ -find_path(DPP_INCLUDE_DIR NAMES "dpp/dpp.h" HINTS "${DPP_ROOT_DIR}") -find_library(DPP_LIBRARIES NAMES "dpp" "libdpp.a" HINTS "${DPP_ROOT_DIR}") +find_path(DPP_INCLUDE_DIR NAMES dpp/dpp.h HINTS ${DPP_ROOT_DIR}) +find_library(DPP_LIBRARIES NAMES dpp "libdpp.a" HINTS ${DPP_ROOT_DIR}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DPP DEFAULT_MSG DPP_LIBRARIES DPP_INCLUDE_DIR) diff --git a/etc/dtranslatebot.example.json b/etc/dtranslatebot.example.json new file mode 100644 index 0000000..202a0ee --- /dev/null +++ b/etc/dtranslatebot.example.json @@ -0,0 +1,37 @@ +{ + "guilds": { + "$guild1_id": { + "$channel1_id": { + "source": "en", + "target": "de", + "webhook": "https://discord.com/api/webhooks/$guild1_de_webhook_id/$guild1_de_webhook_token" + }, + "$channel2_id": { + "source": "de", + "target": "en", + "webhook": "https://discord.com/api/webhooks/$guild1_en_webhook_id/$guild1_en_webhook_token" + } + }, + "My Discord Guild": { + "id": $guild2_id, + "General English": { + "id": $channel3_id, + "source": "en", + "target": { + "de": "https://discord.com/api/webhooks/$guild2_de_webhook_id/$guild2_de_webhook_token", + "fr": "https://discord.com/api/webhooks/$guild2_fr_webhook_id/$guild2_fr_webhook_token" + } + } + } + }, + "preferred_lang": ["en", "de", "fr", ...], + "storage": "$working_directory", + "user": { + "avatar_size": 256 + }, + "token": "$bot_token", + "translator": { + "url": "http://127.0.0.1:5000/", + "apiKey": "" + } +} diff --git a/etc/dtranslatebot.json b/etc/dtranslatebot.json new file mode 100644 index 0000000..28381db --- /dev/null +++ b/etc/dtranslatebot.json @@ -0,0 +1,7 @@ +{ + "token": "", + "translator": { + "url": "http://127.0.0.1:5000/", + "apiKey": "" + } +} diff --git a/rpmsrc/dtranslatebot.json b/rpmsrc/dtranslatebot.json deleted file mode 100644 index e0a0dc0..0000000 --- a/rpmsrc/dtranslatebot.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - /* - A DISCORD BOT TOKEN IS NECESSARY TO USE THIS APPLICATION! - - You can get a Bot Token from the Discord Developer Portal - by creating a New Application: - https://discord.com/developers/applications - */ - - "token": "", - "translator": { - "type": "stub" - } -} diff --git a/rpmsrc/dtranslatebot.service b/rpmsrc/dtranslatebot.service deleted file mode 100644 index 7bd129f..0000000 --- a/rpmsrc/dtranslatebot.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Discord Translation Bot -After=network.target - -[Service] -User=dtranslatebot -Group=dtranslatebot -WorkingDirectory=/var/lib/dtranslatebot -ExecStart=/usr/bin/dtranslatebot /etc/dtranslatebot.json -Restart=on-abnormal - -[Install] -WantedBy=multi-user.target diff --git a/rpmsrc/dtranslatebot.spec b/rpmsrc/dtranslatebot.spec deleted file mode 100644 index 163461d..0000000 --- a/rpmsrc/dtranslatebot.spec +++ /dev/null @@ -1,96 +0,0 @@ -%global _lto_cflags %{?_lto_cflags} -ffat-lto-objects - -%if 0%{?rhel} && 0%{?rhel} < 8 -%global cmake %{?cmake3} -%global cmake_build %{?cmake3_build} -%global cmake_install %{?cmake3_install} -%global cmake_suffix 3 -%global toolset_prefix devtoolset-9- -%endif -%if 0%{?rhel} && 0%{?rhel} == 8 -%global toolset_prefix gcc-toolset-9- -%endif -%if 0%{?suse_version} && 0%{?suse_version} < 1600 -%global toolset_version 9 -%endif - -Name: dtranslatebot -Version: 0.2.0 -Release: 1%{?dist} -Summary: Discord Translation Bot -License: BSD-2-Clause -URL: https://github.com/Syping/%{name} -Source0: %{name}-%{version}.tar.gz -Source1: %{name}.json -Source2: %{name}.service -Source3: %{name}.sysusersd - -%if 0%{?fedora} || 0%{?rhel} -BuildRequires: %{?toolset_prefix}annobin -%if 0%{?rhel} && 0%{?rhel} < 9 -BuildRequires: epel-rpm-macros-systemd -%endif -%endif -BuildRequires: cmake%{?cmake_suffix} -BuildRequires: %{?toolset_prefix}gcc%{?toolset_version}-c++ -BuildRequires: make -BuildRequires: perl(IPC::Cmd) -BuildRequires: systemd-rpm-macros -%systemd_requires -%if 0%{?fedora} || 0%{?rhel} -%sysusers_requires_compat -%endif - -%description -dtranslatebot is a Discord Bot which translate incoming Discord messages to Discord webhooks. - -%prep -%setup -q - -%build -%if 0%{?rhel} && 0%{?rhel} < 8 -source /opt/rh/devtoolset-9/enable -%endif -%if 0%{?rhel} && 0%{?rhel} == 8 -source /opt/rh/gcc-toolset-9/enable -%endif -%cmake \ - -DCMAKE_BUILD_TYPE=Release \ -%if 0%{?toolset_version} - -DCMAKE_C_COMPILER=gcc-%{toolset_version} \ - -DCMAKE_CXX_COMPILER=g++-%{toolset_version} \ -%endif - -DWITH_DPP_STATIC_BUNDLE=TRUE \ - -DWITH_SYSTEMD=TRUE -%cmake_build - -%install -%cmake_install -mkdir -p %{buildroot}%{_localstatedir}/lib/%{name} -install -p -D -m 0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/%{name}.json -install -p -D -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}.service -install -p -D -m 0644 %{SOURCE3} %{buildroot}%{_sysusersdir}/%{name}.conf - -%pre -%if 0%{?fedora} || 0%{?rhel} -%sysusers_create_compat %{SOURCE3} -%endif -%if 0%{?suse_version} -%sysusers_create_package %{name} %{SOURCE3} -%endif - -%post -%systemd_post %{name}.service - -%preun -%systemd_preun %{name}.service - -%postun -%systemd_postun_with_restart %{name}.service - -%files -%{_bindir}/%{name} -%{_unitdir}/%{name}.service -%{_sysusersdir}/%{name}.conf -%config(noreplace) %attr(0640,root,%{name}) %{_sysconfdir}/%{name}.json -%dir %attr(0750,%{name},%{name}) %{_localstatedir}/lib/%{name} diff --git a/rpmsrc/dtranslatebot.sysusersd b/rpmsrc/dtranslatebot.sysusersd deleted file mode 100644 index f181398..0000000 --- a/rpmsrc/dtranslatebot.sysusersd +++ /dev/null @@ -1,2 +0,0 @@ -#Type Name ID GECOS Home directory Shell -u dtranslatebot - "Discord Translation Bot" /var/lib/translatebot - diff --git a/src/core/database.cpp b/src/database_core.cpp similarity index 97% rename from src/core/database.cpp rename to src/database_core.cpp index 2911138..b540f36 100644 --- a/src/core/database.cpp +++ b/src/database_core.cpp @@ -19,9 +19,17 @@ #ifndef NDEBUG #include #endif -#include "database.h" +#include "database_core.h" using namespace bot::database; +database::database() +{ +} + +database::~database() +{ +} + void database::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target) { #ifndef NDEBUG diff --git a/src/core/database.h b/src/database_core.h similarity index 90% rename from src/core/database.h rename to src/database_core.h index 2589f46..6526eda 100644 --- a/src/core/database.h +++ b/src/database_core.h @@ -16,8 +16,8 @@ * responsible for anything with use of the software, you are self responsible. *****************************************************************************/ -#ifndef DATABASE_H -#define DATABASE_H +#ifndef DATABASE_CORE_H +#define DATABASE_CORE_H #include "settings_types.h" @@ -30,10 +30,8 @@ namespace bot { class database { public: - explicit database() = default; - database(const database&) = delete; - database& operator=(const database&) = delete; - virtual ~database() = default; + explicit database(); + virtual ~database(); virtual void add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const bot::settings::target &target); virtual void delete_channel(dpp::snowflake guild_id, dpp::snowflake channel_id); virtual void delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target); @@ -54,4 +52,4 @@ namespace bot { } } -#endif // DATABASE_H +#endif // DATABASE_CORE_H diff --git a/src/database/file/file.cpp b/src/database_file.cpp similarity index 95% rename from src/database/file/file.cpp rename to src/database_file.cpp index e7c6a6d..db5774b 100644 --- a/src/database/file/file.cpp +++ b/src/database_file.cpp @@ -27,7 +27,7 @@ #include #include #include -#include "file.h" +#include "database_file.h" using namespace bot::database; using namespace std::string_literals; @@ -98,7 +98,7 @@ void file::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); channel.targets.push_back(target); cache_add_channel(guild_id, channel_id); guild->channel.push_back(std::move(channel)); @@ -107,7 +107,7 @@ void file::add_channel_target(dpp::snowflake guild_id, dpp::snowflake channel_id } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); channel.targets.push_back(target); cache_add_channel(guild_id, channel_id); m_dataCache.push_back({ guild_id, { std::move(channel) } }); @@ -141,7 +141,7 @@ void file::delete_channel(dpp::snowflake guild_id, dpp::snowflake channel_id) } std::vector channels; - cache_guild(guild_id, channels); + cache_guild(guild_id, &channels); for (auto channel = channels.begin(); channel != channels.end(); channel++) { if (*channel == channel_id) { channels.erase(channel); @@ -175,7 +175,7 @@ void file::delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) { if (_target->target == target) { channel.targets.erase(_target); @@ -188,7 +188,7 @@ void file::delete_channel_target(dpp::snowflake guild_id, dpp::snowflake channel } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); for (auto _target = channel.targets.begin(); _target != channel.targets.end(); _target++) { if (_target->target == target) { channel.targets.erase(_target); @@ -266,7 +266,7 @@ bot::settings::channel file::get_channel(dpp::snowflake guild_id, dpp::snowflake } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); return channel; } @@ -281,7 +281,7 @@ std::vector file::get_channels(dpp::snowflake guild_id) } std::vector channels; - cache_guild(guild_id, channels); + cache_guild(guild_id, &channels); return channels; } @@ -330,7 +330,7 @@ std::vector file::get_guilds() { const std::lock_guard guard(m_mutex); std::vector guilds; - list_guilds(guilds); + list_guilds(&guilds); return guilds; } @@ -348,7 +348,7 @@ void file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); channel.source = source; cache_add_channel(guild_id, channel_id); guild->channel.push_back(std::move(channel)); @@ -357,7 +357,7 @@ void file::set_channel_source(dpp::snowflake guild_id, dpp::snowflake channel_id } bot::settings::channel channel; - cache_get_channel(channel_id, channel); + cache_get_channel(channel_id, &channel); channel.source = source; cache_add_channel(guild_id, channel_id); m_dataCache.push_back({ guild_id, { std::move(channel) } }); @@ -390,16 +390,16 @@ void file::cache_add_channel(dpp::snowflake guild_id, dpp::snowflake channel_id) } std::vector channels; - cache_guild(guild_id, channels); + cache_guild(guild_id, &channels); if (std::find(channels.begin(), channels.end(), channel_id) == channels.end()) channels.push_back(channel_id); m_channelCache.push_back({ guild_id, std::move(channels) }); } -void file::cache_get_channel(dpp::snowflake channel_id, settings::channel &channel) +void file::cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *channel) { - channel.id = channel_id; + channel->id = channel_id; const std::filesystem::path channel_file = m_storagePath / "channel" / (std::to_string(channel_id) + ".json"); @@ -418,7 +418,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, settings::channel &chann if (json.is_object()) { auto json_channel_source = json.find("source"); if (json_channel_source != json.end()) - channel.source = *json_channel_source; + channel->source = *json_channel_source; auto json_channel_target = json.find("target"); if (json_channel_target != json.end()) { @@ -433,7 +433,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, settings::channel &chann else if (json_target->is_string()) { target.webhook = dpp::webhook(*json_target); } - channel.targets.push_back(std::move(target)); + channel->targets.push_back(std::move(target)); } } } @@ -444,7 +444,7 @@ void file::cache_get_channel(dpp::snowflake channel_id, settings::channel &chann } } -void file::cache_guild(dpp::snowflake guild_id, std::vector &channels) +void file::cache_guild(dpp::snowflake guild_id, std::vector *channels) { const std::filesystem::path guild_file = m_storagePath / "guild" / (std::to_string(guild_id) + ".json"); @@ -463,9 +463,9 @@ void file::cache_guild(dpp::snowflake guild_id, std::vector &cha if (json.is_array()) { for (auto channel = json.begin(); channel != json.end(); channel++) { if (channel->is_number()) - channels.push_back(*channel); + channels->push_back(*channel); else if (channel->is_string()) - channels.push_back(std::stoull(std::string(*channel))); + channels->push_back(std::stoull(std::string(*channel))); } } } @@ -474,7 +474,7 @@ void file::cache_guild(dpp::snowflake guild_id, std::vector &cha } } -void file::list_guilds(std::vector &guilds) +void file::list_guilds(std::vector *guilds) { const std::filesystem::path guild_dir = m_storagePath / "guild"; @@ -488,7 +488,7 @@ void file::list_guilds(std::vector &guilds) if (std::all_of(guild_filename.begin(), guild_filename.end(), ::isdigit)) { try { dpp::snowflake guild_id = std::stoull(guild_filename); - guilds.push_back(guild_id); + guilds->push_back(guild_id); } catch (const std::exception &exception) { std::cerr << "[Exception] " << exception.what() << std::endl; diff --git a/src/database/file/file.h b/src/database_file.h similarity index 95% rename from src/database/file/file.h rename to src/database_file.h index f34bd4d..5947b3f 100644 --- a/src/database/file/file.h +++ b/src/database_file.h @@ -26,7 +26,7 @@ #define WIN32_LEAN_AND_MEAN #include #endif -#include "../../core/database.h" +#include "database_core.h" namespace bot { namespace database { @@ -53,9 +53,9 @@ namespace bot { private: void cache_add_channel(dpp::snowflake guild_id, dpp::snowflake channel_id); - void cache_get_channel(dpp::snowflake channel_id, bot::settings::channel &channel); - void cache_guild(dpp::snowflake guild_id, std::vector &channels); - void list_guilds(std::vector &guilds); + void cache_get_channel(dpp::snowflake channel_id, bot::settings::channel *channel); + void cache_guild(dpp::snowflake guild_id, std::vector *channels); + void list_guilds(std::vector *guilds); void sync_cache(); #if defined(__unix__) int fd; diff --git a/src/core/main.cpp b/src/main.cpp similarity index 70% rename from src/core/main.cpp rename to src/main.cpp index 43ddd75..87bd82e 100644 --- a/src/core/main.cpp +++ b/src/main.cpp @@ -24,39 +24,22 @@ #include "message_queue.h" #include "settings.h" #include "slashcommands.h" -using namespace std::chrono_literals; int main(int argc, char* argv[]) { - bool flag_wait_for_translator = false; - std::vector args; - for (size_t i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--wait-for-translator")) - flag_wait_for_translator = true; - else - args.push_back(argv[i]); - } - if (args.size() != 1) { - std::cout << "Usage: " << argv[0] << " [--wait-for-translator] [json]" << std::endl; + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " [json]" << std::endl; return 0; } std::cout << "[Launch] Processing configuration..." << std::endl; bot::settings::settings settings; - if (!settings.parse_file(args.at(0))) + if (!settings.parse_file(argv[1])) return 1; - for (;;) { - std::cout << "[Launch] Requesting supported languages..." << std::endl; - if (!settings.get_translator()->get_languages().empty()) { - break; - } - else if (flag_wait_for_translator) { - std::this_thread::sleep_for(5000ms); - } - else { - std::cerr << "[Error] Failed to initialise translateable languages" << std::endl; - return 1; - } + std::cout << "[Launch] Requesting supported languages..." << std::endl; + if (settings.get_translator()->get_languages().empty()) { + std::cerr << "[Error] Failed to initialise translateable languages" << std::endl; + return 2; } dpp::cluster bot(settings.token(), dpp::i_default_intents | dpp::i_message_content); @@ -72,7 +55,7 @@ int main(int argc, char* argv[]) { bot.on_message_create(std::bind(&bot::message_queue::process_message_event, &message_queue, &bot, &settings, std::placeholders::_1)); bot.on_slashcommand(std::bind(&bot::slashcommands::process_command_event, &bot, &settings, std::placeholders::_1)); - bot.on_ready([&bot, &settings]([[maybe_unused]] const dpp::ready_t &event) { + bot.on_ready([&bot, &settings](const dpp::ready_t &event) { if (dpp::run_once()) { bot::slashcommands::register_commands(&bot, &settings); } diff --git a/src/core/message_queue.cpp b/src/message_queue.cpp similarity index 94% rename from src/core/message_queue.cpp rename to src/message_queue.cpp index a4f1085..7276de3 100644 --- a/src/core/message_queue.cpp +++ b/src/message_queue.cpp @@ -19,7 +19,7 @@ #include #include "message_queue.h" #include "settings.h" -using bot::message_queue; +using namespace bot; using namespace std::chrono_literals; void message_queue::add(const message &message) @@ -36,10 +36,6 @@ void message_queue::add(message &&message) void message_queue::process_message_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::message_create_t &event) { - // We check for conditions we want to skip translation for - if (event.msg.author.id == bot->me.id || event.msg.content.empty() || event.msg.has_thread()) - return; - if (event.msg.webhook_id) { const std::lock_guard guard(*settings); @@ -48,6 +44,10 @@ void message_queue::process_message_event(dpp::cluster *bot, bot::settings::sett return; } + // Same as before, just without the involvement of webhooks + if (event.msg.author.id == bot->me.id) + return; + const std::lock_guard guard(*settings); if (const bot::settings::channel *channel = settings->get_channel(event.msg.guild_id, event.msg.channel_id)) { bot::message message; diff --git a/src/core/message_queue.h b/src/message_queue.h similarity index 100% rename from src/core/message_queue.h rename to src/message_queue.h diff --git a/src/core/regex.h b/src/regex.h similarity index 100% rename from src/core/regex.h rename to src/regex.h diff --git a/src/resources/win32/dtranslatebot.rc.in b/src/resources/win32/dtranslatebot.rc.in deleted file mode 100644 index d1dc7ce..0000000 --- a/src/resources/win32/dtranslatebot.rc.in +++ /dev/null @@ -1,29 +0,0 @@ -#include -VS_VERSION_INFO VERSIONINFO -FILEVERSION @dtranslatebot_VERSION_MAJOR@, @dtranslatebot_VERSION_MINOR@, @dtranslatebot_VERSION_PATCH@, 0 -PRODUCTVERSION @dtranslatebot_VERSION_MAJOR@, @dtranslatebot_VERSION_MINOR@, @dtranslatebot_VERSION_PATCH@, 0 -FILEFLAGSMASK 0x3fL -FILEFLAGS 0 -FILEOS VOS_NT_WINDOWS32 -FILETYPE VFT_APP -FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Syping" - VALUE "FileDescription", "Discord Translation Bot" - VALUE "FileVersion", "@dtranslatebot_VERSION@" - VALUE "InternalName", "dtranslatebot" - VALUE "LegalCopyright", "Copyright © 2023-2024 Syping" - VALUE "OriginalFilename", "dtranslatebot.exe" - VALUE "ProductName", "dtranslatebot" - VALUE "ProductVersion", "@dtranslatebot_VERSION@" - END - END -END diff --git a/src/core/settings.cpp b/src/settings.cpp similarity index 68% rename from src/core/settings.cpp rename to src/settings.cpp index 24181c7..cbce34a 100644 --- a/src/core/settings.cpp +++ b/src/settings.cpp @@ -19,23 +19,19 @@ #include #include #include +#include "database_file.h" #include "settings.h" -#include "../database/file/file.h" -#include "../translator/deepl/deepl.h" -#include "../translator/mozhi/mozhi.h" -#include "../translator/libretranslate/libretranslate.h" -#include "../translator/lingvatranslate/lingvatranslate.h" -#include "../translator/stub/stub.h" +#include "translator_libretranslate.h" using namespace bot::settings; -void process_database_channels(std::shared_ptr database, bot::settings::guild &guild, std::vector &webhookIds) +void process_database_channels(std::shared_ptr database, bot::settings::guild *guild, std::vector *webhookIds) { - const std::vector db_channels = database->get_channels(guild.id); + const std::vector db_channels = database->get_channels(guild->id); for (auto db_channel_id = db_channels.begin(); db_channel_id != db_channels.end(); db_channel_id++) { bool channel_found = false; - for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) { + for (auto channel = guild->channel.begin(); channel != guild->channel.end(); channel++) { if (channel->id == *db_channel_id) { - const bot::settings::channel db_channel = database->get_channel(guild.id, channel->id); + const bot::settings::channel db_channel = database->get_channel(guild->id, channel->id); if (!db_channel.source.empty()) channel->source = db_channel.source; for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) { @@ -43,14 +39,14 @@ void process_database_channels(std::shared_ptr database for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) { if (target->target == db_target->target) { target->webhook = db_target->webhook; - webhookIds.push_back(db_target->webhook.id); + webhookIds->push_back(db_target->webhook.id); target_found = true; break; } } if (!target_found) { channel->targets.push_back(*db_target); - webhookIds.push_back(db_target->webhook.id); + webhookIds->push_back(db_target->webhook.id); } } channel_found = true; @@ -58,23 +54,23 @@ void process_database_channels(std::shared_ptr database } } if (!channel_found) { - const bot::settings::channel db_channel = database->get_channel(guild.id, *db_channel_id); - guild.channel.push_back(db_channel); + const bot::settings::channel db_channel = database->get_channel(guild->id, *db_channel_id); + guild->channel.push_back(db_channel); for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) - webhookIds.push_back(db_target->webhook.id); + webhookIds->push_back(db_target->webhook.id); } } } -void process_database(std::shared_ptr database, std::vector &guilds, std::vector &webhookIds) +void process_database(std::shared_ptr database, std::vector *guilds, std::vector *webhookIds) { std::cout << "[Launch] Loading database..." << std::endl; const std::vector db_guilds = database->get_guilds(); for (auto db_guild_id = db_guilds.begin(); db_guild_id != db_guilds.end(); db_guild_id++) { bool guild_found = false; - for (auto guild = guilds.begin(); guild != guilds.end(); guild++) { + for (auto guild = guilds->begin(); guild != guilds->end(); guild++) { if (guild->id == *db_guild_id) { - process_database_channels(database, *guild, webhookIds); + process_database_channels(database, &*guild, webhookIds); guild_found = true; break; } @@ -82,13 +78,13 @@ void process_database(std::shared_ptr database, std::ve if (!guild_found) { bot::settings::guild guild; guild.id = *db_guild_id; - process_database_channels(database, guild, webhookIds); - guilds.push_back(std::move(guild)); + process_database_channels(database, &guild, webhookIds); + guilds->push_back(std::move(guild)); } } } -void process_guild_settings(const dpp::json &json, std::vector &guilds, std::vector &webhookIds) +void process_guild_settings(const dpp::json &json, std::vector *guilds, std::vector *webhookIds) { for (auto json_guild = json.begin(); json_guild != json.end(); json_guild++) { if (json_guild->is_object()) { @@ -132,7 +128,7 @@ void process_guild_settings(const dpp::json &json, std::vector &guilds, s target target; target.target = *json_channel_target; target.webhook = dpp::webhook(json_channel->at("webhook")); - webhookIds.push_back(target.webhook.id); + webhookIds->push_back(target.webhook.id); channel.targets.push_back(std::move(target)); } else if (json_channel_target->is_object()) { @@ -140,7 +136,7 @@ void process_guild_settings(const dpp::json &json, std::vector &guilds, s target target; target.target = json_target.key(); target.webhook = dpp::webhook(*json_target); - webhookIds.push_back(target.webhook.id); + webhookIds->push_back(target.webhook.id); channel.targets.push_back(std::move(target)); } } @@ -150,7 +146,7 @@ void process_guild_settings(const dpp::json &json, std::vector &guilds, s guild.channel.push_back(std::move(channel)); } } - guilds.push_back(std::move(guild)); + guilds->push_back(std::move(guild)); } } } @@ -166,162 +162,103 @@ void process_preflang_settings(const dpp::json &json, std::vector * } } -void process_server_url(const std::string &url, translator &translator) +void process_user_settings(const dpp::json &json, uint16_t *avatar_size) +{ + auto json_avatar_size = json.find("avatar_size"); + if (json_avatar_size != json.end()) { + *avatar_size = *json_avatar_size; + if (*avatar_size < 16) + *avatar_size = 16; + else if (*avatar_size > 4096) + *avatar_size = 4096; + } +} + +void process_url(const std::string &url, translator *translator) { std::string_view url_v = url; if (url_v.substr(0, 7) == "http://") { - translator.tls = false; - if (!translator.port) - translator.port = 80; + translator->tls = false; + if (!translator->port) + translator->port = 80; url_v = url_v.substr(7); } else if (url_v.substr(0, 8) == "https://") { - translator.tls = true; - if (!translator.port) - translator.port = 443; + translator->tls = true; + if (!translator->port) + translator->port = 443; url_v = url_v.substr(8); } else { - translator.tls = false; - if (!translator.port) - translator.port = 80; + translator->tls = false; + if (!translator->port) + translator->port = 80; } auto slash_pos = url_v.find_first_of('/'); if (slash_pos != std::string_view::npos) { - translator.url = url_v.substr(slash_pos); + translator->url = url_v.substr(slash_pos); url_v = url_v.substr(0, slash_pos); } else { - translator.url = "/"; + translator->url = "/"; url_v = url_v.substr(0, slash_pos); } - // We don't have IPv6 support here yet - auto colon_pos = url_v.find_last_of(':'); + auto colon_pos = url_v.find_first_of(':'); if (colon_pos != std::string_view::npos) { - translator.hostname = url_v.substr(0, colon_pos); + translator->hostname = url_v.substr(0, colon_pos); const int port = std::stoi(std::string(url_v.substr(colon_pos + 1))); if (port > 0 && port < 65536) - translator.port = static_cast(port); + translator->port = static_cast(port); else throw std::invalid_argument("Port is out of range"); } else { - translator.hostname = url_v; + translator->hostname = url_v; } } -bool process_server(const dpp::json &json, translator &translator) -{ - auto json_hostname = json.find("hostname"); - if (json_hostname != json.end()) - translator.hostname = *json_hostname; - - auto json_tls = json.find("tls"); - if (json_tls != json.end()) - translator.tls = *json_tls; - else - translator.tls = false; - - auto json_port = json.find("port"); - if (json_port != json.end()) - translator.port = *json_port; - else - translator.port = 0; - - auto json_url = json.find("url"); - if (json_url == json.end()) { - std::cerr << "[Error] Value url not found in translator object" << std::endl; - return false; - } - if (translator.hostname.empty()) - process_server_url(*json_url, translator); - else - translator.url = *json_url; - - auto json_apiKey = json.find("apiKey"); - if (json_apiKey != json.end()) - translator.apiKey = *json_apiKey; - - return true; -} - -void process_user_settings(const dpp::json &json, uint16_t &avatar_size) -{ - auto json_avatar_size = json.find("avatar_size"); - if (json_avatar_size != json.end()) { - avatar_size = *json_avatar_size; - if (avatar_size < 16) - avatar_size = 16; - else if (avatar_size > 4096) - avatar_size = 4096; - } -} - -bool process_translator_settings(const dpp::json &json, std::shared_ptr &translator_instance) +bool process_translator_settings(const dpp::json &json, translator *translator) { if (!json.is_object()) { std::cerr << "[Error] Value translator needs to be a object" << std::endl; return false; } - bot::settings::translator translator; - auto json_translator_type = json.find("type"); - if (json_translator_type != json.end()) { - translator.type = *json_translator_type; - std::transform(translator.type.begin(), translator.type.end(), translator.type.begin(), ::tolower); - } - else { - translator.type = "libretranslate"; - } + auto json_translate_hostname = json.find("hostname"); + if (json_translate_hostname != json.end()) + translator->hostname = *json_translate_hostname; + else + translator->hostname = {}; - if (translator.type == "deepl") { - auto json_deepl_hostname = json.find("hostname"); - if (json_deepl_hostname != json.end()) - translator.hostname = *json_deepl_hostname; - else - translator.hostname = "api-free.deepl.com"; + auto json_translate_tls = json.find("tls"); + if (json_translate_tls != json.end()) + translator->tls = *json_translate_tls; + else + translator->tls = false; - auto json_deepl_apiKey = json.find("apiKey"); - if (json_deepl_apiKey == json.end()) { - std::cerr << "[Error] DeepL requires API key for authorization" << std::endl; - return false; - } - translator.apiKey = *json_deepl_apiKey; + auto json_translate_port = json.find("port"); + if (json_translate_port != json.end()) + translator->port = *json_translate_port; + else + translator->port = 0; - translator_instance = std::make_shared(translator.hostname, translator.apiKey); - } - else if (translator.type == "mozhi") { - if (!process_server(json, translator)) - return false; - - std::string mozhi_engine; - auto json_mozhi_engine = json.find("engine"); - if (json_mozhi_engine != json.end()) - mozhi_engine = *json_mozhi_engine; - else - mozhi_engine = "google"; - - translator_instance = std::make_shared(translator.hostname, translator.port, translator.url, translator.tls, mozhi_engine); - } - else if (translator.type == "libretranslate") { - if (!process_server(json, translator)) - return false; - - translator_instance = std::make_shared(translator.hostname, translator.port, translator.url, translator.tls, translator.apiKey); - } - else if (translator.type == "lingvatranslate") { - if (!process_server(json, translator)) - return false; - - translator_instance = std::make_shared(translator.hostname, translator.port, translator.url, translator.tls); - } - else if (translator.type == "stub") { - translator_instance = std::make_shared(); - } - else { - std::cerr << "[Error] Translator " << translator.type << " is unknown" << std::endl; + auto json_translate_url = json.find("url"); + if (json_translate_url == json.end()) { + std::cerr << "[Error] Value url not found in translator object" << std::endl; return false; } + if (translator->hostname.empty()) { + process_url(*json_translate_url, translator); + } + else { + translator->url = *json_translate_url; + } + + auto json_translate_apiKey = json.find("apiKey"); + if (json_translate_apiKey != json.end()) + translator->apiKey = *json_translate_apiKey; + else + translator->apiKey.clear(); return true; } @@ -363,27 +300,6 @@ void settings::add_translatebot_webhook(dpp::snowflake webhook_id) m_webhookIds.push_back(webhook_id); } -void settings::erase_channel(guild &guild, dpp::snowflake channel_id) -{ - for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) { - if (channel->id == channel_id) { - guild.channel.erase(channel); - return; - } - } -} - -void settings::erase_guild(dpp::snowflake guild_id) -{ - const std::lock_guard guard(m_mutex); - for (auto guild = m_guilds.begin(); guild != m_guilds.end(); guild++) { - if (guild->id == guild_id) { - m_guilds.erase(guild); - return; - } - } -} - void settings::erase_translatebot_webhook(dpp::snowflake webhook_id) { const std::lock_guard guard(m_mutex); @@ -398,9 +314,9 @@ uint16_t settings::avatar_size() return m_avatarSize; } -channel* settings::get_channel(guild &guild, dpp::snowflake channel_id) +channel* settings::get_channel(guild *guild, dpp::snowflake channel_id) { - for (auto channel = guild.channel.begin(); channel != guild.channel.end(); channel++) { + for (auto channel = guild->channel.begin(); channel != guild->channel.end(); channel++) { if (channel->id == channel_id) return &*channel; } @@ -497,10 +413,10 @@ std::shared_ptr settings::get_database() const return m_database; } -std::shared_ptr settings::get_translator() const +std::unique_ptr settings::get_translator() const { const std::lock_guard guard(m_mutex); - return m_translator; + 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 @@ -530,7 +446,7 @@ bool settings::parse(const std::string &data, bool initialize) try { dpp::json json; try { - json = dpp::json::parse(data, nullptr, true, true); + json = dpp::json::parse(data); } catch (const std::exception &exception) { std::cerr << "[Exception] " << exception.what() << std::endl; @@ -538,24 +454,21 @@ bool settings::parse(const std::string &data, bool initialize) return false; } - const std::lock_guard guard(m_mutex); auto json_token = json.find("token"); - if (json_token != json.end()) - m_token = *json_token; - else if (char *token = getenv("DTRANSLATEBOT_TOKEN")) - m_token = token; - - if (m_token.empty()) { - std::cerr << "[Error] Discord Bot Token is not configured" << std::endl; + if (json_token == json.end()) { + std::cerr << "[Error] Value token not found" << std::endl; return false; } + const std::lock_guard guard(m_mutex); + m_token = *json_token; + std::filesystem::path storage_path; auto json_storage = json.find("storage"); if (json_storage != json.end()) storage_path = std::string(*json_storage); else if (char *storagepath = getenv("DTRANSLATEBOT_STORAGE")) - storage_path = storagepath; + storage_path = storagepath; if (storage_path.empty()) storage_path = std::filesystem::current_path(); @@ -567,12 +480,14 @@ bool settings::parse(const std::string &data, bool initialize) std::cerr << "[Error] Value translator not found" << std::endl; return false; } - if (!process_translator_settings(*json_translator, m_translator)) + if (!process_translator_settings(*json_translator, &m_translator)) return false; + m_avatarSize = 256; + auto json_guilds = json.find("guilds"); if (json_guilds != json.end() && json_guilds->is_object()) - process_guild_settings(*json_guilds, m_guilds, m_webhookIds); + process_guild_settings(*json_guilds, &m_guilds, &m_webhookIds); auto json_preflangs = json.find("preferred_lang"); if (json_preflangs != json.end() && json_preflangs->is_array()) @@ -580,9 +495,9 @@ bool settings::parse(const std::string &data, bool initialize) auto json_user = json.find("user"); if (json_user != json.end() && json_user->is_object()) - process_user_settings(*json_user, m_avatarSize); + process_user_settings(*json_user, &m_avatarSize); - process_database(m_database, m_guilds, m_webhookIds); + process_database(m_database, &m_guilds, &m_webhookIds); return true; } diff --git a/src/core/settings.h b/src/settings.h similarity index 81% rename from src/core/settings.h rename to src/settings.h index f71f812..7f51f16 100644 --- a/src/core/settings.h +++ b/src/settings.h @@ -19,9 +19,9 @@ #ifndef SETTINGS_H #define SETTINGS_H #include -#include "database.h" +#include "database_core.h" #include "settings_types.h" -#include "translator.h" +#include "translator_core.h" namespace bot { namespace settings { @@ -33,13 +33,11 @@ namespace bot { void add_translatebot_webhook(dpp::snowflake webhook_id); /* erase functions */ - static void erase_channel(guild &guild, dpp::snowflake channel_id); - void erase_guild(dpp::snowflake guild_id); void erase_translatebot_webhook(dpp::snowflake webhook_id); /* get functions */ uint16_t avatar_size(); - static channel* get_channel(guild &guild, dpp::snowflake channel_id); + static channel* get_channel(guild *guild, dpp::snowflake channel_id); channel* get_channel(dpp::snowflake guild_id, dpp::snowflake channel_id); guild* get_guild(dpp::snowflake guild_id); target* get_target(dpp::snowflake guild_id, dpp::snowflake channel_id, const std::string &target); @@ -47,7 +45,7 @@ namespace bot { static const target* get_target(const channel *channel, const std::string &target); const std::vector preferred_languages() const; std::shared_ptr get_database() const; - std::shared_ptr get_translator() const; + std::unique_ptr get_translator() const; const std::string token() const; /* is functions */ @@ -61,19 +59,14 @@ namespace bot { bool parse(const std::string &data, bool initialize = true); bool parse_file(const std::string &filename, bool initialize = true); - /* prevent copies */ - settings() = default; - settings(const settings&) = delete; - settings& operator=(const settings&) = delete; - private: mutable std::recursive_mutex m_mutex; - size_t m_externallyLockedCount = 0; - uint16_t m_avatarSize = 256; + size_t m_externallyLockedCount; + uint16_t m_avatarSize; std::shared_ptr m_database; std::vector m_guilds; std::vector m_prefLangs; - std::shared_ptr m_translator; + bot::settings::translator m_translator; std::string m_token; std::vector m_webhookIds; }; diff --git a/src/core/settings_types.h b/src/settings_types.h similarity index 98% rename from src/core/settings_types.h rename to src/settings_types.h index 96d9017..e1c5b3c 100644 --- a/src/core/settings_types.h +++ b/src/settings_types.h @@ -41,7 +41,6 @@ namespace bot { std::vector channel; }; struct translator { - std::string type; std::string hostname; uint16_t port; std::string url; diff --git a/src/core/slashcommands.cpp b/src/slashcommands.cpp similarity index 70% rename from src/core/slashcommands.cpp rename to src/slashcommands.cpp index a55614c..2dede96 100644 --- a/src/core/slashcommands.cpp +++ b/src/slashcommands.cpp @@ -18,20 +18,19 @@ #include #include "slashcommands.h" -using bot::slashcommands; using namespace std::string_literals; -void slashcommands::process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) +void bot::slashcommands::process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) { if (event.command.get_command_name() == "edit") - slashcommands::process_edit_command(bot, settings, event); + bot::slashcommands::process_edit_command(bot, settings, event); else if (event.command.get_command_name() == "list") - slashcommands::process_list_command(bot, settings, event); + bot::slashcommands::process_list_command(bot, settings, event); else if (event.command.get_command_name() == "translate" || event.command.get_command_name() == "translate_pref") - slashcommands::process_translate_command(bot, settings, event); + bot::slashcommands::process_translate_command(bot, settings, event); } -void slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) +void bot::slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) { try { dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id); @@ -41,83 +40,64 @@ void slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::setti dpp::command_interaction interaction = event.command.get_command_interaction(); if (interaction.options[0].name == "delete") { const std::lock_guard guard(*settings); - if (bot::settings::guild *guild = settings->get_guild(event.command.guild_id)) { - if (bot::settings::channel *channel = settings->get_channel(*guild, event.command.channel_id)) { - const std::string target = std::get(event.get_parameter("target")); + if (bot::settings::channel *channel = settings->get_channel(event.command.guild_id, event.command.channel_id)) { + const std::string target = std::get(event.get_parameter("target")); - auto database = settings->get_database(); - const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id); + std::shared_ptr database = settings->get_database(); + const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id); - if (db_channel.targets.empty()) { - event.reply(dpp::message("The current channel has no deleteable targets!").set_flags(dpp::m_ephemeral)); + if (db_channel.targets.empty()) { + event.reply(dpp::message("The current channel has no deleteable targets!").set_flags(dpp::m_ephemeral)); + } + else if (target == "**") { + std::vector targets; + for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) { + targets.push_back(db_target->target); } - else if (target == "**") { - std::vector targets; - for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) { - targets.push_back(db_target->target); + for (auto target = channel->targets.begin(); target != channel->targets.end();) { + if (std::find(targets.begin(), targets.end(), target->target) != targets.end()) { + bot->delete_webhook(target->webhook.id, std::bind(&bot::slashcommands::process_deleted_webhook, settings, target->webhook.id, std::placeholders::_1)); + target = channel->targets.erase(target); } - for (auto target = channel->targets.begin(); target != channel->targets.end();) { - if (std::find(targets.begin(), targets.end(), target->target) != targets.end()) { - bot->delete_webhook(target->webhook.id, std::bind(&slashcommands::process_deleted_webhook, settings, target->webhook.id, std::placeholders::_1)); - target = channel->targets.erase(target); - } - else { - target++; - } + else { + target++; } - - database->delete_channel(event.command.guild_id, event.command.channel_id); - database->sync(); - - if (channel->targets.empty()) { - settings->erase_channel(*guild, event.command.channel_id); - if (guild->channel.empty()) { - settings->erase_guild(event.command.guild_id); - } - } - - event.reply(dpp::message("Deleteable targets have being deleted!").set_flags(dpp::m_ephemeral)); } - else { - bool target_found = false; - for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) { - if (db_target->target == target) { - target_found = true; + + database->delete_channel(event.command.guild_id, event.command.channel_id); + database->sync(); + + event.reply(dpp::message("Deleteable targets have being deleted!").set_flags(dpp::m_ephemeral)); + } + else { + bool target_found = false; + for (auto db_target = db_channel.targets.begin(); db_target != db_channel.targets.end(); db_target++) { + if (db_target->target == target) { + target_found = true; + break; + } + } + + if (target_found) { + for (auto _target = channel->targets.begin(); _target != channel->targets.end(); _target++) { + if (_target->target == target) { + bot->delete_webhook(_target->webhook.id, std::bind(&bot::slashcommands::process_deleted_webhook, settings, _target->webhook.id, std::placeholders::_1)); + channel->targets.erase(_target); break; } } - if (target_found) { - for (auto _target = channel->targets.begin(); _target != channel->targets.end(); _target++) { - if (_target->target == target) { - bot->delete_webhook(_target->webhook.id, std::bind(&slashcommands::process_deleted_webhook, settings, _target->webhook.id, std::placeholders::_1)); - channel->targets.erase(_target); - break; - } - } + if (db_channel.targets.size() == 1) + database->delete_channel(event.command.guild_id, event.command.channel_id); + else + database->delete_channel_target(event.command.guild_id, event.command.channel_id, target); + database->sync(); - if (db_channel.targets.size() == 1) - database->delete_channel(event.command.guild_id, event.command.channel_id); - else - database->delete_channel_target(event.command.guild_id, event.command.channel_id, target); - database->sync(); - - if (channel->targets.empty()) { - settings->erase_channel(*guild, event.command.channel_id); - if (guild->channel.empty()) { - settings->erase_guild(event.command.guild_id); - } - } - - event.reply(dpp::message("Target have being deleted!").set_flags(dpp::m_ephemeral)); - } - else { - event.reply(dpp::message("Target language is not being found or deleteable!").set_flags(dpp::m_ephemeral)); - } + event.reply(dpp::message("Target have being deleted!").set_flags(dpp::m_ephemeral)); + } + else { + event.reply(dpp::message("Target language is not being found or deleteable!").set_flags(dpp::m_ephemeral)); } - } - else { - event.reply(dpp::message("The current channel is not being translated!").set_flags(dpp::m_ephemeral)); } } else { @@ -137,13 +117,13 @@ void slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::setti source_valid = true; break; } - language_codes << ' ' << language.code; + language_codes << " " << language.code; } if (source_valid) { channel->source = source; - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); database->set_channel_source(event.command.guild_id, event.command.channel_id, source); database->sync(); @@ -167,7 +147,7 @@ void slashcommands::process_edit_command(dpp::cluster *bot, bot::settings::setti } } -void slashcommands::process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback) +void bot::slashcommands::process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback) { if (callback.is_error()) { std::cerr << "[Error] Failed to delete Webhook " << webhook_id << std::endl; @@ -176,7 +156,7 @@ void slashcommands::process_deleted_webhook(bot::settings::settings *settings, d settings->erase_translatebot_webhook(webhook_id); } -void slashcommands::process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) +void bot::slashcommands::process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) { try { dpp::command_interaction interaction = event.command.get_command_interaction(); @@ -191,7 +171,7 @@ void slashcommands::process_list_command(dpp::cluster *bot, bot::settings::setti // We want give more information to users who can Manage Webhooks dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id); if (user_permissions.has(dpp::p_manage_webhooks)) { - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); const bot::settings::channel db_channel = database->get_channel(event.command.guild_id, event.command.channel_id); for (auto target = channel->targets.begin(); target != channel->targets.end(); target++) { @@ -237,44 +217,17 @@ void slashcommands::process_list_command(dpp::cluster *bot, bot::settings::setti event.reply(dpp::message("The current guild have no translated channel!").set_flags(dpp::m_ephemeral)); } } - else if (interaction.options[0].name == "languages") { - dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id); - if (user_permissions.has(dpp::p_manage_webhooks)) { - const std::vector languages = settings->get_translator()->get_languages(); - std::ostringstream reply_languages; - reply_languages << "**Available Languages**\n"; - for (auto language = languages.begin(); language != languages.end();) { - reply_languages << language->name << ": " << language->code; - if (++language != languages.end()) - reply_languages << '\n'; - } - if (reply_languages.str().length() <= 2000) { - event.reply(dpp::message(reply_languages.str()).set_flags(dpp::m_ephemeral)); - } - else { - reply_languages.str({}); - reply_languages << "Available Languages:"; - for (auto language = languages.begin(); language != languages.end(); language++) { - reply_languages << ' ' << language->code; - } - event.reply(dpp::message(reply_languages.str()).set_flags(dpp::m_ephemeral)); - } - } - else { - event.reply(dpp::message("Unauthorized to list available languages!").set_flags(dpp::m_ephemeral)); - } - } else { throw std::invalid_argument("Option " + interaction.options[0].name + " is not known"); } } - catch (const std::exception &exception) { + catch (const std::exception& exception) { std::cerr << "[Exception] " << exception.what() << std::endl; event.reply(dpp::message("Exception while processing command:\n"s + exception.what()).set_flags(dpp::m_ephemeral)); } } -void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) +void bot::slashcommands::process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event) { try { dpp::permission user_permissions = event.command.get_resolved_permission(event.command.usr.id); @@ -288,13 +241,13 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: dpp::command_interaction interaction = event.command.get_command_interaction(); if (interaction.options[0].name == "channel") { v_target = event.command.get_resolved_channel( - std::get(event.get_parameter("channel"))); + std::get(event.get_parameter("channel"))); } else if (interaction.options[0].name == "webhook") { v_target = dpp::webhook(std::get(event.get_parameter("webhook"))); } - const auto languages = settings->get_translator()->get_languages(); + const std::vector languages = settings->get_translator()->get_languages(); std::ostringstream language_codes; bool source_valid = false, target_valid = false; @@ -305,7 +258,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: target_valid = true; if (source_valid && target_valid) break; - language_codes << ' ' << language.code; + language_codes << " " << language.code; } if (source_valid && target_valid) { @@ -318,7 +271,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: webhook.guild_id = channel->guild_id; webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">"; - bot->create_webhook(webhook, std::bind(&slashcommands::process_translate_webhook_new_channel, settings, event, source, target, std::placeholders::_1)); + bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_new_channel, settings, event, source, target, std::placeholders::_1)); } else if (dpp::webhook *webhook = std::get_if(&v_target)) { const bot::settings::target s_target = { target, *webhook }; @@ -327,7 +280,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: settings->add_channel(s_channel, event.command.guild_id); settings->add_translatebot_webhook(webhook->id); - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); database->set_channel_source(event.command.guild_id, event.command.channel_id, source); database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target); database->sync(); @@ -345,7 +298,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: webhook.guild_id = channel->guild_id; webhook.name = "Translate Bot Webhook <" + std::to_string(event.command.channel_id) + ":" + source + ":" + target + ">"; - bot->create_webhook(webhook, std::bind(&slashcommands::process_translate_webhook_add_target, settings, event, target, std::placeholders::_1)); + bot->create_webhook(webhook, std::bind(&bot::slashcommands::process_translate_webhook_add_target, settings, event, target, std::placeholders::_1)); } else if (dpp::webhook *webhook = std::get_if(&v_target)) { const bot::settings::target s_target = { target, *webhook }; @@ -353,7 +306,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: settings->add_target(s_target, event.command.guild_id, event.command.channel_id); settings->add_translatebot_webhook(webhook->id); - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target); database->sync(); @@ -380,7 +333,7 @@ void slashcommands::process_translate_command(dpp::cluster *bot, bot::settings:: } } -void slashcommands::process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback) +void bot::slashcommands::process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback) { if (callback.is_error()) { event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral)); @@ -394,14 +347,14 @@ void slashcommands::process_translate_webhook_add_target(bot::settings::settings settings->add_target(s_target, event.command.guild_id, event.command.channel_id); settings->add_translatebot_webhook(webhook.id); - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target); database->sync(); event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral)); } -void slashcommands::process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback) +void bot::slashcommands::process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback) { if (callback.is_error()) { event.reply(dpp::message("Failed to generate webhook!").set_flags(dpp::m_ephemeral)); @@ -416,7 +369,7 @@ void slashcommands::process_translate_webhook_new_channel(bot::settings::setting settings->add_channel(s_channel, event.command.guild_id); settings->add_translatebot_webhook(webhook.id); - auto database = settings->get_database(); + std::shared_ptr database = settings->get_database(); database->set_channel_source(event.command.guild_id, event.command.channel_id, source); database->add_channel_target(event.command.guild_id, event.command.channel_id, s_target); database->sync(); @@ -424,7 +377,7 @@ void slashcommands::process_translate_webhook_new_channel(bot::settings::setting event.reply(dpp::message("Channel will be now translated!").set_flags(dpp::m_ephemeral)); } -void slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings *settings) +void bot::slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings *settings) { settings->lock(); const std::vector languages = settings->get_translator()->get_languages(); @@ -434,9 +387,9 @@ void slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings std::vector commands; dpp::command_option source_option(dpp::co_string, "source", "Source language (ISO 639-1)", true); - source_option.set_max_length(static_cast(5)).set_min_length(static_cast(2)); + source_option.set_max_length(static_cast(2)).set_min_length(static_cast(2)); dpp::command_option target_option(dpp::co_string, "target", "Target language (ISO 639-1)", true); - target_option.set_max_length(static_cast(5)).set_min_length(static_cast(2)); + target_option.set_max_length(static_cast(2)).set_min_length(static_cast(2)); dpp::slashcommand command_edit("edit", "Edit current channel settings", bot->me.id); command_edit.set_default_permissions(dpp::p_manage_webhooks); @@ -451,10 +404,8 @@ void slashcommands::register_commands(dpp::cluster *bot, bot::settings::settings dpp::slashcommand command_list("list", "List translation settings", bot->me.id); dpp::command_option channel_list_subcommand(dpp::co_sub_command, "channel", "List current channel translation settings"); dpp::command_option guild_list_subcommand(dpp::co_sub_command, "guild", "List current guild translation settings"); - dpp::command_option languages_list_subcommand(dpp::co_sub_command, "languages", "List available languages to translate"); command_list.add_option(channel_list_subcommand); command_list.add_option(guild_list_subcommand); - command_list.add_option(languages_list_subcommand); commands.push_back(command_list); dpp::slashcommand command_translate("translate", "Translate current channel", bot->me.id); diff --git a/src/core/slashcommands.h b/src/slashcommands.h similarity index 73% rename from src/core/slashcommands.h rename to src/slashcommands.h index a31d37f..abcb0be 100644 --- a/src/core/slashcommands.h +++ b/src/slashcommands.h @@ -23,20 +23,16 @@ #include "settings.h" namespace bot { - class slashcommands { - public: - slashcommands() = delete; - static void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); - static void register_commands(dpp::cluster *bot, bot::settings::settings *settings); - - private: - static void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); - static void process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback); - static void process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); - static void process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); - static void process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback); - static void process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback); - }; + namespace slashcommands { + extern void process_command_event(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); + extern void process_edit_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); + extern void process_deleted_webhook(bot::settings::settings *settings, dpp::snowflake webhook_id, const dpp::confirmation_callback_t &callback); + extern void process_list_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); + extern void process_translate_command(dpp::cluster *bot, bot::settings::settings *settings, const dpp::slashcommand_t &event); + extern void process_translate_webhook_add_target(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &target, const dpp::confirmation_callback_t &callback); + extern void process_translate_webhook_new_channel(bot::settings::settings *settings, const dpp::slashcommand_t &event, const std::string &source, const std::string &target, const dpp::confirmation_callback_t &callback); + extern void register_commands(dpp::cluster *bot, bot::settings::settings *settings); + } } #endif // SLASHCOMMANDS_H diff --git a/src/core/submit_queue.cpp b/src/submit_queue.cpp similarity index 98% rename from src/core/submit_queue.cpp rename to src/submit_queue.cpp index 12ce874..e752fab 100644 --- a/src/core/submit_queue.cpp +++ b/src/submit_queue.cpp @@ -19,7 +19,7 @@ #include #include "submit_queue.h" #include "webhook_push.h" -using bot::submit_queue; +using namespace bot; using namespace std::chrono_literals; void submit_queue::add(const translated_message &message) diff --git a/src/core/submit_queue.h b/src/submit_queue.h similarity index 100% rename from src/core/submit_queue.h rename to src/submit_queue.h diff --git a/src/systemd/dtranslatebot.service.in b/src/systemd/dtranslatebot.service.in deleted file mode 100644 index 6c2e0c9..0000000 --- a/src/systemd/dtranslatebot.service.in +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Discord Translation Bot -After=network.target - -[Service] -User=dtranslatebot -Group=dtranslatebot -WorkingDirectory=@dtranslatebot_SERVICE_WORKDIR@ -ExecStart="@CMAKE_INSTALL_FULL_BINDIR@/dtranslatebot" "@CMAKE_INSTALL_FULL_SYSCONFDIR@/dtranslatebot.json" -Restart=on-abnormal - -[Install] -WantedBy=multi-user.target diff --git a/src/systemd/dtranslatebot.sysusersd.in b/src/systemd/dtranslatebot.sysusersd.in deleted file mode 100644 index 144004d..0000000 --- a/src/systemd/dtranslatebot.sysusersd.in +++ /dev/null @@ -1 +0,0 @@ -u dtranslatebot - "Discord Translation Bot" "@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/lib/dtranslatebot" - diff --git a/src/translator/deepl/deepl.cpp b/src/translator/deepl/deepl.cpp deleted file mode 100644 index e81481c..0000000 --- a/src/translator/deepl/deepl.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/***************************************************************************** -* 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. -*****************************************************************************/ - -#include -#include -#include "deepl.h" -using namespace bot::translator; -using namespace std::chrono_literals; -using namespace std::string_literals; - -deepl::deepl(const std::string &hostname, const std::string apiKey) : - m_hostname(hostname), m_apiKey(apiKey) -{ -} - -deepl::~deepl() -{ -} - -const std::vector deepl::get_languages() -{ - if (!m_languages.languages.empty()) { - auto current_time = std::chrono::system_clock::now(); - auto threshold_time = m_languages.query_time + 24h; - if (current_time <= threshold_time) - return m_languages.languages; - } - - try { - dpp::https_client http_request(&m_cluster, m_hostname, 443, "/v2/languages?type=target", "GET", {}, { {"Authorization"s, "DeepL-Auth-Key " + m_apiKey} }, false); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_array()) { - m_languages.languages.clear(); - for (auto json_language = response.begin(); json_language != response.end(); json_language++) { - if (json_language->is_object()) { - language language; - - auto json_lang_code = json_language->find("language"); - if (json_lang_code != json_language->end()) - language.code = *json_lang_code; - - if (language.code.size() > 2) - std::transform(language.code.begin(), language.code.begin() + 2, language.code.begin(), ::tolower); - else - std::transform(language.code.begin(), language.code.end(), language.code.begin(), ::tolower); - - auto json_lang_name = json_language->find("name"); - if (json_lang_name != json_language->end()) - language.name = *json_lang_name; - - if (!language.code.empty() && !language.name.empty()) - m_languages.languages.push_back(std::move(language)); - } - } - m_languages.query_time = std::chrono::system_clock::now(); - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return m_languages.languages; -} - -const std::string deepl::translate(const std::string &text, const std::string &source, const std::string &target) -{ - const dpp::http_headers http_headers = { - {"Authorization"s, "DeepL-Auth-Key " + m_apiKey}, - {"Content-Type"s, "application/json"s} - }; - - dpp::json json_body = { - {"text"s, { text } }, - {"source_lang"s, source}, - {"target_lang"s, target}, - }; - - try { - dpp::https_client http_request(&m_cluster, m_hostname, 443, "/v2/translate", "POST", json_body.dump(), http_headers, false); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_object()) { - auto translations = response.find("translations"); - if (translations != response.end() && translations->is_array()) { - for (auto translation = translations->begin(); translation != translations->end(); translation++) { - auto tr_text = translation->find("text"); - if (tr_text != translation->end()) - return *tr_text; - } - } - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return text; -} diff --git a/src/translator/deepl/deepl.h b/src/translator/deepl/deepl.h deleted file mode 100644 index b4e0d0d..0000000 --- a/src/translator/deepl/deepl.h +++ /dev/null @@ -1,43 +0,0 @@ -/***************************************************************************** -* 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 TRANSLATOR_DEEPL_H -#define TRANSLATOR_DEEPL_H - -#include -#include "../../core/translator.h" - -namespace bot { - namespace translator { - class deepl : public translator { - public: - explicit deepl(const std::string &hostname, const std::string apiKey = {}); - ~deepl() override; - const std::vector get_languages() override; - const std::string translate(const std::string &text, const std::string &source, const std::string &target) override; - - private: - dpp::cluster m_cluster; - std::string m_apiKey; - std::string m_hostname; - supported_languages m_languages; - }; - } -} - -#endif // TRANSLATOR_DEEPL_H diff --git a/src/translator/lingvatranslate/lingvatranslate.cpp b/src/translator/lingvatranslate/lingvatranslate.cpp deleted file mode 100644 index b8352e5..0000000 --- a/src/translator/lingvatranslate/lingvatranslate.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/***************************************************************************** -* 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. -*****************************************************************************/ - -#include -#include -#include -#include "lingvatranslate.h" -using namespace bot::translator; -using namespace std::chrono_literals; -using namespace std::string_literals; - -lingvatranslate::lingvatranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls) : - m_hostname(hostname), m_port(port), m_url(url), m_tls(tls) -{ -} - -lingvatranslate::~lingvatranslate() -{ -} - -const std::vector lingvatranslate::get_languages() -{ - if (!m_languages.languages.empty()) { - auto current_time = std::chrono::system_clock::now(); - auto threshold_time = m_languages.query_time + 24h; - if (current_time <= threshold_time) - return m_languages.languages; - } - - try { - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/v1/languages/target", "GET", {}, {}, !m_tls); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_object()) { - auto languages = response.find("languages"); - if (languages != response.end()) { - m_languages.languages.clear(); - for (auto json_language = languages->begin(); json_language != languages->end(); json_language++) { - if (json_language->is_object()) { - language language; - - auto json_lang_code = json_language->find("code"); - if (json_lang_code != json_language->end()) - language.code = *json_lang_code; - - auto json_lang_name = json_language->find("name"); - if (json_lang_name != json_language->end()) - language.name = *json_lang_name; - - if (!language.code.empty() && !language.name.empty()) - m_languages.languages.push_back(std::move(language)); - } - } - m_languages.query_time = std::chrono::system_clock::now(); - } - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return m_languages.languages; -} - -const std::string lingvatranslate::translate(const std::string &text, const std::string &source, const std::string &target) -{ - try { - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/v1/" + source + "/" + target + "/" + dpp::utility::url_encode(text), "GET", {}, {}, !m_tls); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_object()) { - auto tr_text = response.find("translation"); - if (tr_text != response.end()) - return *tr_text; - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return text; -} diff --git a/src/translator/lingvatranslate/lingvatranslate.h b/src/translator/lingvatranslate/lingvatranslate.h deleted file mode 100644 index 805dd9b..0000000 --- a/src/translator/lingvatranslate/lingvatranslate.h +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************** -* 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 TRANSLATOR_LINGVATRANSLATE_H -#define TRANSLATOR_LINGVATRANSLATE_H - -#include -#include -#include "../../core/translator.h" - -namespace bot { - namespace translator { - class lingvatranslate : public translator { - - public: - explicit lingvatranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls); - ~lingvatranslate() override; - const std::vector get_languages() override; - const std::string translate(const std::string &text, const std::string &source, const std::string &target) override; - - private: - dpp::cluster m_cluster; - std::string m_hostname; - supported_languages m_languages; - uint16_t m_port; - std::string m_url; - bool m_tls; - }; - } -} - -#endif // TRANSLATOR_LINGVATRANSLATE_H diff --git a/src/translator/mozhi/mozhi.cpp b/src/translator/mozhi/mozhi.cpp deleted file mode 100644 index e5e8ea1..0000000 --- a/src/translator/mozhi/mozhi.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/***************************************************************************** -* 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. -*****************************************************************************/ - -#include -#include -#include -#include "mozhi.h" -using namespace bot::translator; -using namespace std::chrono_literals; -using namespace std::string_literals; - -mozhi::mozhi(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string &engine) : - m_hostname(hostname), m_port(port), m_url(url), m_tls(tls), m_engine(engine) -{ -} - -mozhi::~mozhi() -{ -} - -const std::vector mozhi::get_languages() -{ - if (!m_languages.languages.empty()) { - auto current_time = std::chrono::system_clock::now(); - auto threshold_time = m_languages.query_time + 24h; - if (current_time <= threshold_time) - return m_languages.languages; - } - - try { - const std::string parameters = dpp::utility::make_url_parameters({ - {"engine"s, m_engine} - }); - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/target_languages" + parameters, "GET", {}, {}, !m_tls); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_array()) { - m_languages.languages.clear(); - for (auto json_language = response.begin(); json_language != response.end(); json_language++) { - if (json_language->is_object()) { - language language; - - auto json_lang_code = json_language->find("Id"); - if (json_lang_code != json_language->end()) - language.code = *json_lang_code; - - auto json_lang_name = json_language->find("Name"); - if (json_lang_name != json_language->end()) - language.name = *json_lang_name; - - if (!language.code.empty() && !language.name.empty()) - m_languages.languages.push_back(std::move(language)); - } - } - m_languages.query_time = std::chrono::system_clock::now(); - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return m_languages.languages; -} - -const std::string mozhi::translate(const std::string &text, const std::string &source, const std::string &target) -{ - try { - const std::string parameters = dpp::utility::make_url_parameters({ - {"engine"s, m_engine}, - {"from"s, source}, - {"to"s, target}, - {"text"s, text}, - }); - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "api/translate" + parameters, "GET", {}, {}, !m_tls); - if (http_request.get_status() == 200) { - const dpp::json response = dpp::json::parse(http_request.get_content()); - if (response.is_object()) { - auto tr_text = response.find("translated-text"); - if (tr_text != response.end()) - return *tr_text; - } - } - } - catch (const std::exception &exception) { - std::cerr << "[Exception] " << exception.what() << std::endl; - } - - return text; -} diff --git a/src/translator/mozhi/mozhi.h b/src/translator/mozhi/mozhi.h deleted file mode 100644 index 8a8735a..0000000 --- a/src/translator/mozhi/mozhi.h +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************** -* 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 TRANSLATOR_MOZHI_H -#define TRANSLATOR_MOZHI_H - -#include -#include -#include "../../core/translator.h" - -namespace bot { - namespace translator { - class mozhi : public translator { - - public: - explicit mozhi(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string &engine); - ~mozhi() override; - const std::vector get_languages() override; - const std::string translate(const std::string &text, const std::string &source, const std::string &target) override; - - private: - dpp::cluster m_cluster; - std::string m_engine; - std::string m_hostname; - supported_languages m_languages; - uint16_t m_port; - std::string m_url; - bool m_tls; - }; - } -} - -#endif // TRANSLATOR_MOZHI_H diff --git a/src/translator/stub/stub.cpp b/src/translator/stub/stub.cpp deleted file mode 100644 index 7e7a083..0000000 --- a/src/translator/stub/stub.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/***************************************************************************** -* 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. -*****************************************************************************/ - -#include "stub.h" -using namespace bot::translator; -using namespace std::string_literals; - -stub::stub() -{ -} - -stub::~stub() -{ -} - -const std::vector stub::get_languages() -{ - return { {"a*", "Any Language"} }; -} - -const std::string stub::translate(const std::string &text, [[maybe_unused]] const std::string &source, [[maybe_unused]] const std::string &target) -{ - return text; -} diff --git a/src/translator/stub/stub.h b/src/translator/stub/stub.h deleted file mode 100644 index c6c73e4..0000000 --- a/src/translator/stub/stub.h +++ /dev/null @@ -1,36 +0,0 @@ -/***************************************************************************** -* 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 TRANSLATOR_STUB_H -#define TRANSLATOR_STUB_H - -#include "../../core/translator.h" - -namespace bot { - namespace translator { - class stub : public translator { - public: - explicit stub(); - ~stub() override; - const std::vector get_languages() override; - const std::string translate(const std::string &text, const std::string &source, const std::string &target) override; - }; - } -} - -#endif // TRANSLATOR_STUB_H diff --git a/src/core/translator.cpp b/src/translator_core.cpp similarity index 94% rename from src/core/translator.cpp rename to src/translator_core.cpp index 993e198..d32d544 100644 --- a/src/core/translator.cpp +++ b/src/translator_core.cpp @@ -19,9 +19,17 @@ #ifndef NDEBUG #include #endif -#include "translator.h" +#include "translator_core.h" using namespace bot::translator; +translator::translator() +{ +} + +translator::~translator() +{ +} + const std::vector translator::get_languages() { #ifndef NDEBUG diff --git a/src/core/translator.h b/src/translator_core.h similarity index 74% rename from src/core/translator.h rename to src/translator_core.h index 91502d9..33fbf0e 100644 --- a/src/core/translator.h +++ b/src/translator_core.h @@ -16,10 +16,9 @@ * responsible for anything with use of the software, you are self responsible. *****************************************************************************/ -#ifndef TRANSLATOR_H -#define TRANSLATOR_H +#ifndef TRANSLATOR_CORE_H +#define TRANSLATOR_CORE_H -#include #include #include @@ -30,21 +29,14 @@ namespace bot { std::string name; }; - struct supported_languages { - std::vector languages; - std::chrono::system_clock::time_point query_time; - }; - class translator { public: - explicit translator() = default; - virtual ~translator() = default; - translator(const translator&) = delete; - translator& operator=(const translator&) = delete; + explicit translator(); + virtual ~translator(); virtual const std::vector get_languages(); virtual const std::string translate(const std::string &text, const std::string &source, const std::string &target); }; } } -#endif // TRANSLATOR_H +#endif // TRANSLATOR_CORE_H diff --git a/src/translator/libretranslate/libretranslate.cpp b/src/translator_libretranslate.cpp similarity index 69% rename from src/translator/libretranslate/libretranslate.cpp rename to src/translator_libretranslate.cpp index 3d82a89..78a0026 100644 --- a/src/translator/libretranslate/libretranslate.cpp +++ b/src/translator_libretranslate.cpp @@ -18,9 +18,8 @@ #include #include -#include "libretranslate.h" +#include "translator_libretranslate.h" using namespace bot::translator; -using namespace std::chrono_literals; using namespace std::string_literals; libretranslate::libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey) : @@ -34,36 +33,29 @@ libretranslate::~libretranslate() const std::vector libretranslate::get_languages() { - if (!m_languages.languages.empty()) { - auto current_time = std::chrono::system_clock::now(); - auto threshold_time = m_languages.query_time + 24h; - if (current_time <= threshold_time) - return m_languages.languages; - } + std::vector languages; try { - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "languages", "GET", {}, {}, !m_tls); + dpp::https_client http_request(m_hostname, m_port, m_url + "languages", "GET", {}, {}, !m_tls); if (http_request.get_status() == 200) { const dpp::json response = dpp::json::parse(http_request.get_content()); if (response.is_array()) { - m_languages.languages.clear(); - for (auto json_language = response.begin(); json_language != response.end(); json_language++) { - if (json_language->is_object()) { + for (const auto &json_language : response) { + if (json_language.is_object()) { language language; - auto json_lang_code = json_language->find("code"); - if (json_lang_code != json_language->end()) + auto json_lang_code = json_language.find("code"); + if (json_lang_code != json_language.end()) language.code = *json_lang_code; - auto json_lang_name = json_language->find("name"); - if (json_lang_name != json_language->end()) + auto json_lang_name = json_language.find("name"); + if (json_lang_name != json_language.end()) language.name = *json_lang_name; if (!language.code.empty() && !language.name.empty()) - m_languages.languages.push_back(std::move(language)); + languages.push_back(std::move(language)); } } - m_languages.query_time = std::chrono::system_clock::now(); } } } @@ -71,7 +63,7 @@ const std::vector libretranslate::get_languages() std::cerr << "[Exception] " << exception.what() << std::endl; } - return m_languages.languages; + return languages; } const std::string libretranslate::translate(const std::string &text, const std::string &source, const std::string &target) @@ -91,7 +83,7 @@ const std::string libretranslate::translate(const std::string &text, const std:: json_body["apiKey"] = m_apiKey; try { - dpp::https_client http_request(&m_cluster, m_hostname, m_port, m_url + "translate", "POST", json_body.dump(), http_headers, !m_tls); + dpp::https_client http_request(m_hostname, m_port, m_url + "translate", "POST", json_body.dump(), http_headers, !m_tls); if (http_request.get_status() == 200) { const dpp::json response = dpp::json::parse(http_request.get_content()); if (response.is_object()) { diff --git a/src/translator/libretranslate/libretranslate.h b/src/translator_libretranslate.h similarity index 92% rename from src/translator/libretranslate/libretranslate.h rename to src/translator_libretranslate.h index 75306a8..eaa287d 100644 --- a/src/translator/libretranslate/libretranslate.h +++ b/src/translator_libretranslate.h @@ -20,13 +20,12 @@ #define TRANSLATOR_LIBRETRANSLATE_H #include -#include -#include "../../core/translator.h" +#include +#include "translator_core.h" namespace bot { namespace translator { class libretranslate : public translator { - public: explicit libretranslate(const std::string &hostname, uint16_t port, const std::string &url, bool tls, const std::string apiKey = {}); ~libretranslate() override; @@ -34,10 +33,8 @@ namespace bot { const std::string translate(const std::string &text, const std::string &source, const std::string &target) override; private: - dpp::cluster m_cluster; std::string m_apiKey; std::string m_hostname; - supported_languages m_languages; uint16_t m_port; std::string m_url; bool m_tls; diff --git a/src/core/webhook_push.cpp b/src/webhook_push.cpp similarity index 83% rename from src/core/webhook_push.cpp rename to src/webhook_push.cpp index 457ec3e..1e4a0f7 100644 --- a/src/core/webhook_push.cpp +++ b/src/webhook_push.cpp @@ -25,12 +25,10 @@ using namespace std::string_view_literals; void bot::webhook_push::run(const bot::translated_message &message, dpp::cluster *bot) { dpp::json json_body = { - {"username"s, message.author} + {"username"s, message.author}, + {"avatar_url"s, message.avatar} }; - if (!message.avatar.empty()) - json_body["avatar_url"] = message.avatar; - // We will split too long messages into multiple messages if (message.message.length() > 2000) { std::string_view message_v = message.message; @@ -75,18 +73,14 @@ void bot::webhook_push::run(const bot::translated_message &message, dpp::cluster } } -void webhook_request_completed(std::promise &promise, dpp::json &json, const dpp::http_request_completion_t &event) -{ - if (event.status != 204) - std::cerr << "[Warning] Webhook push returned unexpected code " << event.status << std::endl; - promise.set_value(event); -} - void bot::webhook_push::push_request(dpp::snowflake webhook_id, const std::string &webhook_token, const std::string &json, dpp::cluster *bot) { - std::promise promise; - std::future future = promise.get_future(); - bot->post_rest(API_PATH "/webhooks", std::to_string(webhook_id), dpp::utility::url_encode(webhook_token), dpp::m_post, json, - std::bind(&webhook_request_completed, std::ref(promise), std::placeholders::_1, std::placeholders::_2)); - future.wait(); + std::promise _p; + std::future _f = _p.get_future(); + bot->post_rest(API_PATH "/webhooks", std::to_string(webhook_id), dpp::utility::url_encode(webhook_token), dpp::m_post, json, [&bot, &_p](dpp::json &json, const dpp::http_request_completion_t &event) { + if (event.status != 204) + std::cerr << "[Warning] Webhook push returned unexpected code " << event.status << std::endl; + _p.set_value(event); + }); + _f.wait(); } diff --git a/src/core/webhook_push.h b/src/webhook_push.h similarity index 97% rename from src/core/webhook_push.h rename to src/webhook_push.h index d4b03f9..643b20d 100644 --- a/src/core/webhook_push.h +++ b/src/webhook_push.h @@ -26,7 +26,6 @@ namespace bot { class webhook_push { public: - webhook_push() = delete; static void run(const bot::translated_message &message, dpp::cluster *bot); private: