Skip to content
This repository has been archived by the owner on Mar 5, 2024. It is now read-only.

Commit

Permalink
Merge branch 'separate_config_paths'
Browse files Browse the repository at this point in the history
  • Loading branch information
PazerOP committed Jan 9, 2021
2 parents ae0cc38 + b9e577f commit 3152d3e
Show file tree
Hide file tree
Showing 23 changed files with 634 additions and 230 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,4 @@ staging/debug_report.zip
staging/cfg/playerlist.json
staging/cfg/.non_portable
staging/cfg/account_ages.json
staging/temp/
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ add_subdirectory(submodules/imgui_desktop)
add_subdirectory(submodules/mh_stuff)

add_subdirectory(tf2_bot_detector_common)

if (WIN32)
add_subdirectory(tf2_bot_detector_winrt)
endif()

# add_subdirectory(tf2_bot_detector_updater)
add_subdirectory(tf2_bot_detector)

1 change: 1 addition & 0 deletions cmake/init-postproject.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ if (MSVC)
# Generate PDBs for release builds - RelWithDebInfo is NOT a Release build!
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG")
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /DEBUG")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG")

if (CMAKE_BUILD_TYPE MATCHES "Release")
Expand Down
2 changes: 1 addition & 1 deletion submodules/mh_stuff
4 changes: 4 additions & 0 deletions tf2_bot_detector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ if (TF2BD_ENABLE_DISCORD_INTEGRATION)
)
endif()

if (WIN32)
INCLUDE_TF2BD_WINRT(tf2_bot_detector)
endif()

find_package(OpenSSL REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(libzip CONFIG REQUIRED)
Expand Down
34 changes: 16 additions & 18 deletions tf2_bot_detector/Config/ConfigHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,34 @@ auto tf2_bot_detector::GetConfigFilePaths(const std::string_view& basename) -> C
if (auto path = mh::format("cfg/{}.json", basename); IFilesystem::Get().Exists(path))
retVal.m_User = path;

if (const auto cfg = IFilesystem::Get().GetMutableDataDir() / std::filesystem::path("cfg");
std::filesystem::is_directory(cfg))
constexpr std::filesystem::directory_options options =
std::filesystem::directory_options::skip_permission_denied | std::filesystem::directory_options::follow_directory_symlink;

try
{
try
for (const auto& file : IFilesystem::Get().IterateDir("cfg", false, options))
{
const std::regex filenameRegex(mh::format("{}{}", basename, R"regex(\.(?!official).*\.json)regex"),
std::regex::optimize | std::regex::icase);

for (const auto& file : std::filesystem::directory_iterator(cfg,
std::filesystem::directory_options::follow_directory_symlink | std::filesystem::directory_options::skip_permission_denied))
{
const auto path = file.path();
const auto filename = path.filename().string();
if (std::regex_match(filename.begin(), filename.end(), filenameRegex))
retVal.m_Others.push_back(cfg / filename);
}
}
catch (const std::filesystem::filesystem_error& e)
{
LogException(MH_SOURCE_LOCATION_CURRENT(), e,
"Failed to gather names matching {}.*.json in {}", basename, cfg);
const auto path = file.path();
const auto filename = path.filename().string();
if (std::regex_match(filename.begin(), filename.end(), filenameRegex))
retVal.m_Others.push_back(path);
}
}
catch (const std::filesystem::filesystem_error& e)
{
LogException(MH_SOURCE_LOCATION_CURRENT(), e,
"Failed to gather names matching {}.*.json in cfg", basename);
}

return retVal;
}

static void SaveJSONToFile(const std::filesystem::path& filename, const nlohmann::json& json)
{
IFilesystem::Get().WriteFile(filename, json.dump(1, '\t', true, nlohmann::detail::error_handler_t::ignore) << '\n');
IFilesystem::Get().WriteFile(filename, json.dump(1, '\t', true, nlohmann::detail::error_handler_t::ignore) << '\n', PathUsage::WriteRoaming);
}

