blob: 8046f436413d39c345824976c710acfaa0e1321d [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_COMPONENT_INCOMING_CPP_DIRECTORY_WATCHER_H_
#define LIB_COMPONENT_INCOMING_CPP_DIRECTORY_WATCHER_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/wait.h>
#include <lib/component/incoming/cpp/directory.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/component/incoming/cpp/service.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <deque>
namespace component {
// A watcher for directory entries.
//
// Watching is automatically stopped on destruction.
class DirectoryWatcher final {
public:
// A callback to be invoked when directory entries are added or removed.
//
// |event| will be either fuchsia_io::wire::WatchEvent::kExisting, if an instance was
// existing at the beginning, fuchsia_io::wire::WatchEvent::kAdded, if an instance
// was added, or fuchsia_io::wire::WatchEvent::kIdle, if all the existing instances
// have been reported.
// |instance| will be the name of the instance associated with the event.
using Callback = fit::function<void(fuchsia_io::wire::WatchEvent event, std::string instance)>;
// Begins watching for entries in the provided directory.
// When an entry is found, calls
// the callback function with the entry name and the event type.
// Begin will return ZX_ERR_UNAVAILABLE if it is called multiple times
// without Cancel called first.
zx_status_t Begin(fidl::UnownedClientEnd<fuchsia_io::Directory> dir, Callback callback,
async_dispatcher_t* dispatcher);
// Cancels watching for directory entries.
zx_status_t Cancel();
private:
void OnWatchedEvent(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal);
Callback callback_;
std::shared_ptr<std::array<uint8_t, fuchsia_io::wire::kMaxBuf>> buf_;
zx::channel client_end_;
async::WaitMethod<DirectoryWatcher, &DirectoryWatcher::OnWatchedEvent> wait_{this};
};
// SyncDirectoryWatcher allows directories to be waited for synchronously.
//
// The directory can be specified in multiple forms:
// - a fidl::UnownedClientEnd<fuchsia_io::Directory>
// - a fidl::UnownedClientEnd<fuchsia_io::Directory> and a path relative to it
// - a full path, which will be opened relative to the root of the component's namespace.
// The instantiation arguments will not be checked until GetNextEntry is first called.
class SyncDirectoryWatcher final {
public:
explicit SyncDirectoryWatcher(fidl::UnownedClientEnd<fuchsia_io::Directory> dir) : dir_(dir) {}
explicit SyncDirectoryWatcher(fidl::UnownedClientEnd<fuchsia_io::Directory> dir,
const std::string& relative_path)
: dir_(dir), path_(relative_path) {}
explicit SyncDirectoryWatcher(const std::string& full_path) : path_(full_path) {}
// Sequentially query for directory entries at the directory given at initialization
//
// This call will block until a directory entry is found. When an entry is detected, the
// name of the entry is returned.
//
// Subsequent calls to GetNextEntry will return other entries if they exist.
// GetNextEntry will iterate through all directory entries of a given directory.
// When all of the existing directory entries have been returned,
// if |stop_at_idle| is true, GetNextEntry will return a zx::error(ZX_ERR_STOP).
// Otherwise, GetNextEntry will wait until |deadline| for a new instance to appear.
zx::result<std::string> GetNextEntry(bool stop_at_idle, zx::time deadline = zx::time::infinite());
private:
zx::result<> Begin();
void OnWatchedEvent(fuchsia_io::wire::WatchEvent event, const std::string& instance);
bool has_begun_iterating_ = false;
bool idle_called_ = false;
// For doing blocking waits:
std::deque<std::string> entries_;
std::optional<fidl::UnownedClientEnd<fuchsia_io::Directory>> dir_;
std::optional<std::string> path_;
DirectoryWatcher directory_watcher_;
async::Loop loop_{&kAsyncLoopConfigNeverAttachToThread};
};
} // namespace component
#endif // LIB_COMPONENT_INCOMING_CPP_DIRECTORY_WATCHER_H_