mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
add public file watching api
This commit is contained in:
parent
8842e8f793
commit
50ff15c356
3 changed files with 106 additions and 2 deletions
|
@ -252,4 +252,40 @@ namespace geode::utils::file {
|
||||||
* @param options Picker options
|
* @param options Picker options
|
||||||
*/
|
*/
|
||||||
GEODE_DLL Result<std::vector<ghc::filesystem::path>> pickFiles(FilePickOptions const& options);
|
GEODE_DLL Result<std::vector<ghc::filesystem::path>> pickFiles(FilePickOptions const& options);
|
||||||
|
|
||||||
|
class GEODE_DLL FileWatchEvent : public Event {
|
||||||
|
protected:
|
||||||
|
ghc::filesystem::path m_path;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileWatchEvent(ghc::filesystem::path const& path);
|
||||||
|
ghc::filesystem::path getPath() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GEODE_DLL FileWatchFilter : public EventFilter<FileWatchEvent> {
|
||||||
|
protected:
|
||||||
|
ghc::filesystem::path m_path;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Callback = void(FileWatchEvent*);
|
||||||
|
|
||||||
|
ListenerResult handle(utils::MiniFunction<Callback> callback, FileWatchEvent* event);
|
||||||
|
FileWatchFilter(ghc::filesystem::path const& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Watch a file for changes. Whenever the file is modified on disk, a
|
||||||
|
* FileWatchEvent is emitted. Add an EventListener with FileWatchFilter
|
||||||
|
* to catch these events
|
||||||
|
* @param file The file to watch
|
||||||
|
* @note Watching uses file system equivalence instead of path equivalence,
|
||||||
|
* so different paths that point to the same file will be considered the
|
||||||
|
* same
|
||||||
|
*/
|
||||||
|
GEODE_DLL Result<> watchFile(ghc::filesystem::path const& file);
|
||||||
|
/**
|
||||||
|
* Stop watching a file for changes
|
||||||
|
* @param file The file to unwatch
|
||||||
|
*/
|
||||||
|
GEODE_DLL void unwatchFile(ghc::filesystem::path const& file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,28 @@ protected:
|
||||||
public:
|
public:
|
||||||
bool watching() const;
|
bool watching() const;
|
||||||
|
|
||||||
ghc::filesystem::path path() {
|
ghc::filesystem::path path() const {
|
||||||
return m_file;
|
return m_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileWatcher(
|
FileWatcher(
|
||||||
ghc::filesystem::path const& file, FileWatchCallback callback, ErrorCallback error = nullptr
|
ghc::filesystem::path const& file,
|
||||||
|
FileWatchCallback callback,
|
||||||
|
ErrorCallback error = nullptr
|
||||||
);
|
);
|
||||||
|
FileWatcher(FileWatcher const&) = delete;
|
||||||
|
inline FileWatcher(FileWatcher&& other)
|
||||||
|
: m_file(std::move(other.m_file)),
|
||||||
|
m_callback(std::move(other.m_callback)),
|
||||||
|
m_error(std::move(other.m_error)),
|
||||||
|
m_filemode(other.m_filemode),
|
||||||
|
m_platformHandle(other.m_platformHandle),
|
||||||
|
m_exiting(other.m_exiting)
|
||||||
|
{
|
||||||
|
other.m_callback = nullptr;
|
||||||
|
other.m_error = nullptr;
|
||||||
|
other.m_platformHandle = nullptr;
|
||||||
|
other.m_exiting = true;
|
||||||
|
}
|
||||||
~FileWatcher();
|
~FileWatcher();
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <mz_strm_os.h>
|
#include <mz_strm_os.h>
|
||||||
#include <mz_strm_mem.h>
|
#include <mz_strm_mem.h>
|
||||||
#include <mz_zip.h>
|
#include <mz_zip.h>
|
||||||
|
#include <internal/FileWatcher.hpp>
|
||||||
|
|
||||||
using namespace geode::prelude;
|
using namespace geode::prelude;
|
||||||
using namespace geode::utils::file;
|
using namespace geode::utils::file;
|
||||||
|
@ -551,3 +552,54 @@ Result<> Zip::addAllFrom(Path const& dir) {
|
||||||
Result<> Zip::addFolder(Path const& entry) {
|
Result<> Zip::addFolder(Path const& entry) {
|
||||||
return m_impl->addFolder(entry);
|
return m_impl->addFolder(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileWatchEvent::FileWatchEvent(ghc::filesystem::path const& path)
|
||||||
|
: m_path(path) {}
|
||||||
|
|
||||||
|
ghc::filesystem::path FileWatchEvent::getPath() const {
|
||||||
|
return m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListenerResult FileWatchFilter::handle(
|
||||||
|
MiniFunction<Callback> callback,
|
||||||
|
FileWatchEvent* event
|
||||||
|
) {
|
||||||
|
std::error_code ec;
|
||||||
|
if (ghc::filesystem::equivalent(event->getPath(), m_path, ec)) {
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
|
return ListenerResult::Propagate;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileWatchFilter::FileWatchFilter(ghc::filesystem::path const& path)
|
||||||
|
: m_path(path) {}
|
||||||
|
|
||||||
|
// This is a vector because need to use ghc::filesystem::equivalent for
|
||||||
|
// comparisons and removal is not exactly performance-critical here
|
||||||
|
// (who's going to add and remove 500 file watchers every frame)
|
||||||
|
static std::vector<std::unique_ptr<FileWatcher>> FILE_WATCHERS {};
|
||||||
|
|
||||||
|
Result<> file::watchFile(ghc::filesystem::path const& file) {
|
||||||
|
if (!ghc::filesystem::exists(file)) {
|
||||||
|
return Err("File does not exist");
|
||||||
|
}
|
||||||
|
auto watcher = std::make_unique<FileWatcher>(
|
||||||
|
file,
|
||||||
|
[](auto const& path) {
|
||||||
|
Loader::get()->queueInGDThread([=] {
|
||||||
|
FileWatchEvent(path).post();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!watcher->watching()) {
|
||||||
|
return Err("Unknown error watching file");
|
||||||
|
}
|
||||||
|
FILE_WATCHERS.emplace_back(std::move(watcher));
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
void file::unwatchFile(ghc::filesystem::path const& file) {
|
||||||
|
ranges::remove(FILE_WATCHERS, [=](std::unique_ptr<FileWatcher> const& watcher) {
|
||||||
|
return ghc::filesystem::equivalent(file, watcher->path());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue