ladybird/Userland/Libraries/LibCore/FileWatcher.h
sin-ack 2159f90e00 Userland+LibCore: Update FileWatcher + its users for InodeWatcher 2.0
With the new InodeWatcher API, the old style of creating a watcher per
inode will no longer work.  Therefore the FileWatcher API has been
updated to support multiple watches, and its users have also been
refactored to the new style.  At the moment, all operations done on a
(Blocking)FileWatcher return Result objects, however, this may be
changed in the future if it becomes too obnoxious. :^)

Co-authored-by: Gunnar Beutner <gunnar@beutner.name>
2021-05-12 22:38:20 +02:00

125 lines
3.2 KiB
C++

/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* Copyright (c) 2021, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/EnumBits.h>
#include <AK/Function.h>
#include <AK/Noncopyable.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <AK/Result.h>
#include <AK/String.h>
#include <Kernel/API/InodeWatcherEvent.h>
#include <Kernel/API/InodeWatcherFlags.h>
#include <LibCore/Notifier.h>
namespace Core {
struct FileWatcherEvent {
enum class Type {
Invalid = 0,
MetadataModified = 1 << 0,
ContentModified = 1 << 1,
Deleted = 1 << 2,
ChildCreated = 1 << 3,
ChildDeleted = 1 << 4,
};
Type type;
String event_path;
};
AK_ENUM_BITWISE_OPERATORS(FileWatcherEvent::Type);
class FileWatcherBase {
public:
virtual ~FileWatcherBase() { }
Result<bool, String> add_watch(String path, FileWatcherEvent::Type event_mask);
Result<bool, String> remove_watch(String path);
bool is_watching(String const& path) const { return m_path_to_wd.find(path) != m_path_to_wd.end(); }
protected:
FileWatcherBase(int watcher_fd)
: m_watcher_fd(watcher_fd)
{
}
int m_watcher_fd { -1 };
HashMap<String, unsigned> m_path_to_wd;
HashMap<unsigned, String> m_wd_to_path;
};
class BlockingFileWatcher final : public FileWatcherBase {
AK_MAKE_NONCOPYABLE(BlockingFileWatcher);
public:
explicit BlockingFileWatcher(InodeWatcherFlags = InodeWatcherFlags::None);
~BlockingFileWatcher();
Optional<FileWatcherEvent> wait_for_event();
};
class FileWatcher final : public FileWatcherBase
, public RefCounted<FileWatcher> {
AK_MAKE_NONCOPYABLE(FileWatcher);
public:
static Result<NonnullRefPtr<FileWatcher>, String> create(InodeWatcherFlags = InodeWatcherFlags::None);
~FileWatcher();
Function<void(FileWatcherEvent const&)> on_change;
private:
FileWatcher(int watcher_fd, NonnullRefPtr<Notifier>);
NonnullRefPtr<Notifier> m_notifier;
};
}
namespace AK {
template<>
struct Formatter<Core::FileWatcherEvent> : Formatter<FormatString> {
void format(FormatBuilder& builder, const Core::FileWatcherEvent& value)
{
Formatter<FormatString>::format(builder, "FileWatcherEvent(\"{}\", {})", value.event_path, value.type);
}
};
template<>
struct Formatter<Core::FileWatcherEvent::Type> : Formatter<FormatString> {
void format(FormatBuilder& builder, const Core::FileWatcherEvent::Type& value)
{
char const* type;
switch (value) {
case Core::FileWatcherEvent::Type::ChildCreated:
type = "ChildCreated";
break;
case Core::FileWatcherEvent::Type::ChildDeleted:
type = "ChildDeleted";
break;
case Core::FileWatcherEvent::Type::Deleted:
type = "Deleted";
break;
case Core::FileWatcherEvent::Type::ContentModified:
type = "ContentModified";
break;
case Core::FileWatcherEvent::Type::MetadataModified:
type = "MetadataModified";
break;
default:
VERIFY_NOT_REACHED();
}
builder.put_string(type);
}
};
}