162 lines
6 KiB
C++
162 lines
6 KiB
C++
// MassBuilderSaveTool
|
|
// Copyright (C) 2021-2022 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/Utility/Format.h>
|
|
|
|
#include <curl/curl.h>
|
|
|
|
#include "SaveTool.h"
|
|
|
|
void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|
_updateThread.join();
|
|
|
|
if(event.user.code == CurlInitFailed) {
|
|
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
|
|
return;
|
|
}
|
|
else if(event.user.code == CurlError) {
|
|
Containers::String error{static_cast<char*>(event.user.data2), CURL_ERROR_SIZE, nullptr};
|
|
_queue.addToast(Toast::Type::Error, error, std::chrono::milliseconds{5000});
|
|
_queue.addToast(Toast::Type::Error, static_cast<char*>(event.user.data1), std::chrono::milliseconds{5000});
|
|
return;
|
|
}
|
|
else if(event.user.code == CurlTimeout) {
|
|
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
|
return;
|
|
}
|
|
else if(event.user.code != 200) {
|
|
_queue.addToast(Toast::Type::Error, Utility::format("The request failed with error code {}", event.user.code));
|
|
return;
|
|
}
|
|
|
|
struct Version {
|
|
explicit Version(Containers::StringView str) {
|
|
std::size_t start_point = 0;
|
|
|
|
if(str[0] == 'v') {
|
|
start_point++;
|
|
}
|
|
|
|
auto components = Containers::StringView{str.data() + start_point}.split('.');
|
|
|
|
major = std::strtol(components[0].data(), nullptr, 10);
|
|
minor = std::strtol(components[1].data(), nullptr, 10);
|
|
patch = std::strtol(components[2].data(), nullptr, 10);
|
|
|
|
fullVersion = major * 10000 + minor * 100 + patch;
|
|
|
|
if(str.hasSuffix("-pre")) {
|
|
prerelease = true;
|
|
}
|
|
}
|
|
Int fullVersion;
|
|
Int major = 0;
|
|
Int minor = 0;
|
|
Int patch = 0;
|
|
bool prerelease = false;
|
|
|
|
bool operator==(const Version& other) const {
|
|
return fullVersion == other.fullVersion;
|
|
}
|
|
bool operator>(const Version& other) const {
|
|
if((fullVersion > other.fullVersion) ||
|
|
(fullVersion == other.fullVersion && prerelease == false && other.prerelease == true))
|
|
{
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
operator Containers::String() const {
|
|
return Utility::format("{}.{}.{}{}", major, minor, patch, prerelease ? "-pre" : "");
|
|
}
|
|
};
|
|
|
|
static const Version current_ver{SAVETOOL_VERSION};
|
|
|
|
Containers::String response{static_cast<char*>(event.user.data1), strlen(static_cast<char*>(event.user.data1)), nullptr};
|
|
auto components = response.split('\n');
|
|
|
|
Version latest_ver{components.front()};
|
|
|
|
if(latest_ver > current_ver) {
|
|
_queue.addToast(Toast::Type::Warning, "Your version is out of date.\nCheck the settings for more information."_s,
|
|
std::chrono::milliseconds{5000});
|
|
_updateAvailable = true;
|
|
_latestVersion = latest_ver;
|
|
_releaseLink = Utility::format("https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases/tag/v{}", components.front());
|
|
_downloadLink = components.back();
|
|
}
|
|
else if(latest_ver == current_ver || (current_ver > latest_ver && current_ver.prerelease == true)) {
|
|
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
|
|
}
|
|
else if(current_ver > latest_ver && current_ver.prerelease == false) {
|
|
_queue.addToast(Toast::Type::Warning, "Your version is more recent than the latest one in the repo. How???"_s);
|
|
}
|
|
}
|
|
|
|
inline auto writeData(char* ptr, std::size_t size, std::size_t nmemb, Containers::String* buf)-> std::size_t {
|
|
if(!ptr || !buf) return 0;
|
|
(*buf) = Utility::format("{}{}", *buf, Containers::StringView{ptr, size * nmemb});
|
|
return size * nmemb;
|
|
}
|
|
|
|
void SaveTool::checkForUpdates() {
|
|
SDL_Event event;
|
|
SDL_zero(event);
|
|
event.type = _updateEventId;
|
|
|
|
auto curl = curl_easy_init();
|
|
if(!curl) {
|
|
event.user.code = CurlInitFailed;
|
|
}
|
|
|
|
if(curl) {
|
|
Containers::String response_body{Containers::AllocatedInit, ""};
|
|
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE * 2};
|
|
|
|
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, writeData);
|
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
|
|
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
|
|
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
|
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 10000L);
|
|
|
|
auto code = curl_easy_perform(curl);
|
|
|
|
if(code == CURLE_OK) {
|
|
long status = 0;
|
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
|
event.user.code = Int(status);
|
|
event.user.data1 = response_body.release();
|
|
}
|
|
else if(code == CURLE_OPERATION_TIMEDOUT) {
|
|
event.user.code = CurlTimeout;
|
|
}
|
|
else {
|
|
event.user.code = CurlError;
|
|
event.user.data1 = const_cast<char*>(curl_easy_strerror(code));
|
|
event.user.data2 = Containers::String{error_buffer}.release();
|
|
}
|
|
|
|
curl_easy_cleanup(curl);
|
|
}
|
|
|
|
SDL_PushEvent(&event);
|
|
}
|