#include "stdafx.h" #include "SiaCurl.h" #include using namespace Sia::Api; CSiaCurl::CSiaCurl() : _curlHandle(curl_easy_init()) { SetHostConfig({ L"localhost", 9980, L""}); } CSiaCurl::CSiaCurl(const SiaHostConfig& hostConfig) : _curlHandle(curl_easy_init()) { SetHostConfig(hostConfig); } CSiaCurl::~CSiaCurl() { curl_easy_cleanup(_curlHandle); } SiaCurlError CSiaCurl::CheckApiError(const json& result) { SiaCurlError ret = SiaCurlError::Success; if (result.find("message") != result.end()) { ret = SiaCurlError::UnknownFailure; const std::string msg = result["message"].get(); if ((msg.length() >= 3)) { if ((msg.substr(0, 3) == "404")) { ret = SiaCurlError::InvalidRequestPath; } } } return ret; } std::string CSiaCurl::ConstructPath(const String& relativePath) const { const std::string ret = "http://" + std::string(CW2A(GetHostConfig().HostName.c_str())) + ":" + std::to_string(GetHostConfig().HostPort) + std::string(CW2A(relativePath.c_str())); return ret; } SiaCurlError CSiaCurl::CheckHttpError(const std::string& result) { if (result.length() && ((result.length() < 2) || (result[0] != '{'))) { return SiaCurlError::HttpError; } return SiaCurlError::Success; } SiaCurlError CSiaCurl::ProcessResponse(const int& res, const std::string& result, json& response) const { SiaCurlError ret; if (res == CURLE_OK) { ret = CheckHttpError(result); if (API_SUCCESS(SiaCurlError, ret)) { ret = (result.length() ? CheckApiError((response = json::parse(result.c_str()))) : SiaCurlError::Success); } } else { if ((res == CURLE_COULDNT_RESOLVE_HOST) || (res == CURLE_COULDNT_CONNECT)) { ret = SiaCurlError::NoResponse; } else { ret = SiaCurlError::UnknownFailure; } } return ret; } SiaCurlError CSiaCurl::_Get(const String& path, json& response) const { curl_easy_reset(_curlHandle); curl_easy_setopt(_curlHandle, CURLOPT_USERAGENT, "Sia-Agent"); curl_easy_setopt(_curlHandle, CURLOPT_URL, ConstructPath(path).c_str()); curl_easy_setopt(_curlHandle, CURLOPT_WRITEFUNCTION, static_cast([](char *buffer, size_t size, size_t nitems, void *outstream) -> size_t { (*reinterpret_cast(outstream)) += std::string(reinterpret_cast(buffer), size * nitems); return size * nitems; })); std::string result; curl_easy_setopt(_curlHandle, CURLOPT_WRITEDATA, &result); const CURLcode res = curl_easy_perform(_curlHandle); return ProcessResponse(res, result, response); } bool CSiaCurl::CheckVersion(SiaCurlError& error) const { error = SiaCurlError::InvalidRequiredVersion; if (GetHostConfig().RequiredVersion.length()) { error = SiaCurlError::NoResponse; const String serverVersion = GetServerVersion(); if (serverVersion.length()) { error = (serverVersion == GetHostConfig().RequiredVersion) ? SiaCurlError::Success : SiaCurlError::ServerVersionMismatch; } } return API_SUCCESS(SiaCurlError, error); } String CSiaCurl::GetServerVersion() const { json response; if (API_SUCCESS(SiaCurlError, _Get(L"/daemon/version", response))) { return String(CA2W(response["version"].get().c_str())); } return L""; } SiaCurlError CSiaCurl::Get(const String& path, json& response) const { SiaCurlError ret; if (CheckVersion(ret)) { ret = _Get(path, response); } return ret; } SiaCurlError CSiaCurl::Post(const String& path, const PostParameters& parameters, json& response) const { SiaCurlError ret; if (CheckVersion(ret)) { curl_easy_reset(_curlHandle); curl_easy_setopt(_curlHandle, CURLOPT_USERAGENT, "Sia-Agent"); curl_easy_setopt(_curlHandle, CURLOPT_URL, ConstructPath(path).c_str()); curl_easy_setopt(_curlHandle, CURLOPT_WRITEFUNCTION, static_cast([](char *buffer, size_t size, size_t nitems, void *outstream) -> size_t { (*reinterpret_cast(outstream)) += std::string(reinterpret_cast(buffer), size * nitems); return size * nitems; })); std::string fields; for (const auto& param : parameters) { if (fields.length()) { fields += "&"; } fields += (std::string(CW2A(param.first.c_str())) + "=" + std::string(CW2A(param.second.c_str()))); } curl_easy_setopt(_curlHandle, CURLOPT_POSTFIELDS, fields.c_str()); std::string result; curl_easy_setopt(_curlHandle, CURLOPT_WRITEDATA, &result); const CURLcode res = curl_easy_perform(_curlHandle); ret = ProcessResponse(res, result, response); } return ret; }