Skip to content

Commit

Permalink
feat: in-app update checker
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahkittyy committed Nov 1, 2022
1 parent 95be3e3 commit f7f7149
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ else()
list(APPEND flags -DSERVER_URL="http://localhost:3000")
endif()

if(APP_VERSION)
list(APPEND flags "-DAPP_TAG=${APP_VERSION}")
endif()

if(WIN32)
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/appicon.rc")
add_executable(bq-r WIN32 ${sources} ${imgui_sources} ${APP_ICON_RESOURCE_WINDOWS})
Expand Down
55 changes: 54 additions & 1 deletion game/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
#include "level.hpp"
#include "settings.hpp"

#define STRINGIFY(s) #s

api::api()
: m_cli(settings::get().server_url()) {
: m_cli(settings::get().server_url()),
m_gh_cli("https://api.github.com") {
}

api &api::get() {
Expand Down Expand Up @@ -219,6 +222,56 @@ std::future<api::response> api::upload_level(::level l, const char *title, const
});
}

const char *api::version() const {
#ifndef NDEBUG
return "vDEBUG";
#elifdef APP_TAG
return STRINGIFY(APP_TAG);
#else
return "vUNKNOWN";
#endif
}

std::future<api::update_response> api::is_up_to_date() {
std::string ctag(version());
return std::async([this, ctag]() -> api::update_response {
try {
if (auto res = m_gh_cli.Get("/repos/sarahkittyy/blockquest-remake/releases/latest")) {
nlohmann::json result = nlohmann::json::parse(res->body);
if (res->status == 200) {
return {
.success = true,
.up_to_date = ctag == result["tag_name"],
.latest_version = result["tag_name"]
};
} else {
return {
.success = false,
.error = "Invalid response from github"
};
}
} else {
throw "Could not connect to github api";
}
} catch (const char *e) {
return {
.success = false,
.error = e,
};
} catch (std::exception &e) {
return {
.success = false,
.error = e.what()
};
} catch (...) {
return {
.success = false,
.error = "Unknown error."
};
}
});
}

bool api::search_query::operator==(const search_query &other) const {
return limit == other.limit &&
query == other.query &&
Expand Down
14 changes: 14 additions & 0 deletions game/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ class api {
std::future<response> upload_level(::level l, const char* title, const char* description, bool override = false);
std::future<response> download_level(int id);

struct update_response {
bool success;
std::optional<bool> up_to_date;
std::optional<std::string> latest_version;
std::optional<std::string> error;
};

// get the current app version
const char* version() const;

// is this application up-to-date
std::future<update_response> is_up_to_date();

std::future<search_response> search_levels(search_query q);

// sends a download ping to be run when we fetch a level
Expand All @@ -66,4 +79,5 @@ class api {
api(api&& other) = delete;

httplib::Client m_cli;
httplib::Client m_gh_cli;
};
45 changes: 45 additions & 0 deletions game/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
#include "auth.hpp"
#include "debug.hpp"

#include "gui/image_text_button.hpp"
#include "imgui-SFML.h"
#include "imgui.h"

#include "states/debug.hpp"
#include "states/edit.hpp"
#include "states/search.hpp"

#include "api.hpp"
#include "util.hpp"

app::app(int argc, char** argv) {
if (!ImGui::SFML::Init(resource::get().window()))
throw "Could not initialize ImGui";
Expand Down Expand Up @@ -46,6 +53,10 @@ int app::run() {

sf::RenderWindow& win = resource::get().window();

std::future<api::update_response> version_future = api::get().is_up_to_date();
std::optional<api::update_response> version_resp;
bool version_ack = false;

// app loop
while (win.isOpen()) {
while (win.pollEvent(evt)) {
Expand All @@ -72,6 +83,40 @@ int app::run() {
// imgui rendering
m_fsm.imdraw();
debug::get().imdraw(dt);

// versioning / update stuff
if (version_future.valid() && util::ready(version_future)) {
version_resp = version_future.get();
}
if (!version_ack && version_resp.has_value()) {
if (!version_resp->success) {
ImGui::OpenPopup("Warning###UpdateWarning");
} else if (!*version_resp->up_to_date) {
ImGui::OpenPopup("A new update is available!###UpdateError");
}
}
bool dummy = true;
ImGuiWindowFlags flags = ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize;
ImGui::SetNextWindowSize(ImVec2(500, 500), ImGuiCond_Appearing);
if (ImGui::BeginPopupModal("Warning###UpdateWarning", &dummy, flags)) {
version_ack = true;
ImGui::TextWrapped("Could not run the updater - %s", version_resp->error->c_str());
ImGui::TextWrapped("Some things may not work correctly if you are on a version too old!");
ImGui::Text("Current version: %s\n", api::get().version());
if (ImGui::ImageButtonWithText(resource::get().imtex("assets/gui/yes.png"), "Ok"))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
ImGui::SetNextWindowSize(ImVec2(500, 500), ImGuiCond_Appearing);
if (ImGui::BeginPopupModal("A new update is available!###UpdateError", &dummy, flags)) {
version_ack = true;
ImGui::TextWrapped("An update from version %s to %s is available.", api::get().version(), version_resp->latest_version->c_str());
ImGui::TextWrapped("Run the game through launcher.exe to update.");
if (ImGui::ImageButtonWithText(resource::get().imtex("assets/gui/yes.png"), "Ok"))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}

ImGui::EndFrame();

win.clear(m_fsm.bg());
Expand Down
10 changes: 5 additions & 5 deletions launcher.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import requests
import readchar
import os
import sys
import shutil
import distutils.dir_util
import time

def stage1():
version_path = getattr(sys, '_MEIPASS', os.getcwd())
Expand All @@ -12,10 +12,10 @@ def stage1():
current_version = version.read().strip()

def exit_err(err):
print(f"Error: {err}")
print("Press any key to quit")
readchar.readchar()
sys.exit(-1)
print(f"Could not update: {err}")
print("Launching...")
time.sleep(1)
launch()

print(f'Current version: {current_version}\nChecking for updates...')

Expand Down

0 comments on commit f7f7149

Please sign in to comment.