diff --git a/dll/dll/local_storage.h b/dll/dll/local_storage.h index c692ead9..0858d711 100644 --- a/dll/dll/local_storage.h +++ b/dll/dll/local_storage.h @@ -81,7 +81,7 @@ public: unsigned int data_settings_size(std::string file); int get_data_settings(std::string file, char *data, unsigned int max_length); int count_files(std::string folder); - bool iterate_file(std::string folder, int index, char *output_filename, int32 *output_size); + bool iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size); bool file_exists(std::string folder, std::string file); unsigned int file_size(std::string folder, std::string file); bool file_delete(std::string folder, std::string file); diff --git a/dll/dll/steam_matchmaking_servers.h b/dll/dll/steam_matchmaking_servers.h index a5bc9433..4264da65 100644 --- a/dll/dll/steam_matchmaking_servers.h +++ b/dll/dll/steam_matchmaking_servers.h @@ -19,6 +19,7 @@ #define __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__ #include "base.h" +#include "common_helpers/forgettable_memory.hpp" #include struct Steam_Matchmaking_Servers_Direct_IP_Request { @@ -68,6 +69,8 @@ public ISteamMatchmakingServers std::vector requests{}; std::vector direct_ip_requests{}; + common_helpers::ForgettableMemory requests_from_GetServerDetails{}; + HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type); void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type); diff --git a/dll/dll/steam_remote_storage.h b/dll/dll/steam_remote_storage.h index 9bda193e..65d16342 100644 --- a/dll/dll/steam_remote_storage.h +++ b/dll/dll/steam_remote_storage.h @@ -20,6 +20,7 @@ #include "base.h" #include "ugc_remote_storage_bridge.h" +#include "common_helpers/forgettable_memory.hpp" struct Async_Read { SteamAPICall_t api_call{}; @@ -86,6 +87,7 @@ private: class Local_Storage *local_storage{}; class SteamCallResults *callback_results{}; class SteamCallBacks *callbacks{}; + class RunEveryRunCB *run_every_runcb{}; std::vector async_reads{}; std::vector stream_writes{}; @@ -94,9 +96,16 @@ private: bool steam_cloud_enabled = true; + common_helpers::ForgettableMemory requests_GetFileNameAndSize{}; + common_helpers::ForgettableMemory requests_GetUGCDetails{}; + + static void steam_run_every_runcb(void *object); + void RunCallbacks(); + public: - Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks); + Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb); + ~Steam_Remote_Storage(); // NOTE // diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp index 2a236824..eac0ae79 100644 --- a/dll/local_storage.cpp +++ b/dll/local_storage.cpp @@ -170,7 +170,7 @@ uint64_t Local_Storage::file_timestamp(std::string folder, std::string file) return 0; } -bool Local_Storage::iterate_file(std::string folder, int index, char *output_filename, int32 *output_size) +bool Local_Storage::iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size) { return false; } @@ -766,8 +766,11 @@ uint64_t Local_Storage::file_timestamp(std::string folder, std::string file) return buffer.st_mtime; } -bool Local_Storage::iterate_file(std::string folder, int index, char *output_filename, int32 *output_size) +bool Local_Storage::iterate_file(std::string folder, int index, std::string &output_filename, int32 *output_size) { + output_filename.clear(); + if (output_size) *output_size = 0; + if (folder.size() && folder.back() != *PATH_SEPARATOR) { folder.append(PATH_SEPARATOR); } @@ -777,10 +780,12 @@ bool Local_Storage::iterate_file(std::string folder, int index, char *output_fil std::string name(desanitize_file_name(files[index].name)); if (output_size) *output_size = file_size(folder, name); + #if defined(STEAM_WIN32) name = replace_with(name, PATH_SEPARATOR, "/"); #endif - strcpy(output_filename, name.c_str()); + + output_filename = std::move(name); return true; } diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 85ef0d8e..3fe619d3 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -100,7 +100,7 @@ Steam_Client::Steam_Client() steam_user_stats = new Steam_User_Stats(settings_client, network, local_storage, callback_results_client, callbacks_client, run_every_runcb, steam_overlay); steam_apps = new Steam_Apps(settings_client, callback_results_client, callbacks_client); steam_networking = new Steam_Networking(settings_client, network, callbacks_client, run_every_runcb); - steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client, callbacks_client); + steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client, callbacks_client, run_every_runcb); steam_screenshots = new Steam_Screenshots(local_storage, callbacks_client); steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client); steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb); diff --git a/dll/steam_matchmaking_servers.cpp b/dll/steam_matchmaking_servers.cpp index 42453a4b..629ea05c 100644 --- a/dll/steam_matchmaking_servers.cpp +++ b/dll/steam_matchmaking_servers.cpp @@ -395,10 +395,10 @@ gameserveritem_t *Steam_Matchmaking_Servers::GetServerDetails( HServerListReques } Gameserver *gs = &gameservers_filtered[iServer].server; - gameserveritem_t *server = new gameserveritem_t(); //TODO: is the new here ok? - server_details(gs, server); + auto &server = requests_from_GetServerDetails.create(std::chrono::hours(1)); + server_details(gs, &server); PRINT_DEBUG(" Returned server details"); - return server; + return &server; } @@ -910,6 +910,8 @@ void Steam_Matchmaking_Servers::RunCallbacks() if (r.players_response) r.players_response->PlayersRefreshComplete(); if (r.ping_response) r.ping_response->ServerFailedToRespond(); } + + requests_from_GetServerDetails.cleanup(); } void Steam_Matchmaking_Servers::Callback(Common_Message *msg) diff --git a/dll/steam_remote_storage.cpp b/dll/steam_remote_storage.cpp index 8446e4c6..362044e6 100644 --- a/dll/steam_remote_storage.cpp +++ b/dll/steam_remote_storage.cpp @@ -38,19 +38,35 @@ static void copy_file(const std::string &src_filepath, const std::string &dst_fi const auto dst_p(std::filesystem::u8path(dst_filepath)); std::filesystem::create_directories(dst_p.parent_path()); // make the folder tree if needed - std::filesystem::copy_file(src_p, dst_p, std::filesystem::copy_options::overwrite_existing); + std::filesystem::copy_file(src_p, dst_p, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::copy_symlinks); } catch(...) {} } -Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks) + +void Steam_Remote_Storage::steam_run_every_runcb(void *object) +{ + // PRINT_DEBUG_ENTRY(); + + auto inst = reinterpret_cast(object); + inst->RunCallbacks(); +} + +Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb) { this->settings = settings; this->ugc_bridge = ugc_bridge; this->local_storage = local_storage; this->callback_results = callback_results; this->callbacks = callbacks; + this->run_every_runcb = run_every_runcb; steam_cloud_enabled = true; + this->run_every_runcb->add(&Steam_Remote_Storage::steam_run_every_runcb, this); +} + +Steam_Remote_Storage::~Steam_Remote_Storage() +{ + this->run_every_runcb->remove(&Steam_Remote_Storage::steam_run_every_runcb, this); } // NOTE @@ -329,16 +345,17 @@ int32 Steam_Remote_Storage::GetFileCount() const char* Steam_Remote_Storage::GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) { - PRINT_DEBUG("%i", iFile); + PRINT_DEBUG("%i %p", iFile, pnFileSizeInBytes); std::lock_guard lock(global_mutex); - static char output_filename[MAX_FILENAME_LENGTH]; + std::string output_filename{}; if (local_storage->iterate_file(Local_Storage::remote_storage_folder, iFile, output_filename, pnFileSizeInBytes)) { - PRINT_DEBUG("|%s|, size: %i", output_filename, pnFileSizeInBytes ? *pnFileSizeInBytes : 0); - return output_filename; - } else { - return ""; + auto &request = requests_GetFileNameAndSize.create(std::chrono::minutes(15), std::move(output_filename)); + PRINT_DEBUG("file '%s', size: %i", request.c_str(), pnFileSizeInBytes ? *pnFileSizeInBytes : 0); + return request.c_str(); } + + return ""; } @@ -504,8 +521,8 @@ bool Steam_Remote_Storage::GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID if (ppchName) *ppchName = nullptr; if (auto query_res = ugc_bridge->get_ugc_query_result(hContent)) { - auto mod = settings->getMod(query_res.value().mod_id); - auto &mod_name = query_res.value().is_primary_file + const auto mod = settings->getMod(query_res.value().mod_id); + const auto &mod_name = query_res.value().is_primary_file ? mod.primaryFileName : mod.previewFileName; int32 mod_size = query_res.value().is_primary_file @@ -513,8 +530,8 @@ bool Steam_Remote_Storage::GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID : mod.previewFileSize; if (ppchName) { - *ppchName = new char[mod_name.size() + 1]; - std::strcpy(*ppchName, mod_name.c_str()); + auto &new_str = requests_GetUGCDetails.create(std::chrono::minutes(30), mod_name); // this will make a copy of mod_name + *ppchName = const_cast(new_str.c_str()); } if (pnFileSizeInBytes) *pnFileSizeInBytes = mod_size; if (pSteamIDOwner) *pSteamIDOwner = mod.steamIDOwner; @@ -1238,3 +1255,10 @@ bool Steam_Remote_Storage::EndFileWriteBatch() return true; } + + +void Steam_Remote_Storage::RunCallbacks() +{ + requests_GetFileNameAndSize.cleanup(); + requests_GetUGCDetails.cleanup(); +} diff --git a/helpers/common_helpers/forgettable_memory.hpp b/helpers/common_helpers/forgettable_memory.hpp new file mode 100644 index 00000000..14e04a12 --- /dev/null +++ b/helpers/common_helpers/forgettable_memory.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include +#include + + +namespace common_helpers +{ + template + class ForgettableMemory { + struct ForgettableBlock { + Ty block; + std::chrono::high_resolution_clock::time_point due_time; + + template + ForgettableBlock(std::chrono::duration duration, Args&&... args) + : due_time(std::chrono::high_resolution_clock::now() + duration), + block( std::forward(args)... ) + { } + }; + + std::recursive_mutex mtx{}; + std::forward_list storage{}; + + + public: + template + Ty& create(std::chrono::duration duration, Args&&... args) { + std::lock_guard lock(mtx); + + auto& new_ele = storage.emplace_front(duration, std::forward(args)...); + return new_ele.block; + } + + bool is_alive(const Ty& block) { + std::lock_guard lock(mtx); + + auto ele_it = std::find_if(storage.begin(), storage.end(), [&block](const ForgettableBlock &item){ + return &item.block == █ + }); + return storage.end() != ele_it; + } + + void destroy(const Ty& block) { + std::lock_guard lock(mtx); + + storage.remove_if([&block](const ForgettableBlock &item){ + return &item.block == █ + }); + } + + void destroy_all() { + std::lock_guard lock(mtx); + + storage.clear(); + } + + void cleanup() { + std::lock_guard lock(mtx); + + const auto now = std::chrono::high_resolution_clock::now(); + storage.remove_if([&now](const ForgettableBlock &item){ + return now > item.due_time; + }); + + } + + }; +}