This commit is contained in:
parent
f5346eddc7
commit
24b4ea6e22
@ -35,10 +35,13 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||||||
src)
|
src)
|
||||||
|
|
||||||
# Find packages
|
# Find packages
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
find_package(Drogon CONFIG REQUIRED)
|
||||||
find_package(nlohmann_json REQUIRED)
|
find_package(nlohmann_json REQUIRED)
|
||||||
|
|
||||||
# Link libraries
|
# Link libraries
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
nlohmann_json::nlohmann_json
|
nlohmann_json::nlohmann_json Drogon::Drogon
|
||||||
)
|
/usr/local/lib/libpgcommon.a /usr/local/lib/libpgport.a
|
||||||
|
lzma dl)
|
||||||
|
|
@ -1,13 +1,15 @@
|
|||||||
#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
|
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "GetbinClient.hpp"
|
#include "GetbinClient.hpp"
|
||||||
#include "httplib.hpp"
|
#include <drogon/HttpClient.h>
|
||||||
|
#include <drogon/utils/Utilities.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
@ -16,22 +18,41 @@ static constexpr const char* SERVER_HOST = "tools.dropshell.app";
|
|||||||
GetbinClient::GetbinClient() {}
|
GetbinClient::GetbinClient() {}
|
||||||
|
|
||||||
bool GetbinClient::download(const std::string& toolName, const std::string& arch, const std::string& outPath) {
|
bool GetbinClient::download(const std::string& toolName, const std::string& arch, const std::string& outPath) {
|
||||||
httplib::SSLClient cli(SERVER_HOST, 443);
|
auto client = drogon::HttpClient::newHttpClient("https://" + std::string(SERVER_HOST));
|
||||||
std::string object_path = "/object/" + toolName + ":" + arch;
|
std::string object_path = "/object/" + toolName + ":" + arch;
|
||||||
auto res = cli.Get(object_path.c_str());
|
|
||||||
if (!res || res->status != 200) {
|
auto req = drogon::HttpRequest::newHttpRequest();
|
||||||
std::cerr << "[GetbinClient::download] HTTP request failed (no response)." << std::endl;
|
req->setMethod(drogon::Get);
|
||||||
return false;
|
req->setPath(object_path);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
client->sendRequest(req, [&](drogon::ReqResult result, const drogon::HttpResponsePtr& response) {
|
||||||
|
if (result != drogon::ReqResult::Ok || !response || response->getStatusCode() != drogon::k200OK) {
|
||||||
|
std::cerr << "[GetbinClient::download] HTTP request failed." << std::endl;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream ofs(outPath, std::ios::binary);
|
std::ofstream ofs(outPath, std::ios::binary);
|
||||||
if (!ofs) return false;
|
if (!ofs) return;
|
||||||
ofs.write(res->body.data(), res->body.size());
|
|
||||||
return ofs.good();
|
const auto& body = response->getBody();
|
||||||
|
ofs.write(body.data(), body.size());
|
||||||
|
success = ofs.good();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the async request to complete
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
while (!success) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
// Add timeout logic here if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetbinClient::upload(const std::string& archivePath, std::string& outUrl, std::string& outHash, const std::string& token) {
|
bool GetbinClient::upload(const std::string& archivePath, std::string& outUrl, std::string& outHash, const std::string& token) {
|
||||||
httplib::SSLClient cli(SERVER_HOST,443);
|
auto client = drogon::HttpClient::newHttpClient("https://" + std::string(SERVER_HOST));
|
||||||
httplib::MultipartFormDataItems items;
|
|
||||||
// Read file
|
// Read file
|
||||||
std::ifstream ifs(archivePath, std::ios::binary);
|
std::ifstream ifs(archivePath, std::ios::binary);
|
||||||
if (!ifs) {
|
if (!ifs) {
|
||||||
@ -39,6 +60,7 @@ bool GetbinClient::upload(const std::string& archivePath, std::string& outUrl, s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::string file_content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
std::string file_content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
// Compose metadata (minimal, can be extended)
|
// Compose metadata (minimal, can be extended)
|
||||||
json metadata = { {"labeltags", json::array()} };
|
json metadata = { {"labeltags", json::array()} };
|
||||||
// Try to extract tool:arch from filename
|
// Try to extract tool:arch from filename
|
||||||
@ -46,56 +68,101 @@ bool GetbinClient::upload(const std::string& archivePath, std::string& outUrl, s
|
|||||||
size_t dot = filename.find('.');
|
size_t dot = filename.find('.');
|
||||||
std::string labeltag = dot != std::string::npos ? filename.substr(0, dot) : filename;
|
std::string labeltag = dot != std::string::npos ? filename.substr(0, dot) : filename;
|
||||||
metadata["labeltags"].push_back(labeltag);
|
metadata["labeltags"].push_back(labeltag);
|
||||||
items.push_back({"file", file_content, filename, "application/gzip"});
|
|
||||||
items.push_back({"metadata", metadata.dump(), "", "application/json"});
|
|
||||||
httplib::Headers headers = { {"Authorization", "Bearer " + token} };
|
|
||||||
|
|
||||||
//cli.enable_server_certificate_verification(false); // TEMPORARY
|
// Create request with raw body upload (simplified approach)
|
||||||
cli.set_ca_cert_path("/etc/ssl/certs/ca-certificates.crt");
|
auto req = drogon::HttpRequest::newHttpRequest();
|
||||||
auto res = cli.Put("/upload", headers, items);
|
req->setMethod(drogon::Put);
|
||||||
if (!res) {
|
req->setPath("/upload");
|
||||||
|
req->addHeader("Authorization", "Bearer " + token);
|
||||||
|
req->addHeader("Content-Type", "application/gzip");
|
||||||
|
req->addHeader("X-Metadata", metadata.dump());
|
||||||
|
req->setBody(file_content);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
std::string response_body;
|
||||||
|
int status_code = 0;
|
||||||
|
|
||||||
|
client->sendRequest(req, [&](drogon::ReqResult result, const drogon::HttpResponsePtr& response) {
|
||||||
|
if (result != drogon::ReqResult::Ok || !response) {
|
||||||
std::cerr << "[GetbinClient::upload] HTTP request failed (no response)." << std::endl;
|
std::cerr << "[GetbinClient::upload] HTTP request failed (no response)." << std::endl;
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (res->status != 200 && res->status != 201) {
|
|
||||||
std::cerr << "[GetbinClient::upload] HTTP error: status code " << res->status << std::endl;
|
status_code = static_cast<int>(response->getStatusCode());
|
||||||
std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl;
|
response_body = response->getBody();
|
||||||
return false;
|
|
||||||
|
if (status_code != 200 && status_code != 201) {
|
||||||
|
std::cerr << "[GetbinClient::upload] HTTP error: status code " << status_code << std::endl;
|
||||||
|
std::cerr << "[GetbinClient::upload] Response body: " << response_body << std::endl;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse response for URL/hash
|
// Parse response for URL/hash
|
||||||
try {
|
try {
|
||||||
auto resp_json = json::parse(res->body);
|
auto resp_json = json::parse(response_body);
|
||||||
if (resp_json.contains("url")) outUrl = resp_json["url"].get<std::string>();
|
if (resp_json.contains("url")) outUrl = resp_json["url"].get<std::string>();
|
||||||
if (resp_json.contains("hash")) outHash = resp_json["hash"].get<std::string>();
|
if (resp_json.contains("hash")) outHash = resp_json["hash"].get<std::string>();
|
||||||
|
success = true;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
std::cerr << "[GetbinClient::upload] Failed to parse JSON response: " << e.what() << std::endl;
|
std::cerr << "[GetbinClient::upload] Failed to parse JSON response: " << e.what() << std::endl;
|
||||||
std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl;
|
std::cerr << "[GetbinClient::upload] Response body: " << response_body << std::endl;
|
||||||
return false;
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
std::cerr << "[GetbinClient::upload] Unknown error while parsing JSON response." << std::endl;
|
std::cerr << "[GetbinClient::upload] Unknown error while parsing JSON response." << std::endl;
|
||||||
std::cerr << "[GetbinClient::upload] Response body: " << res->body << std::endl;
|
std::cerr << "[GetbinClient::upload] Response body: " << response_body << std::endl;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
});
|
||||||
|
|
||||||
|
// Wait for the async request to complete
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
while (!success && status_code == 0) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
// Add timeout logic here if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetbinClient::getHash(const std::string& toolName, const std::string& arch, std::string& outHash) {
|
bool GetbinClient::getHash(const std::string& toolName, const std::string& arch, std::string& outHash) {
|
||||||
httplib::SSLClient cli(SERVER_HOST, 443);
|
auto client = drogon::HttpClient::newHttpClient("https://" + std::string(SERVER_HOST));
|
||||||
std::string exists_path = "/exists/" + toolName + ":" + arch;
|
std::string exists_path = "/exists/" + toolName + ":" + arch;
|
||||||
auto res = cli.Get(exists_path.c_str());
|
|
||||||
if (!res || res->status != 200) return false;
|
auto req = drogon::HttpRequest::newHttpRequest();
|
||||||
|
req->setMethod(drogon::Get);
|
||||||
|
req->setPath(exists_path);
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
std::string response_body;
|
||||||
|
|
||||||
|
client->sendRequest(req, [&](drogon::ReqResult result, const drogon::HttpResponsePtr& response) {
|
||||||
|
if (result != drogon::ReqResult::Ok || !response || response->getStatusCode() != drogon::k200OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response_body = response->getBody();
|
||||||
|
|
||||||
// Try to parse hash from response body (assume plain text or JSON)
|
// Try to parse hash from response body (assume plain text or JSON)
|
||||||
try {
|
try {
|
||||||
// Try JSON
|
// Try JSON
|
||||||
auto resp_json = json::parse(res->body);
|
auto resp_json = json::parse(response_body);
|
||||||
if (resp_json.contains("hash")) {
|
if (resp_json.contains("hash")) {
|
||||||
outHash = resp_json["hash"].get<std::string>();
|
outHash = resp_json["hash"].get<std::string>();
|
||||||
return true;
|
success = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// Not JSON, treat as plain text
|
// Not JSON, treat as plain text
|
||||||
outHash = res->body;
|
outHash = response_body;
|
||||||
return !outHash.empty();
|
success = !outHash.empty();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return false;
|
});
|
||||||
|
|
||||||
|
// Wait for the async request to complete
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
while (!success && response_body.empty()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
// Add timeout logic here if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user