From 200211ef17c9433a620092bb74d732347c8b4358 Mon Sep 17 00:00:00 2001 From: Soo Hwan Na Date: Mon, 3 Jun 2024 19:28:35 +0900 Subject: [PATCH] TgBot++: socket: Refactor code 2 - Namespace generalizations - Two-step upload with dry procedure --- CMakeLists.txt | 6 +- src/SpamBlocker.cpp | 10 +- src/database/utils/SendMediaToChat.cc | 11 +- src/include/SpamBlock.h | 2 +- src/socket/TgBotCommandMap.cpp | 56 +-- src/socket/TgBotSocket.h | 60 ++-- src/socket/TgBotSocketClient.cpp | 208 ++++++----- src/socket/include/TgBotCommandExport.hpp | 156 ++++---- src/socket/interface/SocketBase.cpp | 1 - src/socket/interface/SocketBase.hpp | 8 +- src/socket/interface/impl/SocketPosix.cpp | 4 +- src/socket/interface/impl/SocketPosix.hpp | 5 +- src/socket/interface/impl/SocketWindows.cpp | 2 +- src/socket/interface/impl/SocketWindows.hpp | 2 +- .../interface/impl/bot/SocketDataHandler.cpp | 153 +++++--- .../interface/impl/bot/TgBotPacketParser.cpp | 25 +- .../interface/impl/bot/TgBotPacketParser.hpp | 6 +- .../impl/bot/TgBotSocketFileHelper.cpp | 69 ---- .../impl/bot/TgBotSocketFileHelper.hpp | 336 ++++++++++++++++-- .../impl/bot/TgBotSocketInterface.hpp | 9 +- .../interface/impl/helper/SocketHelper.cpp | 5 + .../interface/impl/local/SocketPosixLocal.cpp | 6 +- .../impl/local/SocketWindowsLocal.cpp | 6 +- src/socket/selector/SelectorPosix.hpp | 2 + 24 files changed, 735 insertions(+), 413 deletions(-) delete mode 100644 src/socket/interface/impl/bot/TgBotSocketFileHelper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 331a1782..9d2513e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,8 +278,7 @@ if (USE_UNIX_SOCKETS) extend_set(SRC_LIST src/ChatObserver.cpp ${SOCKET_SRC_INTERFACE}/impl/bot/SocketDataHandler.cpp - ${SOCKET_SRC_INTERFACE}/impl/bot/TgBotSocketInterface.cpp - ${SOCKET_SRC_INTERFACE}/impl/bot/TgBotSocketFileHelper.cpp) + ${SOCKET_SRC_INTERFACE}/impl/bot/TgBotSocketInterface.cpp) if (UNIX) set(SOCKET_SRC_LIST ${SOCKET_SRC_INTERFACE}/impl/SocketPosix.cpp @@ -333,8 +332,7 @@ if (USE_UNIX_SOCKETS) endif() target_link_libraries(TgBotSocket TgBotUtils) add_executable(${SOCKET_CLI_NAME} - src/socket/TgBotSocketClient.cpp - ${SOCKET_SRC_INTERFACE}/impl/bot/TgBotSocketFileHelper.cpp) + src/socket/TgBotSocketClient.cpp) target_link_libraries(${SOCKET_CLI_NAME} TgBotSocket TgBotLogInit) target_link_lib_if_windows(${SOCKET_CLI_NAME} Ws2_32) diff --git a/src/SpamBlocker.cpp b/src/SpamBlocker.cpp index 20968b32..7206817c 100644 --- a/src/SpamBlocker.cpp +++ b/src/SpamBlocker.cpp @@ -16,7 +16,7 @@ using TgBot::ChatPermissions; #ifdef SOCKET_CONNECTION #include -CtrlSpamBlock gSpamBlockCfg = CTRL_ON; +TgBotSocket::data::CtrlSpamBlock gSpamBlockCfg = CtrlSpamBlock::CTRL_ON; #endif template @@ -143,7 +143,7 @@ void SpamBlockBase::addMessage(const Message::Ptr &message) { #ifdef SOCKET_CONNECTION // Global cfg - if (gSpamBlockCfg == CTRL_OFF) { + if (gSpamBlockCfg == CtrlSpamBlock::CTRL_OFF) { return; } #endif @@ -203,14 +203,14 @@ void SpamBlockManager::handleUserAndMessagePair(PerChatHandleConstRef e, bool enforce = false; #ifdef SOCKET_CONNECTION switch (gSpamBlockCfg) { - case CTRL_ENFORCE: + case CtrlSpamBlock::CTRL_ENFORCE: enforce = true; [[fallthrough]]; - case CTRL_ON: { + case CtrlSpamBlock::CTRL_ON: { _deleteAndMuteCommon(it, e, threshold, name, enforce); break; } - case CTRL_LOGGING_ONLY_ON: + case CtrlSpamBlock::CTRL_LOGGING_ONLY_ON: if (isEntryOverThreshold(e, threshold)) _logSpamDetectCommon(e, name); break; diff --git a/src/database/utils/SendMediaToChat.cc b/src/database/utils/SendMediaToChat.cc index 5312ac3d..15aef05a 100644 --- a/src/database/utils/SendMediaToChat.cc +++ b/src/database/utils/SendMediaToChat.cc @@ -8,6 +8,7 @@ #include #include #include +#include "TgBotCommandExport.hpp" [[noreturn]] static void usage(const char* argv0, const int exitCode) { @@ -18,7 +19,7 @@ int main(int argc, char* const* argv) { ChatId chatId = 0; - TgBotCommandData::SendFileToChatId data = {}; + TgBotSocket::data::SendFileToChatId data = {}; const auto _usage = [capture0 = argv[0]](auto&& PH1) { usage(capture0, std::forward(PH1)); }; @@ -43,10 +44,10 @@ int main(int argc, char* const* argv) { LOG(INFO) << "Found, sending (fileid " << info->mediaId << ") to chat " << chatId; } - strncpy(data.filepath, info->mediaId.c_str(), sizeof(data.filepath) - 1); - data.id = chatId; - data.type = TgBotCommandData::TYPE_DOCUMENT; + strncpy(data.filePath.data(), info->mediaId.c_str(), data.filePath.size()); + data.chat = chatId; + data.fileType = TgBotSocket::data::FileType::TYPE_DOCUMENT; - struct TgBotCommandPacket pkt(CMD_SEND_FILE_TO_CHAT_ID, data); + struct TgBotSocket::Packet pkt(TgBotSocket::Command::CMD_SEND_FILE_TO_CHAT_ID, data); getClientBackend()->writeAsClientToSocket(pkt.toSocketData()); } diff --git a/src/include/SpamBlock.h b/src/include/SpamBlock.h index 878b35f2..48ed6a6e 100644 --- a/src/include/SpamBlock.h +++ b/src/include/SpamBlock.h @@ -19,7 +19,7 @@ #include #ifdef SOCKET_CONNECTION -using namespace TgBotCommandData; +using namespace TgBotSocket::data; extern CtrlSpamBlock gSpamBlockCfg; #endif diff --git a/src/socket/TgBotCommandMap.cpp b/src/socket/TgBotCommandMap.cpp index ff4770fd..e47312eb 100644 --- a/src/socket/TgBotCommandMap.cpp +++ b/src/socket/TgBotCommandMap.cpp @@ -4,52 +4,61 @@ #include #include +#include "TgBotCommandExport.hpp" #include "TgBotSocket.h" -#define ARGUMENT_SIZE(enum, len) array_helpers::make_elem(enum, len) +#define ARGUMENT_SIZE(enum, len) array_helpers::make_elem(Command::enum, len) + +#undef ENUM_AND_STR +#define ENUM_AND_STR(e) \ + array_helpers::make_elem(Command::e, #e) + +using namespace TgBotSocket; + +constexpr int MAX_LEN = static_cast(Command::CMD_CLIENT_MAX); constexpr auto kTgBotCommandStrMap = - array_helpers::make( + array_helpers::make( ENUM_AND_STR(CMD_WRITE_MSG_TO_CHAT_ID), ENUM_AND_STR(CMD_CTRL_SPAMBLOCK), ENUM_AND_STR(CMD_OBSERVE_CHAT_ID), ENUM_AND_STR(CMD_SEND_FILE_TO_CHAT_ID), ENUM_AND_STR(CMD_OBSERVE_ALL_CHATS), - ENUM_AND_STR(CMD_DELETE_CONTROLLER_BY_ID), - ENUM_AND_STR(CMD_GET_UPTIME), - ENUM_AND_STR(CMD_UPLOAD_FILE), - ENUM_AND_STR(CMD_DOWNLOAD_FILE)); + ENUM_AND_STR(CMD_DELETE_CONTROLLER_BY_ID), ENUM_AND_STR(CMD_GET_UPTIME), + ENUM_AND_STR(CMD_UPLOAD_FILE), ENUM_AND_STR(CMD_DOWNLOAD_FILE), + ENUM_AND_STR(CMD_UPLOAD_FILE_DRY)); const auto kTgBotCommandArgsCount = - array_helpers::make( + array_helpers::make( ARGUMENT_SIZE(CMD_WRITE_MSG_TO_CHAT_ID, 2), // chatid, msg ARGUMENT_SIZE(CMD_CTRL_SPAMBLOCK, 1), // policy ARGUMENT_SIZE(CMD_OBSERVE_CHAT_ID, 2), // chatid, policy ARGUMENT_SIZE(CMD_SEND_FILE_TO_CHAT_ID, 3), // chatid, type, filepath ARGUMENT_SIZE(CMD_OBSERVE_ALL_CHATS, 1), // policy - ARGUMENT_SIZE(CMD_DELETE_CONTROLLER_BY_ID, 1), // id + ARGUMENT_SIZE(CMD_DELETE_CONTROLLER_BY_ID, 1), // id ARGUMENT_SIZE(CMD_GET_UPTIME, 0), - ARGUMENT_SIZE(CMD_UPLOAD_FILE, 2), // source, dest filepath - ARGUMENT_SIZE(CMD_DOWNLOAD_FILE, 2)); // source, dest filepath + ARGUMENT_SIZE(CMD_UPLOAD_FILE, 2), // source, dest filepath + ARGUMENT_SIZE(CMD_DOWNLOAD_FILE, 2)); // source, dest filepath -namespace TgBotCmd { -std::string toStr(TgBotCommand cmd) { - const auto *const it = array_helpers::find(kTgBotCommandStrMap, cmd); +namespace TgBotSocket::CommandHelpers { + +std::string toStr(Command cmd) { + const auto* const it = array_helpers::find(kTgBotCommandStrMap, cmd); LOG_IF(FATAL, it == kTgBotCommandStrMap.end()) - << "Couldn't find cmd " << cmd << " in map"; + << "Couldn't find cmd " << static_cast(cmd) << " in map"; return it->second; } -int toCount(TgBotCommand cmd) { +int toCount(Command cmd) { const auto* const it = array_helpers::find(kTgBotCommandArgsCount, cmd); LOG_IF(FATAL, it == kTgBotCommandArgsCount.end()) - << "Couldn't find cmd " << cmd << " in map"; + << "Couldn't find cmd " << static_cast(cmd) << " in map"; return it->second; } -bool isClientCommand(TgBotCommand cmd) { return cmd < CMD_CLIENT_MAX; } +bool isClientCommand(Command cmd) { return cmd < Command::CMD_CLIENT_MAX; } -bool isInternalCommand(TgBotCommand cmd) { - return cmd >= CMD_SERVER_INTERNAL_START; +bool isInternalCommand(Command cmd) { + return cmd >= Command::CMD_SERVER_INTERNAL_START; } std::string getHelpText() { @@ -61,10 +70,10 @@ std::string getHelpText() { for (const auto& ent : kTgBotCommandStrMap) { int count = 0; - count = TgBotCmd::toCount(ent.first); + count = toCount(ent.first); - help << ent.second << ": value " << ent.first << ", Requires " - << count << " argument"; + help << ent.second << ": value " << static_cast(ent.first) + << ", Requires " << count << " argument"; if (count > 1) { help << "s"; } @@ -74,4 +83,5 @@ std::string getHelpText() { }); return helptext; } -} // namespace TgBotCmd + +} // namespace TgBotSocket::CommandHelpers diff --git a/src/socket/TgBotSocket.h b/src/socket/TgBotSocket.h index a763ff2f..5b531466 100644 --- a/src/socket/TgBotSocket.h +++ b/src/socket/TgBotSocket.h @@ -6,61 +6,53 @@ #include #include #include -#include #include #include #include "SharedMalloc.hpp" - -inline std::filesystem::path getSocketPath() { - static auto spath = std::filesystem::temp_directory_path() / "tgbot.sock"; - return spath; -} - -#define TGBOT_NAMESPACE_BEGIN namespace TgBotCommandData { -#define TGBOT_NAMESPACE_END } #include "TgBotCommandExport.hpp" -namespace TgBotCmd { +namespace TgBotSocket { +namespace CommandHelpers { /** * @brief Convert TgBotCommand to string * - * @param cmd TgBotCommand to convert - * @return std::string string representation of TgBotCommand enum + * @param cmd Command to convert + * @return std::string string representation of Command enum */ -std::string toStr(TgBotCommand cmd); +std::string toStr(Command cmd); /** - * @brief Get count of TgBotCommand + * @brief Get count of Command * - * @param cmd TgBotCommand to get arg count of - * @return required arg count of TgBotCommand + * @param cmd Command to get arg count of + * @return required arg count of Command */ -int toCount(TgBotCommand cmd); +int toCount(Command cmd); /** * @brief Check if given command is a client command * - * @param cmd TgBotCommand to check + * @param cmd Command to check * @return true if given command is a client command, false otherwise */ -bool isClientCommand(TgBotCommand cmd); +bool isClientCommand(Command cmd); /** * @brief Check if given command is an internal command * - * @param cmd TgBotCommand to check + * @param cmd Command to check * @return true if given command is an internal command, false otherwise */ -bool isInternalCommand(TgBotCommand cmd); +bool isInternalCommand(Command cmd); /** - * @brief Get help text for TgBotCommand + * @brief Get help text for Command * - * @return std::string help text for TgBotCommand + * @return std::string help text for Command */ std::string getHelpText(void); -} // namespace TgBotCmd +} // namespace CommandHelpers /** * @brief Packet for sending commands to the server @@ -72,13 +64,13 @@ std::string getHelpText(void); * It contains a header, which contains the magic value, the command, and the * size of the data. The data is then followed by the actual data. */ -struct TgBotCommandPacket { - static constexpr auto hdr_sz = sizeof(TgBotCommandPacketHeader); - using header_type = TgBotCommandPacketHeader; +struct Packet { + static constexpr auto hdr_sz = sizeof(PacketHeader); + using header_type = PacketHeader; header_type header{}; SharedMalloc data; - explicit TgBotCommandPacket(header_type::length_type length) + explicit Packet(header_type::length_type length) : data(length) { header.magic = header_type::MAGIC_VALUE; header.data_size = length; @@ -86,15 +78,15 @@ struct TgBotCommandPacket { // Constructor that takes malloc template - explicit TgBotCommandPacket(TgBotCommand cmd, T data) - : TgBotCommandPacket(cmd, &data, sizeof(T)) { + explicit Packet(Command cmd, T data) + : Packet(cmd, &data, sizeof(T)) { static_assert(!std::is_pointer_v, "This constructor should not be used with a pointer"); } // Constructor that takes pointer, uses malloc but with size template - explicit TgBotCommandPacket(TgBotCommand cmd, T in_data, std::size_t size) + explicit Packet(Command cmd, T in_data, std::size_t size) : data(size) { boost::crc_32_type crc; @@ -112,8 +104,10 @@ struct TgBotCommandPacket { SharedMalloc toSocketData() { data->size = hdr_sz + header.data_size; data->alloc(); - memmove(static_cast(data.get()) + hdr_sz, data.get(), header.data_size); + memmove(static_cast(data.get()) + hdr_sz, data.get(), + header.data_size); memcpy(data.get(), &header, hdr_sz); return data; } -}; \ No newline at end of file +}; +} // namespace TgBotSocket diff --git a/src/socket/TgBotSocketClient.cpp b/src/socket/TgBotSocketClient.cpp index a46eed9b..3a841cf0 100644 --- a/src/socket/TgBotSocketClient.cpp +++ b/src/socket/TgBotSocketClient.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include +#include #include #include #include @@ -12,48 +14,49 @@ #include #include #include +#include + #include "SharedMalloc.hpp" #include "TgBotCommandExport.hpp" -#include - // Come last #include -[[noreturn]] static void usage(const char* argv, bool success) { +using namespace TgBotSocket; + +namespace { + +[[noreturn]] void usage(const char* argv, bool success) { std::cout << "Usage: " << argv << " [cmd enum value] [args...]" << std::endl << std::endl; std::cout << "Available cmd enum values:" << std::endl; - std::cout << TgBotCmd::getHelpText(); + std::cout << CommandHelpers::getHelpText(); - exit(!success); + exit(static_cast(!success)); } -static bool verifyArgsCount(TgBotCommand cmd, int argc) { - int required = TgBotCmd::toCount(cmd); +bool verifyArgsCount(Command cmd, int argc) { + int required = CommandHelpers::toCount(cmd); if (required != argc) { LOG(ERROR) << "Invalid argument count " << argc << " for cmd " - << TgBotCmd::toStr(cmd) << ", " << required << " required"; + << CommandHelpers::toStr(cmd) << ", " << required + << " required"; return false; } return true; } -static void _copyToStrBuf(char dst[], size_t dst_size, char* src) { - memset(dst, 0, dst_size); - strncpy(dst, src, dst_size - 1); -} - -template -void copyToStrBuf(char (&dst)[N], char* src) { - _copyToStrBuf(dst, sizeof(dst), src); +template +void copyToStrBuf(std::array& dst, char* src) { + memset(dst.data(), 0, dst.size()); + strncpy(dst.data(), src, dst.size() - 1); } template bool parseOneEnum(C* res, C max, const char* str, const char* name) { - int parsed = 0; + int parsed{}; if (try_parse(str, &parsed)) { - if (max >= 0 && parsed < max) { + if (parsed >= 0 && parsed < static_cast(max)) { *res = static_cast(parsed); return true; } else { @@ -64,54 +67,80 @@ bool parseOneEnum(C* res, C max, const char* str, const char* name) { return false; } +std::string_view AckTypeToStr(callback::AckType type) { + using callback::AckType; + using callback::GenericAck; + switch (type) { + case AckType::SUCCESS: + return "Success"; + case AckType::ERROR_TGAPI_EXCEPTION: + return "Failed: Telegram Api exception"; + case AckType::ERROR_INVALID_ARGUMENT: + return "Failed: Invalid argument"; + case AckType::ERROR_COMMAND_IGNORED: + return "Failed: Command ignored"; + case AckType::ERROR_RUNTIME_ERROR: + return "Failed: Runtime error"; + } + return "Unknown ack type"; +} + +} // namespace + +// TODO: WTF is this +FileDataHelper::DataFromFileParam p; + struct ClientParser : TgBotSocketParser { explicit ClientParser(SocketInterfaceBase* interface) : TgBotSocketParser(interface) {} - void handle_CommandPacket(SocketConnContext context, - TgBotCommandPacket pkt) override { - using TgBotCommandData::AckType; - using TgBotCommandData::GenericAck; - TgBotCommandData::GetUptimeCallback callbackData = {}; - GenericAck result{}; + void handle_CommandPacket(SocketConnContext context, Packet pkt) override { + using callback::AckType; + using callback::GenericAck; + + callback::GetUptimeCallback callbackData = {}; + callback::GenericAck result{}; std::string resultText; switch (pkt.header.cmd) { - case CMD_GET_UPTIME_CALLBACK: { + case Command::CMD_GET_UPTIME_CALLBACK: { pkt.data.assignTo(callbackData); - LOG(INFO) << "Server replied: " << callbackData; + LOG(INFO) << "Server replied: " << callbackData.uptime.data(); break; } - case CMD_DOWNLOAD_FILE_CALLBACK: { - fileData_tofile(pkt.data.get(), pkt.header.data_size); + case Command::CMD_DOWNLOAD_FILE_CALLBACK: { + FileDataHelper::DataToFile( + pkt.data.get(), pkt.header.data_size); break; } - case CMD_GENERIC_ACK: + case Command::CMD_UPLOAD_FILE_DRY_CALLBACK: { pkt.data.assignTo(result); - switch (result.result) { - case AckType::SUCCESS: - resultText = "Success"; - break; - case AckType::ERROR_TGAPI_EXCEPTION: - resultText = "Failed: Telegram Api exception"; - break; - case AckType::ERROR_INVALID_ARGUMENT: - resultText = "Failed: Invalid argument"; - break; - case AckType::ERROR_COMMAND_IGNORED: - resultText = "Failed: Command ignored"; - break; - case AckType::ERROR_RUNTIME_ERROR: - resultText = "Failed: Runtime error"; - break; + LOG(INFO) << "Response from server: " + << AckTypeToStr(result.result); + if (result.result != AckType::SUCCESS) { + LOG(ERROR) << "Reason: " << result.error_msg.data(); + } else { + interface->closeSocketHandle(context); + context = interface->createClientSocket().value(); + LOG(INFO) << "Recreated client socket"; + auto newPkt = FileDataHelper::DataFromFile< + FileDataHelper::UPLOAD_FILE>(p); + LOG(INFO) << "Sending the actual file content again..."; + interface->writeToSocket(context, newPkt->toSocketData()); + onNewBuffer(context); } - LOG(INFO) << "Response from server: " << resultText; + break; + } + case Command::CMD_GENERIC_ACK: + pkt.data.assignTo(result); + LOG(INFO) << "Response from server: " + << AckTypeToStr(result.result); if (result.result != AckType::SUCCESS) { - LOG(ERROR) << "Reason: " << result.error_msg; + LOG(ERROR) << "Reason: " << result.error_msg.data(); } break; default: LOG(ERROR) << "Unhandled callback of command: " - << pkt.header.cmd; + << static_cast(pkt.header.cmd); break; } interface->closeSocketHandle(context); @@ -119,8 +148,8 @@ struct ClientParser : TgBotSocketParser { }; int main(int argc, char** argv) { - enum TgBotCommand cmd = CMD_MAX; - std::optional pkt; + enum Command cmd {}; + std::optional pkt; const char* exe = argv[0]; TgBot_AbslLogInit(); @@ -131,12 +160,12 @@ int main(int argc, char** argv) { ++argv; --argc; - if (!parseOneEnum(&cmd, CMD_MAX, *argv, "cmd")) { + if (!parseOneEnum(&cmd, Command::CMD_MAX, *argv, "cmd")) { LOG(ERROR) << "Invalid cmd enum value"; usage(exe, false); } - if (TgBotCmd::isInternalCommand(cmd)) { + if (CommandHelpers::isInternalCommand(cmd)) { LOG(ERROR) << "Internal commands not supported"; return EXIT_FAILURE; } @@ -150,74 +179,81 @@ int main(int argc, char** argv) { } switch (cmd) { - case CMD_WRITE_MSG_TO_CHAT_ID: { - TgBotCommandData::WriteMsgToChatId data{}; - if (!try_parse(argv[0], &data.to)) { + case Command::CMD_WRITE_MSG_TO_CHAT_ID: { + data::WriteMsgToChatId data{}; + if (!try_parse(argv[0], &data.chat)) { break; } - copyToStrBuf(data.msg, argv[1]); - pkt = TgBotCommandPacket(cmd, data); + copyToStrBuf(data.message, argv[1]); + pkt = Packet(cmd, data); break; } - case CMD_CTRL_SPAMBLOCK: { - TgBotCommandData::CtrlSpamBlock data; - if (parseOneEnum(&data, TgBotCommandData::CTRL_MAX, argv[0], + case Command::CMD_CTRL_SPAMBLOCK: { + data::CtrlSpamBlock data; + if (parseOneEnum(&data, data::CtrlSpamBlock::CTRL_MAX, argv[0], "spamblock")) - pkt = TgBotCommandPacket(cmd, data); + pkt = Packet(cmd, data); break; } - case CMD_OBSERVE_CHAT_ID: { - TgBotCommandData::ObserveChatId data{}; - if (try_parse(argv[0], &data.id) && + case Command::CMD_OBSERVE_CHAT_ID: { + data::ObserveChatId data{}; + if (try_parse(argv[0], &data.chat) && try_parse(argv[1], &data.observe)) - pkt = TgBotCommandPacket(cmd, data); + pkt = Packet(cmd, data); } break; - case CMD_SEND_FILE_TO_CHAT_ID: { - TgBotCommandData::SendFileToChatId data{}; - if (try_parse(argv[0], &data.id) && - parseOneEnum(&data.type, TgBotCommandData::TYPE_MAX, argv[1], + case Command::CMD_SEND_FILE_TO_CHAT_ID: { + data::SendFileToChatId data{}; + if (try_parse(argv[0], &data.chat) && + parseOneEnum(&data.fileType, data::FileType::TYPE_MAX, argv[1], "type")) { - copyToStrBuf(data.filepath, argv[2]); - pkt = TgBotCommandPacket(cmd, data); + copyToStrBuf(data.filePath, argv[2]); + pkt = Packet(cmd, data); } } break; - case CMD_OBSERVE_ALL_CHATS: { - TgBotCommandData::ObserveAllChats data = false; - if (try_parse(argv[0], &data)) { - pkt = TgBotCommandPacket(cmd, data); + case Command::CMD_OBSERVE_ALL_CHATS: { + data::ObserveAllChats data{}; + if (try_parse(argv[0], &data.observe)) { + pkt = Packet(cmd, data); } } break; - case CMD_DELETE_CONTROLLER_BY_ID: { + case Command::CMD_DELETE_CONTROLLER_BY_ID: { SingleThreadCtrlManager::ThreadUsage data{}; if (parseOneEnum(&data, SingleThreadCtrlManager::USAGE_MAX, argv[0], "usage")) { - pkt = TgBotCommandPacket(cmd, data); + pkt = Packet(cmd, data); } } - case CMD_GET_UPTIME: { + case Command::CMD_GET_UPTIME: { // Data is unused in this case - pkt = TgBotCommandPacket(cmd, 1); + pkt = Packet(cmd, 1); break; } - case CMD_UPLOAD_FILE: { - pkt = fileData_fromFile(CMD_UPLOAD_FILE, argv[0], argv[1]); + case Command::CMD_UPLOAD_FILE: { + FileDataHelper::DataFromFileParam params; + params.filepath = argv[0]; + params.destfilepath = argv[1]; + params.options.hash_ignore = false; //= true; + params.options.overwrite = true; + pkt = FileDataHelper::DataFromFile( + params); + p = params; break; } - case CMD_DOWNLOAD_FILE: { - TgBotCommandData::DownloadFile data{}; + case Command::CMD_DOWNLOAD_FILE: { + data::DownloadFile data{}; copyToStrBuf(data.filepath, argv[0]); copyToStrBuf(data.destfilename, argv[1]); - pkt = TgBotCommandPacket(cmd, &data, sizeof(data)); + pkt = Packet(cmd, &data, sizeof(data)); break; } default: - LOG(FATAL) << "Unhandled command: " << TgBotCmd::toStr(cmd); + LOG(FATAL) << "Unhandled command: " << CommandHelpers::toStr(cmd); }; if (!pkt) { LOG(ERROR) << "Failed parsing arguments for " - << TgBotCmd::toStr(cmd).c_str(); + << CommandHelpers::toStr(cmd).c_str(); return EXIT_FAILURE; } else { boost::crc_32_type crc; diff --git a/src/socket/include/TgBotCommandExport.hpp b/src/socket/include/TgBotCommandExport.hpp index 267bd1d8..46f0c958 100644 --- a/src/socket/include/TgBotCommandExport.hpp +++ b/src/socket/include/TgBotCommandExport.hpp @@ -2,24 +2,21 @@ // A header export for the TgBot's socket connection +#include + +#include #include #include #include #include "../../include/Types.h" -#ifndef TGBOT_NAMESPACE_BEGIN -#define TGBOT_NAMESPACE_BEGIN -#endif -#ifndef TGBOT_NAMESPACE_END -#define TGBOT_NAMESPACE_END -#endif -#undef ERROR_INVALID_STATE +namespace TgBotSocket { constexpr int MAX_PATH_SIZE = 256; constexpr int MAX_MSG_SIZE = 256; -enum TgBotCommand : std::int32_t { +enum class Command : std::int32_t { CMD_WRITE_MSG_TO_CHAT_ID, CMD_CTRL_SPAMBLOCK, CMD_OBSERVE_CHAT_ID, @@ -27,6 +24,7 @@ enum TgBotCommand : std::int32_t { CMD_OBSERVE_ALL_CHATS, CMD_DELETE_CONTROLLER_BY_ID, CMD_GET_UPTIME, + CMD_UPLOAD_FILE_DRY, CMD_UPLOAD_FILE, CMD_DOWNLOAD_FILE, CMD_CLIENT_MAX, @@ -35,13 +33,35 @@ enum TgBotCommand : std::int32_t { CMD_SERVER_INTERNAL_START = 100, CMD_GET_UPTIME_CALLBACK = CMD_SERVER_INTERNAL_START, CMD_GENERIC_ACK, + CMD_UPLOAD_FILE_DRY_CALLBACK, CMD_DOWNLOAD_FILE_CALLBACK, CMD_MAX, }; -TGBOT_NAMESPACE_BEGIN +/** + * @brief Header for TgBotCommand Packets + * + * Header contains the magic value, command, and the size of the data + */ +struct PacketHeader { + using length_type = uint64_t; + constexpr static int64_t MAGIC_VALUE_BASE = 0xDEADFACE; + // Version number, to be increased on breaking changes + // 1: Initial version + // 2: Added crc32 checks to packet data + // 3: Uploadfile has a sha256sum check, std::array conversions + constexpr static int DATA_VERSION = 3; + constexpr static int64_t MAGIC_VALUE = MAGIC_VALUE_BASE + DATA_VERSION; + + int64_t magic = MAGIC_VALUE; ///< Magic value to verify the packet + Command cmd{}; ///< Command to be executed + length_type data_size{}; ///< Size of the data in the packet + uint32_t checksum{}; ///< Checksum of the packet data +}; + +namespace data { -enum FileType { +enum class FileType { TYPE_PHOTO, TYPE_VIDEO, TYPE_GIF, @@ -50,7 +70,7 @@ enum FileType { TYPE_MAX }; -enum CtrlSpamBlock { +enum class CtrlSpamBlock { CTRL_OFF, // Disabled CTRL_LOGGING_ONLY_ON, // Logging only, not taking action CTRL_ON, // Enabled, does delete but doesn't mute @@ -59,27 +79,61 @@ enum CtrlSpamBlock { }; struct WriteMsgToChatId { - ChatId to; // destination chatid - char msg[MAX_MSG_SIZE]; // Msg to send + ChatId chat; // destination chatid + std::array message; // Msg to send }; struct ObserveChatId { - ChatId id; + ChatId chat; bool observe; // new state for given ChatId, // true/false - Start/Stop observing }; struct SendFileToChatId { - ChatId id; // Destination ChatId - FileType type; // File type for file - char filepath[MAX_PATH_SIZE]; // Path to file + ChatId chat; // Destination ChatId + FileType fileType; // File type for file + std::array filePath; // Path to file (local) +}; + +struct ObserveAllChats { + bool observe; // new state for all chats, + // true/false - Start/Stop observing }; -using ObserveAllChats = bool; +struct DeleteControllerById { + int controller_id; +}; -using DeleteControllerById = int; +struct UploadFile { + std::array filepath{}; // Destination file name + std::array + sha256_hash{}; // SHA256 hash of the file + + // Returns AckType::ERROR_COMMAND_IGNORED on options failure + struct Options { + bool overwrite = false; // Overwrite existing file if exists + bool hash_ignore = + false; // Ignore hash, always upload file even if the same file + // exists and the hash matches. Depends on overwrite flag + // for actual overwriting + bool dry_run = + false; // If true, just check the hashes and return result. + } options; + uint8_t buf[]; // Buffer +}; -using GetUptimeCallback = char[sizeof("Uptime: 99h 99m 99s")]; +struct DownloadFile { + std::array filepath{}; // Path to file (in remote) + std::array destfilename{}; // Destination file name + uint8_t buf[]; // Buffer +}; +} // namespace data + +namespace callback { + +struct GetUptimeCallback { + std::array uptime; +}; enum class AckType { SUCCESS, @@ -90,69 +144,45 @@ enum class AckType { }; struct GenericAck { - AckType result; // result type - char error_msg[MAX_MSG_SIZE]{}; // Error message, only valid when result - // type is not SUCCESS + AckType result; // result type + // Error message, only valid when result type is not SUCCESS + std::array error_msg{}; // Create a new instance of the Generic Ack, error. explicit GenericAck(AckType result, const std::string& errorMsg) : result(result) { - std::strncpy(this->error_msg, errorMsg.c_str(), MAX_MSG_SIZE); + std::strncpy(this->error_msg.data(), errorMsg.c_str(), MAX_MSG_SIZE); this->error_msg[MAX_MSG_SIZE - 1] = '\0'; } GenericAck() = default; - // Create a new instance of the Generic Ack, success. - static GenericAck ok() { - return GenericAck(AckType::SUCCESS, "OK"); - } -}; - -using UploadFile = char[MAX_PATH_SIZE]; // Destination file name - -struct DownloadFile { - char filepath[MAX_PATH_SIZE]{}; // Path to file (in remote) - char destfilename[MAX_PATH_SIZE]{}; // Destination file name -}; -TGBOT_NAMESPACE_END - -/** - * @brief Header for TgBotCommand Packets - * - * Header contains the magic value, command, and the size of the data - */ -struct TgBotCommandPacketHeader { - using length_type = uint64_t; - constexpr static int64_t MAGIC_VALUE_BASE = 0xDEADFACE; - // Version number, to be increased on breaking changes - // 1: Initial version - // 2: Added crc32 checks to packet data - constexpr static int DATA_VERSION = 2; - constexpr static int64_t MAGIC_VALUE = MAGIC_VALUE_BASE + DATA_VERSION; - - int64_t magic = MAGIC_VALUE; ///< Magic value to verify the packet - TgBotCommand cmd{}; ///< Command to be executed - length_type data_size{}; ///< Size of the data in the packet - uint32_t checksum{}; ///< Checksum of the packet data + // Create a new instance of the Generic Ack, success. + static GenericAck ok() { return GenericAck(AckType::SUCCESS, "OK"); } }; -TGBOT_NAMESPACE_BEGIN +} // namespace callback +} // namespace TgBotSocket +// static asserts for compatibility check // We make some asserts here to ensure that the size of the packet is expected #define ASSERT_SIZE(DataType, DataSize) \ static_assert(sizeof(DataType) == (DataSize), \ "Size of " #DataType " has changed") +namespace TgBotSocket::data { ASSERT_SIZE(WriteMsgToChatId, 264); ASSERT_SIZE(ObserveChatId, 16); ASSERT_SIZE(SendFileToChatId, 272); ASSERT_SIZE(ObserveAllChats, 1); ASSERT_SIZE(DeleteControllerById, 4); -ASSERT_SIZE(GetUptimeCallback, 20); -ASSERT_SIZE(GenericAck, 260); -ASSERT_SIZE(UploadFile, 256); +ASSERT_SIZE(UploadFile, 291); ASSERT_SIZE(DownloadFile, 512); -ASSERT_SIZE(TgBotCommandPacketHeader, 32); -#undef ASSERT_SIZE +ASSERT_SIZE(PacketHeader, 32); +} + +namespace TgBotSocket::callback { +ASSERT_SIZE(GetUptimeCallback, 21); +ASSERT_SIZE(GenericAck, 260); +} -TGBOT_NAMESPACE_END \ No newline at end of file +#undef ASSERT_SIZE \ No newline at end of file diff --git a/src/socket/interface/SocketBase.cpp b/src/socket/interface/SocketBase.cpp index f7ff4dc0..613fe9a4 100644 --- a/src/socket/interface/SocketBase.cpp +++ b/src/socket/interface/SocketBase.cpp @@ -6,7 +6,6 @@ #include #include "SharedMalloc.hpp" -#include "SocketDescriptor_defs.hpp" void SocketInterfaceBase::setOptions(Options opt, const std::string data, bool persistent) { diff --git a/src/socket/interface/SocketBase.hpp b/src/socket/interface/SocketBase.hpp index 6a2a97b1..b82645dd 100644 --- a/src/socket/interface/SocketBase.hpp +++ b/src/socket/interface/SocketBase.hpp @@ -3,13 +3,14 @@ #include #include +#include +#include #include #include #include #include "SharedMalloc.hpp" - struct SocketConnContext { socket_handle_t cfd{}; // connection socket file descriptor SharedMalloc addr; // struct sockaddr_*'s address @@ -31,6 +32,7 @@ struct SocketInterfaceBase { // addr is used as void pointer to maintain platform independence. using listener_callback_t = std::function; using dummy_listen_buf_t = char; + using buffer_len_t = uint64_t; constexpr static int kTgBotHostPort = 50000; @@ -67,8 +69,7 @@ struct SocketInterfaceBase { * empty optional if an error occurred or no data was available. */ virtual std::optional readFromSocket( - SocketConnContext context, - TgBotCommandPacketHeader::length_type length) = 0; + SocketConnContext context, buffer_len_t length) = 0; /** * @brief Closes the socket handle. @@ -216,6 +217,7 @@ struct SocketInterfaceBase { bool canSocketBeClosed(); void cleanupServerSocket(); void doGetRemoteAddr(socket_handle_t handle); + static std::filesystem::path getSocketPath(); private: SocketInterfaceBase *interface; diff --git a/src/socket/interface/impl/SocketPosix.cpp b/src/socket/interface/impl/SocketPosix.cpp index 088ec25d..cdee5089 100644 --- a/src/socket/interface/impl/SocketPosix.cpp +++ b/src/socket/interface/impl/SocketPosix.cpp @@ -103,7 +103,7 @@ void SocketInterfaceUnix::writeToSocket(SocketConnContext context, } std::optional SocketInterfaceUnix::readFromSocket( - SocketConnContext handle, TgBotCommandPacketHeader::length_type length) { + SocketConnContext handle, buffer_len_t length) { SharedMalloc buf(length); auto* addr = static_cast(handle.addr.get()); socklen_t addrlen = handle.addr->size; @@ -139,5 +139,5 @@ bool SocketInterfaceUnix::setSocketOptTimeout(socket_handle_t handle, if (ret) { PLOG(ERROR) << "Failed to set socket timeout"; } - return !ret; + return ret == 0; } diff --git a/src/socket/interface/impl/SocketPosix.hpp b/src/socket/interface/impl/SocketPosix.hpp index c413c278..3d7b6ce5 100644 --- a/src/socket/interface/impl/SocketPosix.hpp +++ b/src/socket/interface/impl/SocketPosix.hpp @@ -21,9 +21,8 @@ struct SocketInterfaceUnix : SocketInterfaceBase { bool closeSocketHandle(socket_handle_t& handle) override; bool setSocketOptTimeout(socket_handle_t handle, int timeout) override; - std::optional readFromSocket( - SocketConnContext context, - TgBotCommandPacketHeader::length_type length) override; + std::optional readFromSocket(SocketConnContext context, + buffer_len_t length) override; SocketInterfaceUnix() = default; virtual ~SocketInterfaceUnix() = default; diff --git a/src/socket/interface/impl/SocketWindows.cpp b/src/socket/interface/impl/SocketWindows.cpp index 6222014a..6b954244 100644 --- a/src/socket/interface/impl/SocketWindows.cpp +++ b/src/socket/interface/impl/SocketWindows.cpp @@ -89,7 +89,7 @@ void SocketInterfaceWindows::writeToSocket(SocketConnContext context, void SocketInterfaceWindows::forceStopListening(void) { kRun = false; } std::optional SocketInterfaceWindows::readFromSocket( - SocketConnContext context, TgBotCommandPacketHeader::length_type length) { + SocketConnContext context, TgBotSocket::PacketHeader::length_type length) { SharedMalloc buf(length); auto *addr = static_cast(context.addr.get()); auto *data = static_cast(buf.get()); diff --git a/src/socket/interface/impl/SocketWindows.hpp b/src/socket/interface/impl/SocketWindows.hpp index 26d364f4..a8811e6b 100644 --- a/src/socket/interface/impl/SocketWindows.hpp +++ b/src/socket/interface/impl/SocketWindows.hpp @@ -23,7 +23,7 @@ struct SocketInterfaceWindows : SocketInterfaceBase { bool setSocketOptTimeout(socket_handle_t handle, int timeout) override; std::optional readFromSocket( SocketConnContext context, - TgBotCommandPacketHeader::length_type length) override; + TgBotSocket::PacketHeader::length_type length) override; struct WinHelper { explicit WinHelper(SocketInterfaceWindows* interface) diff --git a/src/socket/interface/impl/bot/SocketDataHandler.cpp b/src/socket/interface/impl/bot/SocketDataHandler.cpp index 191b8cc1..b716c820 100644 --- a/src/socket/interface/impl/bot/SocketDataHandler.cpp +++ b/src/socket/interface/impl/bot/SocketDataHandler.cpp @@ -17,14 +17,20 @@ #include #include #include +#include #include +#include "TgBotCommandExport.hpp" + // Come last #include using TgBot::Api; using TgBot::InputFile; namespace fs = std::filesystem; +using namespace TgBotSocket; +using namespace TgBotSocket::callback; +using namespace TgBotSocket::data; namespace { @@ -63,7 +69,7 @@ std::string getMIMEString(const std::string& path) { GenericAck SocketInterfaceTgBot::handle_WriteMsgToChatId(const void* ptr) { const auto* data = static_cast(ptr); try { - bot_sendMessage(_bot, data->to, data->msg); + bot_sendMessage(_bot, data->chat, data->message.data()); } catch (const TgBot::TgException& e) { LOG(ERROR) << "Exception at handler: " << e.what(); return GenericAck(AckType::ERROR_TGAPI_EXCEPTION, e.what()); @@ -81,7 +87,7 @@ GenericAck SocketInterfaceTgBot::handle_ObserveChatId(const void* ptr) { const auto* data = static_cast(ptr); auto obs = ChatObserver::getInstance(); const std::lock_guard _(obs->m); - auto it = std::ranges::find(obs->observedChatIds, data->id); + auto it = std::ranges::find(obs->observedChatIds, data->chat); bool observe = data->observe; if (obs->observeAllChats) { @@ -90,7 +96,7 @@ GenericAck SocketInterfaceTgBot::handle_ObserveChatId(const void* ptr) { } if (it == obs->observedChatIds.end()) { if (observe) { - obs->observedChatIds.push_back(data->id); + obs->observedChatIds.push_back(data->chat); } else { return GenericAck(AckType::ERROR_COMMAND_IGNORED, "Target chat wasn't being observed"); @@ -109,54 +115,54 @@ GenericAck SocketInterfaceTgBot::handle_ObserveChatId(const void* ptr) { GenericAck SocketInterfaceTgBot::handle_SendFileToChatId(const void* ptr) { const auto* data = static_cast(ptr); - const auto* file = data->filepath; + const auto* file = data->filePath.data(); using FileOrId_t = boost::variant; - std::function fn; + std::function fn; try { - switch (data->type) { - case TYPE_PHOTO: - fn = [](const Api& api, ChatId id, const FileOrId_t file) { + switch (data->fileType) { + case FileType::TYPE_PHOTO: + fn = [](const Api& api, ChatId id, const FileOrId_t& file) { return api.sendPhoto(id, file); }; break; - case TYPE_VIDEO: - fn = [](const Api& api, ChatId id, const FileOrId_t file) { + case FileType::TYPE_VIDEO: + fn = [](const Api& api, ChatId id, const FileOrId_t& file) { return api.sendVideo(id, file); }; break; - case TYPE_GIF: - fn = [](const Api& api, ChatId id, const FileOrId_t file) { + case FileType::TYPE_GIF: + fn = [](const Api& api, ChatId id, const FileOrId_t& file) { return api.sendAnimation(id, file); }; - case TYPE_DOCUMENT: - fn = [](const Api& api, ChatId id, const FileOrId_t file) { + case FileType::TYPE_DOCUMENT: + fn = [](const Api& api, ChatId id, const FileOrId_t& file) { return api.sendDocument(id, file); }; break; - case TYPE_DICE: { + case FileType::TYPE_DICE: { static const std::vector dices = { "🎲", "🎯", "🏀", "⚽", "🎳", "🎰"}; // TODO: More clean code? _bot.getApi().sendDice( - data->id, false, 0, nullptr, + data->chat, false, 0, nullptr, dices[genRandomNumber(0, dices.size() - 1)]); return GenericAck(); } default: - fn = [](const Api&, ChatId, const FileOrId_t) { + fn = [](const Api&, ChatId, const FileOrId_t&) { return nullptr; }; break; } // Try to send as local file first try { - fn(_bot.getApi(), data->id, + fn(_bot.getApi(), data->chat, InputFile::fromFile(file, getMIMEString(file))); } catch (std::ifstream::failure& e) { LOG(INFO) << "Failed to send '" << file << "' as local file, trying as Telegram " "file id"; - fn(_bot.getApi(), data->id, std::string(file)); + fn(_bot.getApi(), data->chat, std::string(file)); } } catch (const TgBot::TgException& e) { LOG(ERROR) << "Exception at handler, " << e.what(); @@ -168,41 +174,60 @@ GenericAck SocketInterfaceTgBot::handle_SendFileToChatId(const void* ptr) { GenericAck SocketInterfaceTgBot::handle_ObserveAllChats(const void* ptr) { auto obs = ChatObserver::getInstance(); const std::lock_guard _(obs->m); - obs->observeAllChats = *static_cast(ptr); + obs->observeAllChats = static_cast(ptr)->observe; return GenericAck::ok(); } GenericAck SocketInterfaceTgBot::handle_DeleteControllerById(const void* ptr) { DeleteControllerById data = *static_cast(ptr); enum SingleThreadCtrlManager::ThreadUsage threadUsage{}; - if (data < 0 || data >= SingleThreadCtrlManager::USAGE_MAX) { - LOG(ERROR) << "Invalid controller id: " << data; + if (data.controller_id < 0 || + data.controller_id >= SingleThreadCtrlManager::USAGE_MAX) { + LOG(ERROR) << "Invalid controller id: " << data.controller_id; return GenericAck(AckType::ERROR_INVALID_ARGUMENT, "Invalid controller id"); } - threadUsage = static_cast(data); + threadUsage = + static_cast(data.controller_id); SingleThreadCtrlManager::getInstance()->destroyController(threadUsage); return GenericAck::ok(); } GenericAck SocketInterfaceTgBot::handle_UploadFile( - const void* ptr, TgBotCommandPacketHeader::length_type len) { - if (fileData_tofile(ptr, len)) { - return GenericAck::ok(); + const void* ptr, TgBotSocket::PacketHeader::length_type len, bool dry) { + bool ret = false; + + if (dry) { + ret = FileDataHelper::DataToFile(ptr, + len); + if (!ret) { + return GenericAck(AckType::ERROR_COMMAND_IGNORED, + "Options verification failed"); + } + } else { + ret = FileDataHelper::DataToFile(ptr, len); + if (!ret) { + return GenericAck(AckType::ERROR_RUNTIME_ERROR, + "Failed to write file"); + } } - return GenericAck(AckType::ERROR_RUNTIME_ERROR, "Failed to write file"); + + return GenericAck::ok(); } bool SocketInterfaceTgBot::handle_DownloadFile(SocketConnContext ctx, const void* ptr) { const auto* data = static_cast(ptr); - auto pkt = fileData_fromFile(CMD_DOWNLOAD_FILE_CALLBACK, data->filepath, - data->destfilename); + FileDataHelper::DataFromFileParam params; + params.filepath = data->filepath.data(); + params.destfilepath = data->destfilename.data(); + auto pkt = + FileDataHelper::DataFromFile(params); if (!pkt) { LOG(ERROR) << "Failed to prepare download file packet"; return false; } - interface->writeToSocket(ctx, pkt->toSocketData()); + interface->writeToSocket(std::move(ctx), pkt->toSocketData()); return true; } @@ -216,50 +241,52 @@ bool SocketInterfaceTgBot::handle_GetUptime(SocketConnContext ctx, uptime << "Uptime: " << to_string(diff); uptimeStr = uptime.str(); LOG(INFO) << "Sending text back: " << std::quoted(uptimeStr); - TgBotCommandPacket pkt(CMD_GET_UPTIME_CALLBACK, uptimeStr.c_str(), - sizeof(GetUptimeCallback) - 1); + Packet pkt(Command::CMD_GET_UPTIME_CALLBACK, uptimeStr.c_str(), + sizeof(GetUptimeCallback) - 1); interface->writeToSocket(ctx, pkt.toSocketData()); return true; } void SocketInterfaceTgBot::handle_CommandPacket(SocketConnContext ctx, - TgBotCommandPacket pkt) { + TgBotSocket::Packet pkt) { const void* ptr = pkt.data.get(); - using namespace TgBotCommandData; std::variant ret; switch (pkt.header.cmd) { - case CMD_WRITE_MSG_TO_CHAT_ID: + case Command::CMD_WRITE_MSG_TO_CHAT_ID: ret = handle_WriteMsgToChatId(ptr); break; - case CMD_CTRL_SPAMBLOCK: + case Command::CMD_CTRL_SPAMBLOCK: ret = handle_CtrlSpamBlock(ptr); break; - case CMD_OBSERVE_CHAT_ID: + case Command::CMD_OBSERVE_CHAT_ID: ret = handle_ObserveChatId(ptr); break; - case CMD_SEND_FILE_TO_CHAT_ID: + case Command::CMD_SEND_FILE_TO_CHAT_ID: ret = handle_SendFileToChatId(ptr); break; - case CMD_OBSERVE_ALL_CHATS: + case Command::CMD_OBSERVE_ALL_CHATS: ret = handle_ObserveAllChats(ptr); break; - case CMD_DELETE_CONTROLLER_BY_ID: + case Command::CMD_DELETE_CONTROLLER_BY_ID: ret = handle_DeleteControllerById(ptr); break; - case CMD_GET_UPTIME: + case Command::CMD_GET_UPTIME: ret = handle_GetUptime(ctx, ptr); break; - case CMD_UPLOAD_FILE: - ret = handle_UploadFile(ptr, pkt.header.data_size); + case Command::CMD_UPLOAD_FILE: + ret = handle_UploadFile(ptr, pkt.header.data_size, false); break; - case CMD_DOWNLOAD_FILE: + case Command::CMD_UPLOAD_FILE_DRY: + ret = handle_UploadFile(ptr, pkt.header.data_size, true); + break; + case Command::CMD_DOWNLOAD_FILE: ret = handle_DownloadFile(ctx, ptr); break; default: - if (TgBotCmd::isClientCommand(pkt.header.cmd)) { + if (CommandHelpers::isClientCommand(pkt.header.cmd)) { LOG(ERROR) << "Unhandled cmd: " - << TgBotCmd::toStr(pkt.header.cmd); + << CommandHelpers::toStr(pkt.header.cmd); } else { LOG(WARNING) << "cmd ignored (as internal): " << static_cast(pkt.header.cmd); @@ -267,24 +294,34 @@ void SocketInterfaceTgBot::handle_CommandPacket(SocketConnContext ctx, return; }; switch (pkt.header.cmd) { - case CMD_GET_UPTIME: - case CMD_DOWNLOAD_FILE: { + case Command::CMD_GET_UPTIME: + case Command::CMD_DOWNLOAD_FILE: { // This has its own callback, so we don't need to send ack. bool result = std::get(ret); DLOG_IF(INFO, (!result)) - << "Command failed: " << TgBotCmd::toStr(pkt.header.cmd); + << "Command failed: " << CommandHelpers::toStr(pkt.header.cmd); + break; + } + case Command::CMD_UPLOAD_FILE_DRY: { + // Need a special cmd here + GenericAck result = std::get(ret); + Packet ackpkt(Command::CMD_UPLOAD_FILE_DRY_CALLBACK, &result, + sizeof(GenericAck)); + LOG(INFO) << "Sending ack: " << std::boolalpha + << (result.result == AckType::SUCCESS); + interface->writeToSocket(ctx, ackpkt.toSocketData()); break; } - case CMD_WRITE_MSG_TO_CHAT_ID: - case CMD_CTRL_SPAMBLOCK: - case CMD_OBSERVE_CHAT_ID: - case CMD_SEND_FILE_TO_CHAT_ID: - case CMD_OBSERVE_ALL_CHATS: - case CMD_DELETE_CONTROLLER_BY_ID: - case CMD_UPLOAD_FILE: { + case Command::CMD_WRITE_MSG_TO_CHAT_ID: + case Command::CMD_CTRL_SPAMBLOCK: + case Command::CMD_OBSERVE_CHAT_ID: + case Command::CMD_SEND_FILE_TO_CHAT_ID: + case Command::CMD_OBSERVE_ALL_CHATS: + case Command::CMD_DELETE_CONTROLLER_BY_ID: + case Command::CMD_UPLOAD_FILE: { GenericAck result = std::get(ret); - TgBotCommandPacket ackpkt(CMD_GENERIC_ACK, &result, - sizeof(GenericAck)); + Packet ackpkt(Command::CMD_GENERIC_ACK, &result, + sizeof(GenericAck)); LOG(INFO) << "Sending ack: " << std::boolalpha << (result.result == AckType::SUCCESS); interface->writeToSocket(ctx, ackpkt.toSocketData()); diff --git a/src/socket/interface/impl/bot/TgBotPacketParser.cpp b/src/socket/interface/impl/bot/TgBotPacketParser.cpp index d5ee7a9e..c30f99df 100644 --- a/src/socket/interface/impl/bot/TgBotPacketParser.cpp +++ b/src/socket/interface/impl/bot/TgBotPacketParser.cpp @@ -12,23 +12,24 @@ using HandleState = TgBotSocketParser::HandleState; HandleState TgBotSocketParser::handle_PacketHeader( std::optional& socketData, - std::optional& pkt) { + std::optional& pkt) { int64_t diff = 0; - if (!socketData || socketData.value()->size != TgBotCommandPacket::hdr_sz) { + if (!socketData || + socketData.value()->size != TgBotSocket::Packet::hdr_sz) { LOG(ERROR) << "Failed to read from socket"; return HandleState::Fail; } - pkt = TgBotCommandPacket(TgBotCommandPacket::hdr_sz); + pkt = TgBotSocket::Packet(TgBotSocket::Packet::hdr_sz); socketData->assignTo(pkt->header); - diff = pkt->header.magic - TgBotCommandPacketHeader::MAGIC_VALUE_BASE; - if (diff != TgBotCommandPacketHeader::DATA_VERSION) { + diff = pkt->header.magic - TgBotSocket::PacketHeader::MAGIC_VALUE_BASE; + if (diff != TgBotSocket::PacketHeader::DATA_VERSION) { LOG(WARNING) << "Invalid magic value, dropping buffer"; if (diff >= 0) { LOG(INFO) << "This packet contains header data version " << diff << ", but we have version " - << TgBotCommandPacketHeader::DATA_VERSION; + << TgBotSocket::PacketHeader::DATA_VERSION; } return HandleState::Ignore; } @@ -38,11 +39,11 @@ HandleState TgBotSocketParser::handle_PacketHeader( HandleState TgBotSocketParser::handle_Packet( std::optional& socketData, - std::optional& pkt) { + std::optional& pkt) { boost::crc_32_type crc; - if (TgBotCmd::isClientCommand(pkt->header.cmd)) { - LOG(INFO) << "Received buf with " << TgBotCmd::toStr(pkt->header.cmd) + if (TgBotSocket::CommandHelpers::isClientCommand(pkt->header.cmd)) { + LOG(INFO) << "Received buf with " << TgBotSocket::CommandHelpers::toStr(pkt->header.cmd) << ", invoke callback!"; } @@ -62,7 +63,7 @@ HandleState TgBotSocketParser::handle_Packet( return HandleState::Ignore; } - pkt->data->size = TgBotCommandPacket::hdr_sz + pkt->header.data_size; + pkt->data->size = TgBotSocket::Packet::hdr_sz + pkt->header.data_size; pkt->data->alloc(); socketData->assignTo(pkt->data.get(), pkt->header.data_size); @@ -71,10 +72,10 @@ HandleState TgBotSocketParser::handle_Packet( bool TgBotSocketParser::onNewBuffer(SocketConnContext ctx) { std::optional data; - std::optional pkt; + std::optional pkt; bool ret = false; - data = interface->readFromSocket(ctx, sizeof(TgBotCommandPacketHeader)); + data = interface->readFromSocket(ctx, sizeof(TgBotSocket::PacketHeader)); switch (handle_PacketHeader(data, pkt)) { case HandleState::Ok: { data = interface->readFromSocket(ctx, pkt->header.data_size); diff --git a/src/socket/interface/impl/bot/TgBotPacketParser.hpp b/src/socket/interface/impl/bot/TgBotPacketParser.hpp index 5d97ba29..5045a8c4 100644 --- a/src/socket/interface/impl/bot/TgBotPacketParser.hpp +++ b/src/socket/interface/impl/bot/TgBotPacketParser.hpp @@ -26,7 +26,7 @@ struct TgBotSocketParser { */ [[nodiscard]] static HandleState handle_PacketHeader( std::optional &socketData, - std::optional &pkt); + std::optional &pkt); /** * @brief Reads a packet from the socket. @@ -38,10 +38,10 @@ struct TgBotSocketParser { */ [[nodiscard]] static HandleState handle_Packet( std::optional &socketData, - std::optional &pkt); + std::optional &pkt); virtual void handle_CommandPacket(SocketConnContext ctx, - TgBotCommandPacket commandPacket) = 0; + TgBotSocket::Packet commandPacket) = 0; explicit TgBotSocketParser(SocketInterfaceBase *interface) : interface(interface) {} diff --git a/src/socket/interface/impl/bot/TgBotSocketFileHelper.cpp b/src/socket/interface/impl/bot/TgBotSocketFileHelper.cpp deleted file mode 100644 index def84ec2..00000000 --- a/src/socket/interface/impl/bot/TgBotSocketFileHelper.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include - -#include -#include - -#include "TgBotSocketFileHelper.hpp" - -using TgBotCommandData::UploadFile; - -bool fileData_tofile(const void* ptr, size_t len) { - const auto* data = static_cast(ptr); - UploadFile destfilepath{}; - FILE* file = nullptr; - size_t ret = 0; - size_t file_size = len - sizeof(UploadFile); - - LOG(INFO) << "This buffer has a size of " << len << " bytes"; - LOG(INFO) << "Which is " << file_size << " bytes excluding the header"; - - strncpy(destfilepath, data, sizeof(UploadFile)); - if ((file = fopen(destfilepath, "wb")) == nullptr) { - LOG(ERROR) << "Failed to open file: " << destfilepath; - return false; - } - ret = fwrite(data + sizeof(UploadFile), file_size, 1, file); - if (ret != 1) { - LOG(ERROR) << "Failed to write to file: " << destfilepath << " (Wrote " - << ret << " bytes)"; - fclose(file); - return false; - } - fclose(file); - return true; -} - -std::optional fileData_fromFile(TgBotCommand cmd, - const std::string_view filename, - const std::string_view destfilepath) { - constexpr size_t datahdr_size = sizeof(TgBotCommandData::UploadFile); - size_t size = 0; - size_t total_size = 0; - char* buf = nullptr; - FILE* fp = nullptr; - std::optional pkt; - - fp = fopen(filename.data(), "rb"); - if (fp != nullptr) { - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - total_size = size + datahdr_size; - LOG(INFO) << "Sending file " << filename; - buf = static_cast(malloc(total_size)); - LOG(INFO) << "mem-alloc buffer of size " << total_size << " bytes"; - // Copy data header to the beginning of the buffer. - if (buf != nullptr) { - strncpy(buf, destfilepath.data(), datahdr_size); - char* moved_buf = buf + datahdr_size; - fread(moved_buf, 1, size, fp); - pkt = TgBotCommandPacket(cmd, buf, total_size); - free(buf); - } - fclose(fp); - } else { - LOG(ERROR) << "Failed to open file " << filename; - } - return pkt; -} \ No newline at end of file diff --git a/src/socket/interface/impl/bot/TgBotSocketFileHelper.hpp b/src/socket/interface/impl/bot/TgBotSocketFileHelper.hpp index 1a76f08e..cd106f3e 100644 --- a/src/socket/interface/impl/bot/TgBotSocketFileHelper.hpp +++ b/src/socket/interface/impl/bot/TgBotSocketFileHelper.hpp @@ -1,35 +1,311 @@ #pragma once +#include +#include #include +#include +#include +#include +#include +#include #include -#include - -/** - * @brief Writes data to a file. - * - * This function writes the data pointed to by 'ptr' and of length 'len' to a file. - * - * @param ptr Pointer to the data to be written. - * @param len Length of the data to be written. - * - * @return Returns true if the data is successfully written to the file, false otherwise. - */ -bool fileData_tofile(const void* ptr, size_t len); - -/** - * @brief Reads data from a file and creates a TgBotCommandPacket. - * - * This function reads data from a file specified by 'filename' and creates a TgBotCommandPacket. - * The data is then written to a file specified by 'destfilepath'. - * - * @param cmd The TgBotCommand to be included in the TgBotCommandPacket. - * @param filename The name of the file to read data from. - * @param destfilepath The name of the file to write the data to. - * - * @return Returns an optional TgBotCommandPacket containing the command and the data read from the file. - * If the file cannot be opened or read, returns an empty optional. - */ -std::optional fileData_fromFile(TgBotCommand cmd, - const std::string_view filename, - const std::string_view destfilepath); \ No newline at end of file +#include +#include + +#include "SocketBase.hpp" +#include "TgBotCommandExport.hpp" + +template +inline void copyTo(std::array& arr_in, const char* buf) { + strncpy(arr_in.data(), buf, size); +} + +namespace FileDataHelper { +using len_t = SocketInterfaceBase::buffer_len_t; +using RAIIMalloc = std::unique_ptr; + +enum Pass { + UPLOAD_FILE_DRY, + UPLOAD_FILE, + DOWNLOAD_FILE, +}; +struct DataFromFileParam { + std::filesystem::path filepath; + std::filesystem::path destfilepath; + TgBotSocket::data::UploadFile::Options options; +}; +struct ReadFileFullyRet { + RAIIMalloc data; + len_t size; +}; + +static RAIIMalloc createMemory(len_t size); +static bool writeFileCommon(const std::filesystem::path& filename, + const uint8_t* startAddr, const len_t size); + +static std::optional readFileFullyCommon( + const std::filesystem::path& filename); + +template +static bool DataToFile(const void* ptr, len_t len) = delete; +// -> Server (dry) +template <> +bool DataToFile(const void* ptr, len_t len); +// -> Server +template <> +bool DataToFile(const void* ptr, len_t len); +// -> Client +template <> +bool DataToFile(const void* ptr, len_t len); + +template +static std::optional DataFromFile( + const DataFromFileParam&) = delete; + +// Client -> +template <> +std::optional DataFromFile( + const DataFromFileParam&); + +// Client -> +template <> +std::optional DataFromFile( + const DataFromFileParam&); + +// Server -> +template <> +std::optional DataFromFile( + const DataFromFileParam&); +}; // namespace FileDataHelper + +// Implementation starts +using TgBotSocket::data::DownloadFile; +using TgBotSocket::data::UploadFile; +struct HashContainer { + std::array m_data; +}; + +FileDataHelper::RAIIMalloc FileDataHelper::createMemory(len_t size) { + return {malloc(size), &free}; +} + +bool FileDataHelper::writeFileCommon(const std::filesystem::path& filename, + const uint8_t* startAddr, + const len_t size) { + size_t writtenCnt = 0; + FILE* file = nullptr; + bool ret = false; + + LOG(INFO) << "Writing to file " << filename << "..."; + LOG(INFO) << "Size is " << size; + file = fopen(filename.string().c_str(), "wb"); + if (file == nullptr) { + LOG(ERROR) << "Failed to open file"; + return false; + } + writtenCnt = fwrite(startAddr, size, 1, file); + if (writtenCnt != 1) { + LOG(ERROR) << "Failed to write to file"; + } else { + LOG(INFO) << "Wrote " << size << " bytes to file " << filename; + ret = true; + } + fclose(file); + return ret; +} + +std::optional +FileDataHelper::readFileFullyCommon(const std::filesystem::path& filename) { + std::error_code errc; + FILE* file = nullptr; + const auto file_size = std::filesystem::file_size(filename, errc); + + if (errc) { + LOG(ERROR) << "Failed to get file size: " << filename << ": " + << errc.message(); + return std::nullopt; + } + file = fopen(filename.string().c_str(), "rb"); + if (file == nullptr) { + LOG(ERROR) << "Failed to fopen file: " << filename; + return std::nullopt; + } + auto dataP = createMemory(file_size); + if (fread(dataP.get(), file_size, 1, file) != 1) { + LOG(ERROR) << "Failed to read from file"; + fclose(file); + return std::nullopt; + } + fclose(file); + return ReadFileFullyRet{std::move(dataP), file_size}; +} + +inline std::ostream& operator<<(std::ostream& self, const HashContainer& data) { + for (const auto& c : data.m_data) { + self << std::hex << std::setw(2) << std::setfill('0') + << static_cast(c); + } + return self; +} + +template <> +bool FileDataHelper::DataToFile( + const void* ptr, len_t len) { + const auto* data = static_cast(ptr); + const char* filename = data->filepath.data(); + std::error_code errc; + bool exists = false; + + LOG(INFO) << "Dry run: " << filename; + LOG(INFO) << "Do I care if the file exists already? " << std::boolalpha + << !data->options.overwrite; + exists = std::filesystem::exists(filename, errc); + if (!data->options.overwrite && exists) { + LOG(WARNING) << "File already exists: " << filename; + return false; + } + + if (exists) { + HashContainer hash{}; + + if (errc) { + LOG(ERROR) << "Failed to get file size: " << filename << ": " + << errc.message(); + return false; + } + const auto result = readFileFullyCommon(filename); + if (!result) { + LOG(ERROR) << "Failed to read from file: " << filename; + return false; + } + + SHA256(static_cast(result->data.get()), + result->size, hash.m_data.data()); + if (memcmp(hash.m_data.data(), data->sha256_hash.data(), + SHA256_DIGEST_LENGTH) == 0) { + LOG(WARNING) << "File hash matches, Should I ignore? " + << std::boolalpha << data->options.hash_ignore; + if (!data->options.hash_ignore) { + return false; + } + } else { + LOG(INFO) << "File hash does not match, good"; + DLOG(INFO) << hash << " is not same as incoming " + << HashContainer(data->sha256_hash); + } + } + return true; +} + +template <> +bool FileDataHelper::DataToFile(const void* ptr, + len_t len) { + const auto* data = static_cast(ptr); + + return writeFileCommon(data->filepath.data(), &data->buf[0], + len - sizeof(UploadFile)); +} + +template <> +bool FileDataHelper::DataToFile(const void* ptr, + len_t len) { + const auto* data = static_cast(ptr); + + return writeFileCommon(data->filepath.data(), &data->buf[0], + len - sizeof(DownloadFile)); +} + +template <> +std::optional +FileDataHelper::DataFromFile( + const DataFromFileParam& params) { + const auto result = readFileFullyCommon(params.filepath); + HashContainer hash{}; + + if (!result) { + LOG(ERROR) << "Failed to read from file: " << params.filepath; + return std::nullopt; + } + // Create result packet buffer + auto resultPointer = createMemory(result->size + sizeof(UploadFile)); + // The front bytes of the buffer is UploadFile, hence cast it + auto* uploadFile = static_cast(resultPointer.get()); + // Copy destination file name info to the buffer + copyTo(uploadFile->filepath, params.destfilepath.string().c_str()); + // Copy source file data to the buffer + memcpy(&uploadFile->buf[0], result->data.get(), result->size); + // Calculate SHA256 hash + SHA256(static_cast(result->data.get()), result->size, + hash.m_data.data()); + // Copy hash to the buffer + uploadFile->sha256_hash = hash.m_data; + // Copy options to the buffer + uploadFile->options = params.options; + // Set dry run to false + uploadFile->options.dry_run = false; + + return TgBotSocket::Packet{TgBotSocket::Command::CMD_UPLOAD_FILE, + resultPointer.get(), + result->size + sizeof(UploadFile)}; +} + +template <> +std::optional +FileDataHelper::DataFromFile( + const DataFromFileParam& params) { + const auto result = readFileFullyCommon(params.filepath); + HashContainer hash{}; + + if (!result) { + LOG(ERROR) << "Failed to read from file: " << params.filepath; + return std::nullopt; + } + // Create result packet buffer + auto resultPointer = createMemory(sizeof(UploadFile)); + // The front bytes of the buffer is UploadFile, hence cast it + auto* uploadFile = static_cast(resultPointer.get()); + // Copy destination file name info to the buffer + copyTo(uploadFile->filepath, params.destfilepath.string().c_str()); + // Calculate SHA256 hash + SHA256(static_cast(result->data.get()), result->size, + hash.m_data.data()); + // Copy hash to the buffer + uploadFile->sha256_hash = hash.m_data; + // Copy options to the buffer + uploadFile->options = params.options; + // Set dry run to true + uploadFile->options.dry_run = true; + + return TgBotSocket::Packet{TgBotSocket::Command::CMD_UPLOAD_FILE_DRY, + resultPointer.get(), sizeof(UploadFile)}; +} + +// Server -> +template <> +std::optional +FileDataHelper::DataFromFile( + const DataFromFileParam& params) { + const auto result = readFileFullyCommon(params.filepath); + std::array hash{}; + + if (!result) { + LOG(ERROR) << "Failed to read from file: " << params.filepath; + return std::nullopt; + } + // Create result packet buffer + auto resultPointer = createMemory(result->size + sizeof(DownloadFile)); + // The front bytes of the buffer is UploadFile, hence cast it + auto* downloadFile = static_cast(resultPointer.get()); + // Copy destination file name info to the buffer + copyTo(downloadFile->destfilename, params.destfilepath.string().c_str()); + // Copy source file data to the buffer + memcpy(&downloadFile->buf[0], result->data.get(), result->size); + // Calculate SHA256 hash + SHA256(static_cast(result->data.get()), result->size, + hash.data()); + + return TgBotSocket::Packet{TgBotSocket::Command::CMD_DOWNLOAD_FILE_CALLBACK, + resultPointer.get(), + result->size + sizeof(DownloadFile)}; +} diff --git a/src/socket/interface/impl/bot/TgBotSocketInterface.hpp b/src/socket/interface/impl/bot/TgBotSocketInterface.hpp index 5e70e9d7..191d3b8f 100644 --- a/src/socket/interface/impl/bot/TgBotSocketInterface.hpp +++ b/src/socket/interface/impl/bot/TgBotSocketInterface.hpp @@ -11,7 +11,7 @@ #include "TgBotPacketParser.hpp" -using TgBotCommandData::GenericAck; +using TgBotSocket::callback::GenericAck; #ifdef WINDOWS_BUILD #include "impl/SocketWindows.hpp" @@ -35,14 +35,14 @@ struct SocketInterfaceTgBot : SingleThreadCtrlRunnable, } void handle_CommandPacket(SocketConnContext ctx, - TgBotCommandPacket pkt) override; + TgBotSocket::Packet pkt) override; void runFunction() override; explicit SocketInterfaceTgBot( Bot& bot, std::shared_ptr _interface); - // TODO Used by main.cpp + // TODO Used by main.cpp SocketInterfaceTgBot(Bot& bot) : BotClassBase(bot) {} private: @@ -59,7 +59,8 @@ struct SocketInterfaceTgBot : SingleThreadCtrlRunnable, static GenericAck handle_ObserveChatId(const void* ptr); static GenericAck handle_ObserveAllChats(const void* ptr); static GenericAck handle_DeleteControllerById(const void* ptr); - static GenericAck handle_UploadFile(const void *ptr, TgBotCommandPacketHeader::length_type len); + static GenericAck handle_UploadFile( + const void* ptr, TgBotSocket::PacketHeader::length_type len, bool dry); // These have their own ack handlers bool handle_GetUptime(SocketConnContext ctx, const void* ptr); diff --git a/src/socket/interface/impl/helper/SocketHelper.cpp b/src/socket/interface/impl/helper/SocketHelper.cpp index dbfab828..7bc21ab7 100644 --- a/src/socket/interface/impl/helper/SocketHelper.cpp +++ b/src/socket/interface/impl/helper/SocketHelper.cpp @@ -70,4 +70,9 @@ void SocketInterfaceBase::LocalHelper::cleanupServerSocket() { void SocketInterfaceBase::LocalHelper::doGetRemoteAddr(socket_handle_t socket) { LOG(INFO) << "Client connected via local socket"; +} + +std::filesystem::path SocketInterfaceBase::LocalHelper::getSocketPath() { + static auto spath = std::filesystem::temp_directory_path() / "tgbot.sock"; + return spath; } \ No newline at end of file diff --git a/src/socket/interface/impl/local/SocketPosixLocal.cpp b/src/socket/interface/impl/local/SocketPosixLocal.cpp index e8f7e25e..15b47269 100644 --- a/src/socket/interface/impl/local/SocketPosixLocal.cpp +++ b/src/socket/interface/impl/local/SocketPosixLocal.cpp @@ -29,8 +29,8 @@ std::optional SocketInterfaceUnixLocal::createServerSocket() { SocketConnContext ret = SocketConnContext::create(); const auto *_name = reinterpret_cast(ret.addr.get()); - setOptions(Options::DESTINATION_ADDRESS, getSocketPath().string()); - LOG(INFO) << "Creating socket at " << getSocketPath().string(); + setOptions(Options::DESTINATION_ADDRESS, LocalHelper::getSocketPath().string()); + LOG(INFO) << "Creating socket at " << LocalHelper::getSocketPath().string(); if (!createLocalSocket(&ret)) { return std::nullopt; } @@ -56,7 +56,7 @@ std::optional SocketInterfaceUnixLocal::createClientSocket() SocketConnContext ret = SocketConnContext::create(); const auto *_name = reinterpret_cast(ret.addr.get()); - setOptions(Options::DESTINATION_ADDRESS, getSocketPath().string()); + setOptions(Options::DESTINATION_ADDRESS, LocalHelper::getSocketPath().string()); if (!createLocalSocket(&ret)) { return std::nullopt; } diff --git a/src/socket/interface/impl/local/SocketWindowsLocal.cpp b/src/socket/interface/impl/local/SocketWindowsLocal.cpp index 8d78c43e..2a6aaaaa 100644 --- a/src/socket/interface/impl/local/SocketWindowsLocal.cpp +++ b/src/socket/interface/impl/local/SocketWindowsLocal.cpp @@ -31,8 +31,8 @@ std::optional SocketInterfaceWindowsLocal::createServerSocket() SocketConnContext ret = SocketConnContext::create(); const auto *_name = reinterpret_cast(ret.addr.get()); - setOptions(Options::DESTINATION_ADDRESS, getSocketPath().string()); - LOG(INFO) << "Creating socket at " << getSocketPath().string(); + setOptions(Options::DESTINATION_ADDRESS, LocalHelper::getSocketPath().string()); + LOG(INFO) << "Creating socket at " << LocalHelper::getSocketPath().string(); if (!createLocalSocket(&ret)) { return std::nullopt; } @@ -58,7 +58,7 @@ std::optional SocketInterfaceWindowsLocal::createClientSocket SocketConnContext ret = SocketConnContext::create(); const auto *_name = reinterpret_cast(ret.addr.get()); - setOptions(Options::DESTINATION_ADDRESS, getSocketPath().string()); + setOptions(Options::DESTINATION_ADDRESS, LocalHelper::getSocketPath().string()); if (!createLocalSocket(&ret)) { return std::nullopt; } diff --git a/src/socket/selector/SelectorPosix.hpp b/src/socket/selector/SelectorPosix.hpp index 1abd82aa..478a0f13 100644 --- a/src/socket/selector/SelectorPosix.hpp +++ b/src/socket/selector/SelectorPosix.hpp @@ -36,6 +36,7 @@ struct SelectSelector : Selector { std::vector data; }; +#ifdef __linux__ struct EPollSelector : Selector { bool init() override; bool add(socket_handle_t fd, OnSelectedCallback callback) override; @@ -53,3 +54,4 @@ struct EPollSelector : Selector { int epollfd; std::vector data; }; +#endif \ No newline at end of file