static ConfigSchemaInfo LoadAndValidateSchema(const ConfigFileBase& config, const nlohmann::json& json)
Expand Down Expand Up @@ -217,7 +215,7 @@ static void SaveConfigFileBackup(const std::filesystem::path& filename) noexcept
std::filesystem::path backupPath;
for (size_t i = 1; ; i++)
{
backupPath = fs.ResolvePath(filename, PathUsage::Write).remove_filename();
backupPath = fs.ResolvePath(filename, PathUsage::WriteLocal).remove_filename();
backupPath /= mh::format("{}_BACKUP_{}{}", baseFilename.string(), i, extension.string());

if (!std::filesystem::exists(backupPath))
Expand Down
4 changes: 4 additions & 0 deletions tf2_bot_detector/DLLMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "UI/MainWindow.h"
#include "Util/TextUtils.h"
#include "Log.h"
#include "Filesystem.h"

#include <mh/text/string_insertion.hpp>

Expand Down Expand Up @@ -66,6 +67,9 @@ TF2_BOT_DETECTOR_EXPORT int tf2_bot_detector::RunProgram(int argc, const char**
}
#endif

IFilesystem::Get().Init();
ILogManager::GetInstance().Init();

for (int i = 1; i < argc; i++)
{
#ifdef _DEBUG
Expand Down
191 changes: 143 additions & 48 deletions tf2_bot_detector/Filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "Log.h"
#include "Platform/Platform.h"

#include <mh/concurrency/main_thread.hpp>
#include <mh/text/format.hpp>
#include <mh/text/string_insertion.hpp>
#include <mh/utility.hpp>
Expand All @@ -15,26 +16,34 @@ namespace
class Filesystem final : public IFilesystem
{
public:
Filesystem();
void Init() override;

mh::generator<std::filesystem::path> GetSearchPaths() const override;

std::filesystem::path ResolvePath(const std::filesystem::path& path, PathUsage usage) const override;
std::string ReadFile(std::filesystem::path path) const override;
void WriteFile(std::filesystem::path path, const void* begin, const void* end) const override;
void WriteFile(std::filesystem::path path, const void* begin, const void* end, PathUsage usage) const override;

std::filesystem::path GetMutableDataDir() const override;
std::filesystem::path GetRealMutableDataDir() const override;
std::filesystem::path GetLocalAppDataDir() const override;
std::filesystem::path GetRoamingAppDataDir() const override;
std::filesystem::path GetTempDir() const override;

mh::generator<std::filesystem::directory_entry> IterateDir(std::filesystem::path path, bool recursive,
std::filesystem::directory_options options) const override;

private:
bool m_IsInit = false;
void EnsureInit(MH_SOURCE_LOCATION_AUTO(location)) const;

static constexpr char NON_PORTABLE_MARKER[] = ".non_portable";
static constexpr char APPDATA_SUBFOLDER[] = "TF2 Bot Detector";
std::vector<std::filesystem::path> m_SearchPaths;
bool m_IsPortable;

const std::filesystem::path m_ExeDir = Platform::GetCurrentExeDir();
const std::filesystem::path m_WorkingDir = std::filesystem::current_path();
const std::filesystem::path m_AppDataDir = Platform::GetAppDataDir() / APPDATA_SUBFOLDER;
std::filesystem::path m_ExeDir;
std::filesystem::path m_WorkingDir;
std::filesystem::path m_LocalAppDataDir;
std::filesystem::path m_RoamingAppDataDir;
//std::filesystem::path m_MutableDataDir = ChooseMutableDataPath();
};
}
Expand All @@ -45,46 +54,82 @@ IFilesystem& IFilesystem::Get()
return s_Filesystem;
}

