Skip to content

Commit

Permalink
Server: Implement daily autoupdates.
Browse files Browse the repository at this point in the history
  • Loading branch information
geneotech committed Oct 11, 2023
1 parent cfec32d commit 67d8736
Show file tree
Hide file tree
Showing 22 changed files with 281 additions and 45 deletions.
3 changes: 3 additions & 0 deletions docs/pages/todo/brainstorm_now.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ permalink: brainstorm_now
summary: That which we are brainstorming at the moment.
---

- Less round time on small maps to increase tension on T side
- e.g. on duel practice

- Net stats not measured for some reason

- Server administration
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/todo/todo_low.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ hide_sidebar: true
permalink: todo_low
---

- wrong nickname in duel of honor notifications? (Pythagoras1 vs Pythagoras)

- crate caption
- send heartbeats when state changes too
- but dont skip sending heartbeats because the servers will disappear otherwise
Expand Down
3 changes: 3 additions & 0 deletions hypersomnia/default_config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,9 @@ treat_as_music_sounds_longer_than_secs = 5,
arena = "de_cyberaqua",
game_mode = "",

daily_autoupdate = false,
daily_autoupdate_hour = "03:00",

external_arena_files_provider = "https://hypersomnia.xyz/arenas",
sync_all_external_arenas_on_startup = false,

Expand Down
6 changes: 5 additions & 1 deletion src/application/gui/client/rcon_gui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ void perform_rcon_gui(
LOG("Requesting the server to shut down");
}

