MassBuilderSaveTool/src/UpdateChecker/UpdateChecker.cpp

119 lines
3.4 KiB
C++

// MassBuilderSaveTool
// Copyright (C) 2021-2023 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/Format.h>
#include <curl/curl.h>
#include "../Logger/Logger.h"
#include "UpdateChecker.h"
using namespace Corrade;
UpdateChecker::UpdateChecker() {
LOG_INFO("Initialising update checker.");
curl_global_init(CURL_GLOBAL_DEFAULT);
}
UpdateChecker::~UpdateChecker() {
LOG_INFO("Shutting libcurl down.");
curl_global_cleanup();
}
inline
std::size_t
writeCallback(char* data, std::size_t size, std::size_t nmemb, void* user_data) {
if(!data || !user_data) return std::size_t{};
auto* s = static_cast<Containers::String*>(user_data);
(*s) = (*s) + Containers::StringView{data, size * nmemb};
return size * nmemb;
}
UpdateChecker::Result
UpdateChecker::check() {
auto curl = curl_easy_init();
if(!curl) {
return Result::CurlInitFailed;
}
Containers::ScopeGuard guard(curl, curl_easy_cleanup);
Containers::String response_body{Containers::AllocatedInit, ""};
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE};
curl_easy_setopt(curl, CURLOPT_URL, "https://williamjcm.ovh/mbst/version");
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
auto code = curl_easy_perform(curl);
if(code == CURLE_OK) {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
if(status != 200) {
_error = Utility::format("The request failed with error code {}.", status);
return Result::HttpError;
}
auto parts = response_body.splitOnAnyWithoutEmptyParts("\r\n");
_foundVersion = Version{parts.front()};
_downloadLink = parts.back();
LOG_INFO_FORMAT("Found version: {}", Containers::String{_foundVersion});
return Result::Success;
}
else if(code == CURLE_OPERATION_TIMEDOUT) {
return Result::CurlTimeout;
}
else {
_error = Utility::format("{}: {}", curl_easy_strerror(code), error_buffer);
return Result::CurlError;
}
}
Containers::StringView
UpdateChecker::error() const {
return _error;
}
bool
UpdateChecker::updateAvailable() const {
return _foundVersion > current_version;
}
const Version&
UpdateChecker::version() const {
return _foundVersion;
}
Containers::StringView
UpdateChecker::downloadLink() const {
return _downloadLink;
}