Filesystem::Filesystem() try
void Filesystem::Init()
{
DebugLog(MH_SOURCE_LOCATION_CURRENT(), "Initializing filesystem...");
assert(mh::is_main_thread());

m_SearchPaths.insert(m_SearchPaths.begin(), m_ExeDir);
if (!m_IsInit)
{
m_IsInit = true;
try
{
DebugLog("Initializing filesystem...");

if (m_WorkingDir != m_ExeDir)
m_SearchPaths.insert(m_SearchPaths.begin(), m_WorkingDir);
m_ExeDir = Platform::GetCurrentExeDir();
m_WorkingDir = std::filesystem::current_path();
m_LocalAppDataDir = Platform::GetRootLocalAppDataDir() / APPDATA_SUBFOLDER;
m_RoamingAppDataDir = Platform::GetRootRoamingAppDataDir() / APPDATA_SUBFOLDER;

if (!ResolvePath(std::filesystem::path("cfg") / NON_PORTABLE_MARKER, PathUsage::Read).empty())
{
DebugLog("Installation detected as non-portable.");
m_SearchPaths.insert(m_SearchPaths.begin(), m_AppDataDir);
m_IsPortable = false;
m_SearchPaths.insert(m_SearchPaths.begin(), m_ExeDir);

// If we crash, we want our working directory to be somewhere we can write to.
if (std::filesystem::create_directories(m_AppDataDir))
DebugLog("Created {}", m_AppDataDir);
if (m_WorkingDir != m_ExeDir)
m_SearchPaths.insert(m_SearchPaths.begin(), m_WorkingDir);

std::filesystem::current_path(m_AppDataDir);
DebugLog("Set working directory to {}", m_AppDataDir);
}
else
{
DebugLog("Installation detected as portable.");
m_IsPortable = true;
}
if (!ResolvePath(std::filesystem::path("cfg") / NON_PORTABLE_MARKER, PathUsage::Read).empty())
{
DebugLog("Installation detected as non-portable.");
m_SearchPaths.insert(m_SearchPaths.begin(), m_RoamingAppDataDir);
m_IsPortable = false;

{
std::string initMsg = "Filesystem initialized. Search paths:";
for (const auto& searchPath : m_SearchPaths)
initMsg << "\n\t" << searchPath;
// If we crash, we want our working directory to be somewhere we can write to.
if (std::filesystem::create_directories(m_RoamingAppDataDir))
DebugLog("Created {}", m_RoamingAppDataDir);

if (std::filesystem::create_directories(m_LocalAppDataDir))
DebugLog("Created {}", m_LocalAppDataDir);

DebugLog(std::move(initMsg));
std::filesystem::current_path(m_LocalAppDataDir);
DebugLog("Set working directory to {}", m_LocalAppDataDir);
}
else
{
DebugLog("Installation detected as portable.");
m_IsPortable = true;
}

if (auto legacyPath = Platform::GetLegacyAppDataDir(); std::filesystem::exists(legacyPath))
{
legacyPath /= APPDATA_SUBFOLDER;
if (std::filesystem::exists(legacyPath))
{
Log("Found legacy appdata folder {}, copying to {}...", legacyPath, m_RoamingAppDataDir);
std::filesystem::copy(legacyPath, m_RoamingAppDataDir,
std::filesystem::copy_options::recursive | std::filesystem::copy_options::skip_existing);

Log("Copy complete. Deleting {}...", legacyPath);
std::filesystem::remove_all(legacyPath);
}
}

{
std::string initMsg = "Filesystem initialized. Search paths:";
for (const auto& searchPath : m_SearchPaths)
initMsg << "\n\t" << searchPath;

DebugLog(std::move(initMsg));
}

DebugLog("\tLocalAppDataDir: {}", GetLocalAppDataDir());
DebugLog("\tRoamingAppDataDir: {}", GetRoamingAppDataDir());
DebugLog("\tTempDir: {}", GetTempDir());
std::filesystem::create_directories(GetTempDir());
}
catch (...)
{
LogFatalException("Failed to initialize filesystem");
}
}
}
catch (const std::exception& e)
{
LogFatalException(MH_SOURCE_LOCATION_CURRENT(), e, "Failed to initialize filesystem");
}

mh::generator<std::filesystem::path> Filesystem::GetSearchPaths() const
{
Expand All @@ -97,6 +142,8 @@ std::filesystem::path Filesystem::ResolvePath(const std::filesystem::path& path,
if (path.is_absolute())
return path;

EnsureInit();

auto retVal = std::invoke([&]() -> std::filesystem::path
{
if (usage == PathUsage::Read)
Expand All @@ -114,9 +161,13 @@ std::filesystem::path Filesystem::ResolvePath(const std::filesystem::path& path,
DebugLogWarning("Unable to find {} in any search path", path);
return {};
}
else if (usage == PathUsage::Write)
else if (usage == PathUsage::WriteLocal)
{
return GetLocalAppDataDir() / path;
}
else if (usage == PathUsage::WriteRoaming)
{
return GetRealMutableDataDir() / path;
return GetRoamingAppDataDir() / path;
}
else
{
Expand Down Expand Up @@ -155,9 +206,9 @@ catch (...)
throw;
}

void Filesystem::WriteFile(std::filesystem::path path, const void* begin, const void* end) const try
void Filesystem::WriteFile(std::filesystem::path path, const void* begin, const void* end, PathUsage usage) const try
{
path = ResolvePath(path, PathUsage::Write);
path = ResolvePath(path, usage);

// Create any missing directories
if (auto folderPath = mh::copy(path).remove_filename(); std::filesystem::create_directories(folderPath))
Expand All @@ -176,18 +227,62 @@ catch (...)
throw;
}

std::filesystem::path Filesystem::GetMutableDataDir() const
std::filesystem::path Filesystem::GetLocalAppDataDir() const
{
EnsureInit();

return m_IsPortable ? m_WorkingDir : m_LocalAppDataDir;
}

std::filesystem::path Filesystem::GetRoamingAppDataDir() const
{
EnsureInit();

return m_IsPortable ? m_WorkingDir : m_RoamingAppDataDir;
}

std::filesystem::path Filesystem::GetTempDir() const
{
EnsureInit();

if (m_IsPortable)
return m_WorkingDir;
return m_WorkingDir / "temp";
else
return m_AppDataDir;
return Platform::GetRootTempDataDir() / "TF2 Bot Detector";
}

std::filesystem::path Filesystem::GetRealMutableDataDir() const
void Filesystem::EnsureInit(const mh::source_location& location) const
{
if (m_IsPortable)
return m_WorkingDir;
if (!m_IsInit)
{
assert(false);
LogFatalError(location, "Filesystem::EnsureInit failed");
}
}

template<typename TIter>
static mh::generator<std::filesystem::directory_entry> IterateDirImpl(
const std::vector<std::filesystem::path>& searchPaths, std::filesystem::path path, std::filesystem::directory_options options)
{
for (std::filesystem::path searchPath : searchPaths)
{
searchPath /= path;

if (std::filesystem::exists(searchPath))
{
for (const std::filesystem::directory_entry& entry : TIter(searchPath, options))
co_yield entry;
}
}
}

mh::generator<std::filesystem::directory_entry> Filesystem::IterateDir(std::filesystem::path path, bool recursive,
std::filesystem::directory_options options) const
{
assert(!path.is_absolute());

if (recursive)
return IterateDirImpl<std::filesystem::recursive_directory_iterator>(m_SearchPaths, std::move(path), options);
else
return Platform::GetRealAppDataDir() / APPDATA_SUBFOLDER;
return IterateDirImpl<std::filesystem::directory_iterator>(m_SearchPaths, std::move(path), options);
}
Loading

0 comments on commit 3152d3e

Please sign in to comment.