From 353277a86c7dcf574dfd81617684fce275ed985e Mon Sep 17 00:00:00 2001 From: royna2544 Date: Wed, 18 Dec 2024 23:09:50 +0900 Subject: [PATCH] socket: Document JSON api And add CMD_GET_UPTIME_CALLBACK's JSON format --- src/socket/TgBotSocket_Export.hpp | 73 +++++++++++++++++++++++----- src/socket/bot/SocketDataHandler.cpp | 41 ++++++++++++---- src/socket/bot/SocketInterface.hpp | 6 ++- 3 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/socket/TgBotSocket_Export.hpp b/src/socket/TgBotSocket_Export.hpp index ae0f0070..aafc9f7f 100644 --- a/src/socket/TgBotSocket_Export.hpp +++ b/src/socket/TgBotSocket_Export.hpp @@ -155,23 +155,62 @@ enum class CtrlSpamBlock { MAX, }; +/** + * CMD_WRITE_MESSAGE_TO_CHAT's data structure + * + * JSON schema: + * { + * "chat": int64, + * "message": string + * } + */ struct alignas(ALIGNMENT) WriteMsgToChatId { ChatId chat; // destination chatid MessageStringArray message; // Msg to send }; + +/** + * CMD_OBSERVE_CHAT_ID's data structure + * + * JSON schema: + * { + * "chat": int64, + * "observe": True/False + * } + */ struct alignas(ALIGNMENT) ObserveChatId { ChatId chat; bool observe; // new state for given ChatId, // true/false - Start/Stop observing }; + +/** + * CMD_SEND_FILE_TO_CHAT's data structure + * + * JSON schema: + * { + * "chat": int64, + * "fileType": TgBotSocket::data::FileType value as int (TODO: Make it string representation), + * "filePath": string + * } + */ + struct alignas(ALIGNMENT) SendFileToChatId { ChatId chat; // Destination ChatId FileType fileType; // File type for file alignas(ALIGNMENT) PathStringArray filePath; // Path to file (local) }; +/** + * CMD_OBSERVE_ALL_CHATS data structure. + * + * JSON schema: + * { + * "observe": True/False + * } + */ struct alignas(ALIGNMENT) ObserveAllChats { bool observe; // new state for all chats, // true/false - Start/Stop observing @@ -226,6 +265,16 @@ struct alignas(ALIGNMENT) DownloadFile : DownloadFileMeta { namespace callback { +/** + * CMD_GET_UPTIME's callback data structure + * + * JSON schema: + * { + * "start_time": timestamp + * "current_time": timestamp + * "uptime": string (format: "Uptime: 999h 99m 99s") + * } + */ struct alignas(ALIGNMENT) GetUptimeCallback { std::array uptime; }; @@ -239,6 +288,17 @@ enum class AckType { ERROR_CLIENT_ERROR, }; +/** + * GenericAck's JSON schema: + * { + * "result": True|False + * "__comment__": "Below two fields are optional" + * "error_type": + * "TGAPI_EXCEPTION"|"INVALID_ARGUMENT"|"COMMAND_IGNORED"|"RUNTIME_ERROR"|"CLIENT_ERROR", + * "error_msg": "Error message" + * } + */ + struct alignas(ALIGNMENT) GenericAck { AckType result{}; // result type // Error message, only valid when result type is not SUCCESS @@ -247,7 +307,7 @@ struct alignas(ALIGNMENT) GenericAck { // Create a new instance of the Generic Ack, error. explicit GenericAck(AckType result, const std::string& errorMsg) : result(result) { - copyTo(error_msg, errorMsg.c_str()); + copyTo(error_msg, errorMsg); } GenericAck() = default; @@ -255,17 +315,6 @@ struct alignas(ALIGNMENT) GenericAck { static GenericAck ok() { return GenericAck(AckType::SUCCESS, "OK"); } }; -/** - * GenericAck's JSON schema: - * { - * "result": True|False - * "__comment__": "Below two fields are optional" - * "error_type": - * "TGAPI_EXCEPTION"|"INVALID_ARGUMENT"|"COMMAND_IGNORED"|"RUNTIME_ERROR"|"CLIENT_ERROR", - * "error_msg": "Error message" - * } - */ - struct alignas(ALIGNMENT) UploadFileDryCallback : public GenericAck { data::UploadFileMeta requestdata; }; diff --git a/src/socket/bot/SocketDataHandler.cpp b/src/socket/bot/SocketDataHandler.cpp index 7d4349cd..7e49aa1e 100644 --- a/src/socket/bot/SocketDataHandler.cpp +++ b/src/socket/bot/SocketDataHandler.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -439,7 +438,10 @@ GenericAck SocketInterfaceTgBot::handle_ObserveAllChats( const void* ptr, TgBotSocket::Packet::Header::length_type len, TgBotSocket::PayloadType type) { auto data = ObserveAllChats::fromBuffer(ptr, len, type); - observer->observeAll(static_cast(ptr)->observe); + if (!data) { + return GenericAck(AckType::ERROR_INVALID_ARGUMENT, "Invalid command"); + } + observer->observeAll(data->observe); return GenericAck::ok(); } @@ -490,15 +492,35 @@ bool SocketInterfaceTgBot::handle_DownloadFile( bool SocketInterfaceTgBot::handle_GetUptime( const TgBotSocket::Context& ctx, - const TgBotSocket::Packet::Header::session_token_type& token) { + const TgBotSocket::Packet::Header::session_token_type& token, + TgBotSocket::PayloadType type) { auto now = std::chrono::system_clock::now(); const auto diff = to_secs(now - startTp); - GetUptimeCallback callback{}; - copyTo(callback.uptime, fmt::format("Uptime: {:%H:%M:%S}", diff).c_str()); - LOG(INFO) << "Sending text back: " << std::quoted(callback.uptime.data()); - ctx.write(createPacket(Command::CMD_GET_UPTIME_CALLBACK, &callback, - sizeof(callback), PayloadType::Binary, token)); + switch (type) { + case PayloadType::Binary: { + GetUptimeCallback callback{}; + copyTo(callback.uptime, fmt::format("Uptime: {:%H:%M:%S}", diff)); + LOG(INFO) << "Sending text back: " + << std::quoted(callback.uptime.data()); + ctx.write(createPacket(Command::CMD_GET_UPTIME_CALLBACK, &callback, + sizeof(callback), PayloadType::Binary, + token)); + } break; + case PayloadType::Json: { + Json::Value payload; + payload["start_time"] = fmt::format("{}", startTp); + payload["current_time"] = fmt::format("{}", now); + payload["uptime"] = fmt::format("{:%Hh %Mm %Ss}", diff); + LOG(INFO) << "Sending JSON back: " << payload.toStyledString(); + ctx.write( + nodeToPacket(Command::CMD_GET_UPTIME_CALLBACK, payload, token)); + } break; + default: + LOG(WARNING) << "Unsupported payload type: " + << static_cast(type); + return false; + } return true; } @@ -605,7 +627,8 @@ void SocketInterfaceTgBot::handlePacket(const TgBotSocket::Context& ctx, pkt.header.data_type); break; case Command::CMD_GET_UPTIME: - ret = handle_GetUptime(ctx, pkt.header.session_token); + ret = handle_GetUptime(ctx, pkt.header.session_token, + pkt.header.data_type); break; case Command::CMD_UPLOAD_FILE: ret = handle_UploadFile(ptr, pkt.header.data_size); diff --git a/src/socket/bot/SocketInterface.hpp b/src/socket/bot/SocketInterface.hpp index ccef9fc7..df4e27a3 100644 --- a/src/socket/bot/SocketInterface.hpp +++ b/src/socket/bot/SocketInterface.hpp @@ -67,13 +67,15 @@ struct SocketInterfaceTgBot : ThreadRunner { // These have their own ack handlers bool handle_GetUptime( const TgBotSocket::Context& ctx, - const TgBotSocket::Packet::Header::session_token_type& token); + const TgBotSocket::Packet::Header::session_token_type& token, + TgBotSocket::PayloadType type); bool handle_DownloadFile( const TgBotSocket::Context& ctx, const void* ptr, const TgBotSocket::Packet::Header::session_token_type& token); void handle_OpenSession(const TgBotSocket::Context& ctx); - void handle_CloseSession(const TgBotSocket::Packet::Header::session_token_type& token); + void handle_CloseSession( + const TgBotSocket::Packet::Header::session_token_type& token); bool verifyHeader(const TgBotSocket::Packet& packet); };