mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 11:03:00 +01:00
Fix FileWatcher (#18216)
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../core/Path.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "FileSystem.hpp"
|
||||
#include "FileWatcher.h"
|
||||
@@ -81,20 +82,20 @@ FileWatcher::WatchDescriptor::~WatchDescriptor()
|
||||
}
|
||||
#endif
|
||||
|
||||
FileWatcher::FileWatcher(const std::string& directoryPath)
|
||||
FileWatcher::FileWatcher(u8string_view directoryPath)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_path = directoryPath;
|
||||
_directoryHandle = CreateFileA(
|
||||
directoryPath.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
|
||||
nullptr);
|
||||
_path = fs::u8path(directoryPath);
|
||||
_directoryHandle = CreateFileW(
|
||||
String::ToWideChar(directoryPath).c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
if (_directoryHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw std::runtime_error("Unable to open directory '" + directoryPath + "'");
|
||||
throw std::runtime_error("Unable to open directory '" + u8string(directoryPath) + "'");
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
_fileDesc.Initialise();
|
||||
_watchDescs.emplace_back(_fileDesc.Fd, directoryPath);
|
||||
_watchDescs.emplace_back(_fileDesc.Fd, u8string(directoryPath));
|
||||
for (auto& p : fs::recursive_directory_iterator(directoryPath))
|
||||
{
|
||||
if (p.status().type() == fs::file_type::directory)
|
||||
@@ -105,21 +106,22 @@ FileWatcher::FileWatcher(const std::string& directoryPath)
|
||||
#else
|
||||
throw std::runtime_error("FileWatcher not supported on this platform.");
|
||||
#endif
|
||||
_watchThread = std::thread(std::bind(&FileWatcher::WatchDirectory, this));
|
||||
_watchThread = std::thread(&FileWatcher::WatchDirectory, this);
|
||||
}
|
||||
|
||||
FileWatcher::~FileWatcher()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CancelIoEx(_directoryHandle, nullptr);
|
||||
_watchThread.join();
|
||||
CloseHandle(_directoryHandle);
|
||||
#elif defined(__linux__)
|
||||
_finished = true;
|
||||
_watchThread.join();
|
||||
_fileDesc.Close();
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
_watchThread.join();
|
||||
}
|
||||
|
||||
void FileWatcher::WatchDirectory()
|
||||
@@ -131,8 +133,7 @@ void FileWatcher::WatchDirectory()
|
||||
_directoryHandle, eventData.data(), static_cast<DWORD>(eventData.size()), TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
&bytesReturned, nullptr, nullptr))
|
||||
{
|
||||
auto onFileChanged = OnFileChanged;
|
||||
if (onFileChanged)
|
||||
if (bytesReturned != 0 && OnFileChanged)
|
||||
{
|
||||
FILE_NOTIFY_INFORMATION* notifyInfo;
|
||||
size_t offset = 0;
|
||||
@@ -141,10 +142,9 @@ void FileWatcher::WatchDirectory()
|
||||
notifyInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(eventData.data() + offset);
|
||||
offset += notifyInfo->NextEntryOffset;
|
||||
|
||||
std::wstring fileNameW(notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t));
|
||||
auto fileName = String::ToUtf8(fileNameW);
|
||||
auto path = fs::path(_path) / fs::path(fileName);
|
||||
onFileChanged(path.u8string());
|
||||
std::wstring_view fileNameW(notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t));
|
||||
auto path = _path / fs::path(fileNameW);
|
||||
OnFileChanged(path.u8string());
|
||||
} while (notifyInfo->NextEntryOffset != 0);
|
||||
}
|
||||
}
|
||||
@@ -175,9 +175,7 @@ void FileWatcher::WatchDirectory()
|
||||
[wd](const WatchDescriptor& watchDesc) { return wd == watchDesc.Wd; });
|
||||
if (findResult != _watchDescs.end())
|
||||
{
|
||||
auto directory = findResult->Path;
|
||||
auto path = fs::path(directory) / fs::path(e->name);
|
||||
onFileChanged(path);
|
||||
onFileChanged(Path::Combine(findResult->Path, e->name));
|
||||
}
|
||||
}
|
||||
offset += sizeof(inotify_event) + e->len;
|
||||
|
||||
@@ -9,12 +9,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "FileSystem.hpp"
|
||||
|
||||
typedef void* HANDLE;
|
||||
#endif
|
||||
|
||||
@@ -26,7 +30,7 @@ class FileWatcher
|
||||
private:
|
||||
std::thread _watchThread;
|
||||
#if defined(_WIN32)
|
||||
std::string _path;
|
||||
fs::path _path;
|
||||
HANDLE _directoryHandle{};
|
||||
#elif defined(__linux__)
|
||||
struct FileDescriptor
|
||||
@@ -53,9 +57,9 @@ private:
|
||||
#endif
|
||||
|
||||
public:
|
||||
std::function<void(const std::string& path)> OnFileChanged;
|
||||
std::function<void(u8string_view path)> OnFileChanged;
|
||||
|
||||
FileWatcher(const std::string& directoryPath);
|
||||
FileWatcher(u8string_view directoryPath);
|
||||
~FileWatcher();
|
||||
|
||||
private:
|
||||
|
||||
@@ -771,8 +771,8 @@ void ScriptEngine::SetupHotReloading()
|
||||
if (Path::DirectoryExists(base))
|
||||
{
|
||||
_pluginFileWatcher = std::make_unique<FileWatcher>(base);
|
||||
_pluginFileWatcher->OnFileChanged = [this](const std::string& path) {
|
||||
std::lock_guard<std::mutex> guard(_changedPluginFilesMutex);
|
||||
_pluginFileWatcher->OnFileChanged = [this](u8string_view path) {
|
||||
std::lock_guard guard(_changedPluginFilesMutex);
|
||||
_changedPluginFiles.emplace(path);
|
||||
};
|
||||
_hotReloadingInitialised = true;
|
||||
@@ -799,10 +799,10 @@ void ScriptEngine::DoAutoReloadPluginCheck()
|
||||
|
||||
void ScriptEngine::AutoReloadPlugins()
|
||||
{
|
||||
if (_changedPluginFiles.size() > 0)
|
||||
if (!_changedPluginFiles.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_changedPluginFilesMutex);
|
||||
for (auto& path : _changedPluginFiles)
|
||||
std::lock_guard guard(_changedPluginFilesMutex);
|
||||
for (const auto& path : _changedPluginFiles)
|
||||
{
|
||||
auto findResult = std::find_if(_plugins.begin(), _plugins.end(), [&path](const std::shared_ptr<Plugin>& plugin) {
|
||||
return Path::Equals(path, plugin->GetPath());
|
||||
|
||||
Reference in New Issue
Block a user