Skip to content

Commit

Permalink
socket: Implement TRANSFER_FILE JSON mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Royna2544 committed Dec 19, 2024
1 parent 97d3f67 commit 0e8b3a9
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 169 deletions.
24 changes: 0 additions & 24 deletions src/database/utils/SendMediaToChat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,6 @@
exit(exitCode);
}

std::optional<Json::Value> parseAndCheck(
const void* buf, TgBotSocket::Packet::Header::length_type length,
const std::initializer_list<const char*> nodes) {
Json::Value root;
Json::Reader reader;
if (!reader.parse(std::string(static_cast<const char*>(buf), length),
root)) {
LOG(WARNING) << "Failed to parse json: "
<< reader.getFormattedErrorMessages();
return std::nullopt;
}
if (!root.isObject()) {
LOG(WARNING) << "Expected an object in json";
return std::nullopt;
}
for (const auto& node : nodes) {
if (!root.isMember(node)) {
LOG(WARNING) << fmt::format("Missing node '{}' in json", node);
return std::nullopt;
}
}
return root;
}

int main(int argc, char** argv) {
ChatId chatId = 0;
TgBotSocket::data::SendFileToChatId data = {};
Expand Down
10 changes: 5 additions & 5 deletions src/include/SharedMalloc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ struct SharedMalloc {
* memory.
*/
template <typename T>
void assignTo(T &ref, const size_t offset) const {
void assignTo(T &ref, const size_t offset = 0) const {
assignTo(&ref, sizeof(T), offset);
}

Expand All @@ -165,8 +165,8 @@ struct SharedMalloc {
*/
template <typename T>
requires(!std::is_pointer_v<T>)
void assignTo(T &ref) const {
assignTo(&ref, sizeof(T));
void assignTo(T &ref, const size_t offset = 0) const {
assignTo(&ref, sizeof(T), offset);
}

/**
Expand All @@ -181,12 +181,12 @@ struct SharedMalloc {
*/
template <typename T>
requires(!std::is_pointer_v<T>)
void assignFrom(const T &ref) {
void assignFrom(const T &ref, const size_t offset = 0) {
if (sizeof(T) > size()) {
throw std::out_of_range(
"Operation size exceeds allocated memory size");
}
assignFrom(&ref, sizeof(T));
assignFrom(&ref, sizeof(T), offset);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/socket/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ add_my_library(
backends/ClientBackend.cpp
TgBotCommandMap.cpp
PUBLIC_INC interface
LIBS Utils Boost::system OpenSSL::Crypto
LIBS Utils Boost::system OpenSSL::Crypto JsonCpp::JsonCpp
LIBS_WIN32 wsock32 Ws2_32
)

add_my_executable(
NAME SocketCli
SRCS TgBotSocketClient.cpp
LIBS Socket JsonCpp::JsonCpp
LIBS Socket
RELATION Socket
)

Expand Down
161 changes: 118 additions & 43 deletions src/socket/TgBotSocketClient.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <absl/log/log.h>
#include <json/json.h>
#include <openssl/sha.h>

#include <AbslLogInit.hpp>
#include <ManagedThreads.hpp>
Expand Down Expand Up @@ -80,6 +80,20 @@ std::string_view AckTypeToStr(callback::AckType type) {

} // namespace

std::optional<Packet::Header::length_type> findBorderOffset(
const void* buffer, Packet::Header::length_type size) {
const auto* iter = static_cast<const uint8_t*>(buffer);
Packet::Header::length_type offset = 0;
for (Packet::Header::length_type i = 0; i < size; ++i) {
if (iter[i] == data::JSON_BYTE_BORDER) {
LOG(INFO) << "Found JSON_BYTE_BORDER in offset " << i;
return i;
}
}
LOG(WARNING) << "JSON_BYTE_BORDER not found in buffer";
return std::nullopt;
}

void handleCallback(SocketClientWrapper& connector, const Packet& pkt) {
using callback::AckType;
using callback::GenericAck;
Expand All @@ -96,25 +110,110 @@ void handleCallback(SocketClientWrapper& connector, const Packet& pkt) {
break;
}
case Command::CMD_TRANSFER_FILE: {
data::FileTransferMeta meta;
pkt.data.assignTo(meta);
SocketFile2DataHelper::Params params;
params.filepath = meta.srcfilepath.data();
params.destfilepath = meta.destfilepath.data();
params.options = meta.options;
params.hash = meta.sha256_hash;
params.file_size = pkt.data.size() - sizeof(meta);
params.filebuffer = reinterpret_cast<const uint8_t*>(static_cast<const char *>(pkt.data.get()) + sizeof(meta));
helper.ReceiveTransferMeta(params);
SocketFile2DataHelper::Params result;
switch (pkt.header.data_type) {
case PayloadType::Binary: {
if (pkt.data.size() < sizeof(data::FileTransferMeta)) {
DLOG(WARNING)
<< "Payload size mismatch on UploadFileMeta";
return;
}
{
const auto* data =
static_cast<const data::FileTransferMeta*>(
pkt.data.get());
result.filepath = safeParse(data->srcfilepath);
result.destfilepath = safeParse(data->destfilepath);
result.options = data->options;
result.hash = data->sha256_hash;
result.file_size =
pkt.data.size() - sizeof(data::FileTransferMeta);
result.filebuffer = reinterpret_cast<const uint8_t*>(
static_cast<const char*>(pkt.data.get()) +
sizeof(data::FileTransferMeta));
}
break;
}
case PayloadType::Json: {
const auto offset =
findBorderOffset(pkt.data.get(), pkt.data.size())
.value_or(pkt.data.size());
std::string json(static_cast<const char*>(pkt.data.get()),
offset);
auto _root = parseAndCheck(pkt.data.get(), pkt.data.size(),
{"srcfilepath", "destfilepath"});
if (!_root) {
return;
}
auto& root = _root.value();
result.filepath = root["srcfilepath"].asString();
result.destfilepath = root["destfilepath"].asString();
data::FileTransferMeta::Options options;
options.overwrite = root["options"]["overwrite"].asBool();
options.hash_ignore =
root["options"]["hash_ignore"].asBool();
options.dry_run = root["options"]["dry_run"].asBool();
if (!options.hash_ignore && !root.isMember("hash")) {
LOG(WARNING) << "hash_ignore is false, but hash is not "
"provided.";
return;
}
if (root.isMember("hash")) {
auto parsed = hexDecode<SHA256_DIGEST_LENGTH>(
root["hash"].asString());
if (!parsed) {
return;
}
result.hash = parsed.value();
}
result.file_size = pkt.data.size() - offset;
result.filebuffer =
static_cast<const std::uint8_t*>(pkt.data.get()) +
offset;
break;
}
default:
LOG(ERROR) << "Invalid payload type for TransferFileMeta";
return;
}
helper.ReceiveTransferMeta(result);
break;
}
case Command::CMD_GENERIC_ACK: {
callback::GenericAck callbackData{};
pkt.data.assignTo(callbackData);
LOG(INFO) << "Response from server: "
<< AckTypeToStr(callbackData.result);
if (callbackData.result != AckType::SUCCESS) {
LOG(ERROR) << "Reason: " << callbackData.error_msg.data();
switch (pkt.header.data_type) {
case PayloadType::Binary: {
callback::GenericAck callbackData{};
pkt.data.assignTo(callbackData);
LOG(INFO) << "Response from server: "
<< AckTypeToStr(callbackData.result);
if (callbackData.result != AckType::SUCCESS) {
LOG(ERROR)
<< "Reason: " << callbackData.error_msg.data();
}
break;
}
case PayloadType::Json: {
auto root = parseAndCheck(pkt.data.get(), pkt.data.size(),
{"result"});
if (!root) {
LOG(ERROR) << "Invalid json in generic ack";
return;
}
auto result = (*root)["result"].asBool();
if (result) {
LOG(INFO) << "Response from server: Success";
} else {
LOG(ERROR) << "Response from server: Failed";
LOG(ERROR)
<< "Reason: " << (*root)["error_msg"].asString();
LOG(ERROR) << "Error type: "
<< (*root)["error_type"].asString();
}
break;
}
default:
LOG(ERROR) << "Unhandled payload type for generic ack";
break;
}
break;
}
Expand All @@ -125,30 +224,6 @@ void handleCallback(SocketClientWrapper& connector, const Packet& pkt) {
}
}

std::optional<Json::Value> parseAndCheck(
const void* buf, TgBotSocket::Packet::Header::length_type length,
const std::initializer_list<const char*> nodes) {
Json::Value root;
Json::Reader reader;
if (!reader.parse(std::string(static_cast<const char*>(buf), length),
root)) {
LOG(WARNING) << "Failed to parse json: "
<< reader.getFormattedErrorMessages();
return std::nullopt;
}
if (!root.isObject()) {
LOG(WARNING) << "Expected an object in json";
return std::nullopt;
}
for (const auto& node : nodes) {
if (!root.isMember(node)) {
LOG(WARNING) << fmt::format("Missing node '{}' in json", node);
return std::nullopt;
}
}
return root;
}

template <typename T>
std::optional<T> parseArgs(char** argv) = delete;

Expand Down Expand Up @@ -277,7 +352,7 @@ int main(int argc, char** argv) {
}
auto root = *_root;
LOG(INFO) << "Opened session. Token: " << root["session_token"]
<< " expiration_time: " << root["expiration_time"];
<< " Expiration_time: " << root["expiration_time"];

std::string session_token_str = root["session_token"].asString();
if (session_token_str.size() != Packet::Header::SESSION_TOKEN_LENGTH) {
Expand Down Expand Up @@ -353,7 +428,7 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
pkt = helper.CreateTransferMeta(
args.value(), session_token,
args.value(), session_token, PayloadType::Json,
cmd == Command::CMD_TRANSFER_FILE_REQUEST);
break;
}
Expand Down
Loading

0 comments on commit 0e8b3a9

Please sign in to comment.