mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2025-01-12 02:19:31 +08:00
timed memory allocator for: Steam_Remote_Storage::GetFileNameAndSize()
, Steam_Matchmaking_Servers::GetServerDetails()
, Steam_Remote_Storage::GetUGCDetails()
to avoid leaking memory
This commit is contained in:
parent
e02cc9b366
commit
804b57a7ed
@ -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);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__
|
||||
|
||||
#include "base.h"
|
||||
#include "common_helpers/forgettable_memory.hpp"
|
||||
#include <ssq/a2s.h>
|
||||
|
||||
struct Steam_Matchmaking_Servers_Direct_IP_Request {
|
||||
@ -68,6 +69,8 @@ public ISteamMatchmakingServers
|
||||
std::vector <struct Steam_Matchmaking_Request> requests{};
|
||||
std::vector <struct Steam_Matchmaking_Servers_Direct_IP_Request> direct_ip_requests{};
|
||||
|
||||
common_helpers::ForgettableMemory<gameserveritem_t> requests_from_GetServerDetails{};
|
||||
|
||||
HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type);
|
||||
void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type);
|
||||
|
||||
|
@ -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<struct Async_Read> async_reads{};
|
||||
std::vector<struct Stream_Write> stream_writes{};
|
||||
@ -94,9 +96,16 @@ private:
|
||||
|
||||
bool steam_cloud_enabled = true;
|
||||
|
||||
common_helpers::ForgettableMemory<std::string> requests_GetFileNameAndSize{};
|
||||
common_helpers::ForgettableMemory<std::string> 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
|
||||
//
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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<Steam_Remote_Storage *>(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<std::recursive_mutex> 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<char *>(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();
|
||||
}
|
||||
|
72
helpers/common_helpers/forgettable_memory.hpp
Normal file
72
helpers/common_helpers/forgettable_memory.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <forward_list>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace common_helpers
|
||||
{
|
||||
template<typename Ty>
|
||||
class ForgettableMemory {
|
||||
struct ForgettableBlock {
|
||||
Ty block;
|
||||
std::chrono::high_resolution_clock::time_point due_time;
|
||||
|
||||
template<typename Rep, typename Period, class... Args>
|
||||
ForgettableBlock(std::chrono::duration<Rep, Period> duration, Args&&... args)
|
||||
: due_time(std::chrono::high_resolution_clock::now() + duration),
|
||||
block( std::forward<Args>(args)... )
|
||||
{ }
|
||||
};
|
||||
|
||||
std::recursive_mutex mtx{};
|
||||
std::forward_list<ForgettableBlock> storage{};
|
||||
|
||||
|
||||
public:
|
||||
template<typename Rep, typename Period, class... Args>
|
||||
Ty& create(std::chrono::duration<Rep, Period> duration, Args&&... args) {
|
||||
std::lock_guard lock(mtx);
|
||||
|
||||
auto& new_ele = storage.emplace_front(duration, std::forward<Args>(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;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user