if (do_command_button("Restart & update server", RS::RESTART)) {
if (do_command_button("Restart server", RS::RESTART)) {
LOG("Requesting the server to restart");
}

if (do_command_button("Check and apply updates now", RS::CHECK_FOR_UPDATES_NOW)) {
LOG("Requesting the server to restart");
}

Expand Down
7 changes: 7 additions & 0 deletions src/application/gui/settings_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,13 @@ void do_server_vars(
revertable_input_text(SCOPE_CFG_NVP(notified_server_list.address));
revertable_input_text(SCOPE_CFG_NVP(server_name));

revertable_checkbox(SCOPE_CFG_NVP(daily_autoupdate));

if (scope_cfg.daily_autoupdate) {
auto scope = scoped_indent();
revertable_input_text(SCOPE_CFG_NVP(daily_autoupdate_hour));
}

revertable_checkbox("I'm behind router", scope_cfg.allow_nat_traversal);

revertable_input_text(SCOPE_CFG_NVP(external_arena_files_provider));
Expand Down
54 changes: 33 additions & 21 deletions src/application/main/self_updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,16 +595,18 @@ self_update_result check_and_apply_updates(

auto advance_update_logic = [&]() {
const auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
auto loading_window = scoped_window("Loading in progress", nullptr, flags);
auto loading_window = cond_scoped_window(window.has_value(), "Loading in progress", nullptr, flags);

{
auto child = scoped_child("loading view", ImVec2(0, -(ImGui::GetFrameHeightWithSpacing() + 4)), false, flags);

print_new_version_available();
print_version_transition_info();
ImGui::Columns(2);
print_upstream();
ImGui::Columns(1);
auto child = cond_scoped_child(window.has_value(), "loading view", ImVec2(0, -(ImGui::GetFrameHeightWithSpacing() + 4)), false, flags);

if (window.has_value()) {
print_new_version_available();
print_version_transition_info();
ImGui::Columns(2);
print_upstream();
ImGui::Columns(1);
}

if (current_state == state::DOWNLOADING) {
if (valid_and_is_ready(future_response)) {
Expand Down Expand Up @@ -701,7 +703,9 @@ self_update_result check_and_apply_updates(
current_state = state::SAVING_ARCHIVE_TO_DISK;
}

print_download_progress_bar();
if (window.has_value()) {
print_download_progress_bar();
}
}
else if (current_state == state::SAVING_ARCHIVE_TO_DISK) {
if (valid_and_is_ready(completed_save)) {
Expand Down Expand Up @@ -782,7 +786,9 @@ self_update_result check_and_apply_updates(
}
}

print_saving_progress();
if (window.has_value()) {
print_saving_progress();
}
}
else if (current_state == state::EXTRACTING) {
ensure(!is_appimage);
Expand Down Expand Up @@ -986,7 +992,9 @@ self_update_result check_and_apply_updates(
}
}

print_extracting_progress();
if (window.has_value()) {
print_extracting_progress();
}
}
else if (current_state == state::MOVING_FILES_AROUND) {
if (valid_and_is_ready(completed_move)) {
Expand All @@ -1000,16 +1008,20 @@ self_update_result check_and_apply_updates(
}
}

text("Moving files around...");
if (window.has_value()) {
text("Moving files around...");
}
}
else {
ensure(false && "Unknown state!");
}
}

if (current_state != state::MOVING_FILES_AROUND) {
if (do_cancel_button()) {
interrupt(R::CANCELLED);
if (window.has_value()) {
if (current_state != state::MOVING_FILES_AROUND) {
if (do_cancel_button()) {
interrupt(R::CANCELLED);
}
}
}
};
Expand Down Expand Up @@ -1060,15 +1072,16 @@ self_update_result check_and_apply_updates(
);

augs::imgui::pass_inputs(entropy);
}

ImGui::NewFrame();
center_next_window(vec2::square(1.f), ImGuiCond_Always);
ImGui::NewFrame();
center_next_window(vec2::square(1.f), ImGuiCond_Always);
}

advance_update_logic();
augs::imgui::render();

if (window.has_value()) {
augs::imgui::render();

renderer.clear_current_fbo();

ensure(imgui_atlas.has_value());
Expand Down Expand Up @@ -1105,9 +1118,8 @@ self_update_result check_and_apply_updates(
}

window->swap_buffers();
renderer.next_frame();
}

renderer.next_frame();
}

return result;
Expand Down
1 change: 1 addition & 0 deletions src/application/network/rcon_command.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace rcon_commands {
enum class special : unsigned char {
SHUTDOWN,
RESTART,
CHECK_FOR_UPDATES_NOW,
REQUEST_RUNTIME_INFO,
DOWNLOAD_LOGS,

Expand Down
103 changes: 100 additions & 3 deletions src/application/setups/server/server_setup.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "augs/misc/time_utils.h"
#include "augs/misc/pool/pool_io.hpp"
#include "augs/misc/imgui/imgui_scope_wrappers.h"
#include "augs/misc/imgui/imgui_control_wrappers.h"
Expand Down Expand Up @@ -1556,6 +1557,91 @@ void server_setup::advance_clients_state() {
}
}

static auto get_todays_time_at(const hour_and_minute_str& timeStr) {
std::tm tm{};
std::istringstream ss(timeStr);
ss >> std::get_time(&tm, "%H:%M");

// Get the current time
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
std::tm* now_tm = std::localtime(&now_time_t);

// Set the hours and minutes from timeStr
now_tm->tm_hour = tm.tm_hour;
now_tm->tm_min = tm.tm_min;
now_tm->tm_sec = 0;

auto time_t = std::mktime(now_tm);
return std::chrono::system_clock::from_time_t(time_t);
}

void server_setup::check_for_updates() {
if (is_integrated()) {
return;
}

if (!vars.daily_autoupdate) {
return;
}

const auto check_when = vars.daily_autoupdate_hour;

if (check_when.empty()) {
when_to_check_for_updates_last_var = "";
return;
}

const auto now = std::chrono::system_clock::now();

auto get_next_check_readable = [&]() {
return augs::date_time(when_to_check_for_updates).get_readable();
};

auto get_how_long_until_next_check = [&]() {
const auto diff = std::chrono::duration<double>(when_to_check_for_updates - now).count();

return augs::date_time::format_how_long_ago_brief(true, diff);
};

if (when_to_check_for_updates_last_var != check_when) {
when_to_check_for_updates_last_var = check_when;
when_to_check_for_updates = ::get_todays_time_at(check_when);

if (now >= when_to_check_for_updates) {
when_to_check_for_updates += std::chrono::hours(24);
}

LOG(
"Daily autoupdates enabled at: %x. Next check happening in %x (%x)",
check_when,
get_how_long_until_next_check(),
get_next_check_readable()
);
}

if (now >= when_to_check_for_updates) {
check_for_updates_once = true;
when_to_check_for_updates += std::chrono::hours(24);

LOG(
"Time to check for updates. Next check scheduled in: %x (%x)",
get_how_long_until_next_check(),
get_next_check_readable()
);
}
}

bool server_setup::should_check_for_updates_once() {
if (check_for_updates_once) {
check_for_updates_once = false;

return true;
}

return false;
}

void server_setup::broadcast_shutdown_message() {
server_broadcasted_chat message;
message.target = chat_target_type::SERVER_SHUTTING_DOWN;
Expand All @@ -1579,6 +1665,12 @@ void server_setup::schedule_shutdown() {
broadcast_shutdown_message();
}

void server_setup::schedule_restart() {
schedule_shutdown();

request_restart_after_shutdown = true;
}

template <class P>
message_handler_result server_setup::handle_rcon_payload(
const rcon_level_type level,
Expand Down Expand Up @@ -1606,7 +1698,14 @@ message_handler_result server_setup::handle_rcon_payload(
}
}

LOG("Performing a RCON command: %x", typed_payload);

switch (typed_payload) {
case special::CHECK_FOR_UPDATES_NOW:
check_for_updates_once = true;

return continue_v;

case special::SHUTDOWN: {
LOG("Shutting down due to rcon's request.");
schedule_shutdown();
Expand All @@ -1616,9 +1715,7 @@ message_handler_result server_setup::handle_rcon_payload(

case special::RESTART: {
LOG("Restarting the server due to rcon's request.");
schedule_shutdown();

request_restart_after_shutdown = true;
schedule_restart();

return continue_v;
}
Expand Down
11 changes: 11 additions & 0 deletions src/application/setups/server/server_setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ class server_setup :
net_time_t when_last_resolved_server_list_addr = 0;
net_time_t when_last_resolved_internal_address = 0;

std::chrono::system_clock::time_point when_to_check_for_updates;
hour_and_minute_str when_to_check_for_updates_last_var;

std::vector<std::byte> heartbeat_buffer;
std::future<resolve_address_result> future_resolved_server_list_addr;
std::optional<netcode_address_t> resolved_server_list_addr;
Expand Down Expand Up @@ -192,9 +195,14 @@ class server_setup :
void push_duel_interrupted_webhook(const messages::duel_interrupted_message& summary);
std::string get_next_duel_pic_link();

void check_for_updates();
bool check_for_updates_once = false;

public:
net_time_t last_logged_at = 0;
server_profiler profiler;

bool should_check_for_updates_once();
private:
/* No server state follows later in code. */

Expand Down Expand Up @@ -369,6 +377,8 @@ class server_setup :

auto scope = measure_scope(profiler.step);

check_for_updates();

step_collected.clear();

{
Expand Down Expand Up @@ -646,6 +656,7 @@ class server_setup :
void log_match_start_json(const messages::team_match_start_message&);

void schedule_shutdown();
void schedule_restart();
void send_goodbye_to_masterserver();

void broadcast_shutdown_message();
Expand Down
3 changes: 3 additions & 0 deletions src/application/setups/server/server_vars.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ struct server_vars {
bool allow_direct_arena_file_downloads = true;
address_string_type external_arena_files_provider = "";

bool daily_autoupdate = false;
hour_and_minute_str daily_autoupdate_hour = "";

uint32_t send_heartbeat_to_server_list_once_every_secs = 10;
uint32_t resolve_server_list_address_once_every_secs = 60;

Expand Down
3 changes: 3 additions & 0 deletions src/augs/misc/constant_size_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
namespace augs {
template <unsigned const_count>
class constant_size_string {
public:
using array_type = std::array<char, const_count + 1>;
private:


unsigned len = 0;
array_type arr = {};
Expand Down
2 changes: 1 addition & 1 deletion src/augs/misc/imgui/imgui_control_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ namespace augs {

template <unsigned buffer_size, class... Args>
bool input_text(const std::string& label, constant_size_string<buffer_size>& value, Args&&... args) {
std::array<char, buffer_size> buf;
typename remove_cref<decltype(value)>::array_type buf;
return input_text(buf, label, value, std::forward<Args>(args)...);
}

Expand Down
Loading

0 comments on commit 67d8736

Please sign in to comment.