lib/avahi/Publisher: make the service list dynamic
This allows editing the list of services at any time instead of passing a constant list at construction time. To do this, Service instances are now caller-owned and managed in an IntrusiveList instead of Publisher-owned in a std::forward_list.
This commit is contained in:
parent
b20b773189
commit
461da92064
@ -38,28 +38,41 @@ MakePidName(const char *prefix) noexcept
|
||||
}
|
||||
|
||||
Publisher::Publisher(Client &_client, const char *_name,
|
||||
std::forward_list<Service> _services,
|
||||
ErrorHandler &_error_handler) noexcept
|
||||
:error_handler(_error_handler),
|
||||
name(MakePidName(_name)),
|
||||
client(_client),
|
||||
defer_register_services(client.GetEventLoop(),
|
||||
BIND_THIS_METHOD(DeferredRegisterServices)),
|
||||
services(std::move(_services))
|
||||
BIND_THIS_METHOD(DeferredRegisterServices))
|
||||
{
|
||||
assert(!services.empty());
|
||||
|
||||
client.AddListener(*this);
|
||||
|
||||
if (client.IsConnected())
|
||||
defer_register_services.Schedule();
|
||||
}
|
||||
|
||||
Publisher::~Publisher() noexcept
|
||||
{
|
||||
assert(services.empty());
|
||||
|
||||
client.RemoveListener(*this);
|
||||
}
|
||||
|
||||
void
|
||||
Publisher::AddService(Service &service) noexcept
|
||||
{
|
||||
services.push_back(service);
|
||||
|
||||
if (visible && client.IsConnected())
|
||||
defer_register_services.Schedule();
|
||||
}
|
||||
|
||||
void
|
||||
Publisher::RemoveService(Service &service) noexcept
|
||||
{
|
||||
services.erase(services.iterator_to(service));
|
||||
|
||||
if (visible && client.IsConnected())
|
||||
defer_register_services.Schedule();
|
||||
}
|
||||
|
||||
inline void
|
||||
Publisher::GroupCallback(AvahiEntryGroup *g,
|
||||
AvahiEntryGroupState state) noexcept
|
||||
@ -82,6 +95,7 @@ try {
|
||||
}
|
||||
|
||||
/* And recreate the services */
|
||||
should_reset_group = false;
|
||||
RegisterServices(*g);
|
||||
break;
|
||||
|
||||
@ -122,7 +136,7 @@ AddService(AvahiEntryGroup &group, const Service &service,
|
||||
|
||||
static void
|
||||
AddServices(AvahiEntryGroup &group,
|
||||
const std::forward_list<Service> &services, const char *name)
|
||||
const IntrusiveList<Service> &services, const char *name)
|
||||
{
|
||||
for (const auto &i : services)
|
||||
AddService(group, i, name);
|
||||
@ -131,11 +145,20 @@ AddServices(AvahiEntryGroup &group,
|
||||
void
|
||||
Publisher::RegisterServices(AvahiEntryGroup &g)
|
||||
{
|
||||
if (should_reset_group) {
|
||||
should_reset_group = false;
|
||||
avahi_entry_group_reset(&g);
|
||||
}
|
||||
|
||||
AddServices(g, services, name.c_str());
|
||||
|
||||
if (int error = avahi_entry_group_commit(&g);
|
||||
error != AVAHI_OK)
|
||||
throw MakeError(error, "Failed to commit Avahi service group");
|
||||
if (!services.empty()) {
|
||||
should_reset_group = true;
|
||||
|
||||
if (int error = avahi_entry_group_commit(&g);
|
||||
error != AVAHI_OK)
|
||||
throw MakeError(error, "Failed to commit Avahi service group");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -144,6 +167,8 @@ Publisher::RegisterServices(AvahiClient *c)
|
||||
assert(visible);
|
||||
|
||||
if (!group) {
|
||||
assert(!should_reset_group);
|
||||
|
||||
group.reset(avahi_entry_group_new(c, GroupCallback, this));
|
||||
if (!group)
|
||||
throw MakeError(*c, "Failed to create Avahi service group");
|
||||
@ -175,8 +200,12 @@ Publisher::HideServices() noexcept
|
||||
|
||||
defer_register_services.Cancel();
|
||||
|
||||
if (group)
|
||||
if (group) {
|
||||
should_reset_group = false;
|
||||
avahi_entry_group_reset(group.get());
|
||||
} else {
|
||||
assert(!should_reset_group);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -194,7 +223,10 @@ Publisher::ShowServices() noexcept
|
||||
void
|
||||
Publisher::OnAvahiConnect(AvahiClient *c) noexcept
|
||||
{
|
||||
if (visible)
|
||||
assert(!group);
|
||||
assert(!should_reset_group);
|
||||
|
||||
if (visible && !services.empty())
|
||||
try {
|
||||
RegisterServices(c);
|
||||
} catch (...) {
|
||||
@ -206,12 +238,14 @@ void
|
||||
Publisher::OnAvahiDisconnect() noexcept
|
||||
{
|
||||
group.reset();
|
||||
should_reset_group = false;
|
||||
}
|
||||
|
||||
void
|
||||
Publisher::OnAvahiChanged() noexcept
|
||||
{
|
||||
group.reset();
|
||||
should_reset_group = false;
|
||||
}
|
||||
|
||||
} // namespace Avahi
|
||||
|
@ -7,11 +7,11 @@
|
||||
#include "EntryGroup.hxx"
|
||||
#include "ConnectionListener.hxx"
|
||||
#include "event/DeferEvent.hxx"
|
||||
#include "util/IntrusiveList.hxx"
|
||||
|
||||
#include <avahi-client/publish.h>
|
||||
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
|
||||
class SocketAddress;
|
||||
|
||||
@ -36,7 +36,14 @@ class Publisher final : ConnectionListener {
|
||||
|
||||
EntryGroupPtr group;
|
||||
|
||||
const std::forward_list<Service> services;
|
||||
IntrusiveList<Service> services;
|
||||
|
||||
/**
|
||||
* Should avahi_entry_group_reset() be called by the next
|
||||
* RegisterServices() call? This is true if the #gorup is
|
||||
* non-empty.
|
||||
*/
|
||||
bool should_reset_group = false;
|
||||
|
||||
/**
|
||||
* Shall the published services be visible? This is controlled by
|
||||
@ -46,13 +53,28 @@ class Publisher final : ConnectionListener {
|
||||
|
||||
public:
|
||||
Publisher(Client &client, const char *_name,
|
||||
std::forward_list<Service> _services,
|
||||
ErrorHandler &_error_handler) noexcept;
|
||||
~Publisher() noexcept;
|
||||
|
||||
Publisher(const Publisher &) = delete;
|
||||
Publisher &operator=(const Publisher &) = delete;
|
||||
|
||||
/**
|
||||
* Publish another service.
|
||||
*
|
||||
* @param service a #Service instance owned by the caller (it
|
||||
* must remain valid until you call RemoveService())
|
||||
*/
|
||||
void AddService(Service &service) noexcept;
|
||||
|
||||
/**
|
||||
* Unpublish a service.
|
||||
*
|
||||
* @param service a #Service instance which was previously
|
||||
* passed to AddService()
|
||||
*/
|
||||
void RemoveService(Service &service) noexcept;
|
||||
|
||||
/**
|
||||
* Temporarily hide all registered services. You can undo this
|
||||
* with ShowServices().
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/IntrusiveList.hxx"
|
||||
|
||||
#include <avahi-common/address.h>
|
||||
|
||||
#include <cstdint>
|
||||
@ -14,7 +16,7 @@ namespace Avahi {
|
||||
/**
|
||||
* A service that will be published by class #Publisher.
|
||||
*/
|
||||
struct Service {
|
||||
struct Service : IntrusiveListHook<> {
|
||||
AvahiIfIndex interface = AVAHI_IF_UNSPEC;
|
||||
AvahiProtocol protocol = AVAHI_PROTO_UNSPEC;
|
||||
std::string type;
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "Helper.hxx"
|
||||
#include "lib/avahi/Client.hxx"
|
||||
#include "lib/avahi/ErrorHandler.hxx"
|
||||
#include "lib/avahi/Service.hxx"
|
||||
#include "lib/fmt/RuntimeError.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
@ -29,12 +28,19 @@ static std::weak_ptr<SharedAvahiClient> shared_avahi_client;
|
||||
inline
|
||||
AvahiHelper::AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
||||
const char *service_name,
|
||||
std::forward_list<Avahi::Service> &&services)
|
||||
const char *service_type, unsigned port)
|
||||
:client(std::move(_client)),
|
||||
publisher(client->client, service_name,
|
||||
std::move(services), *client) {}
|
||||
publisher(client->client, service_name, *client),
|
||||
service(AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
|
||||
service_type, port)
|
||||
{
|
||||
publisher.AddService(service);
|
||||
}
|
||||
|
||||
AvahiHelper::~AvahiHelper() noexcept = default;
|
||||
AvahiHelper::~AvahiHelper() noexcept
|
||||
{
|
||||
publisher.RemoveService(service);
|
||||
}
|
||||
|
||||
std::unique_ptr<AvahiHelper>
|
||||
AvahiInit(EventLoop &event_loop, const char *service_name,
|
||||
@ -49,11 +55,6 @@ AvahiInit(EventLoop &event_loop, const char *service_name,
|
||||
shared_avahi_client = client =
|
||||
std::make_shared<SharedAvahiClient>(event_loop);
|
||||
|
||||
std::forward_list<Avahi::Service> services;
|
||||
services.emplace_front(AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
service_type, port);
|
||||
|
||||
return std::make_unique<AvahiHelper>(std::move(client), service_name,
|
||||
std::move(services));
|
||||
service_type, port);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/avahi/Publisher.hxx"
|
||||
#include "lib/avahi/Service.hxx"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -15,11 +16,12 @@ class SharedAvahiClient;
|
||||
class AvahiHelper final {
|
||||
std::shared_ptr<SharedAvahiClient> client;
|
||||
Avahi::Publisher publisher;
|
||||
Avahi::Service service;
|
||||
|
||||
public:
|
||||
AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
||||
const char *service_name,
|
||||
std::forward_list<Avahi::Service> &&services);
|
||||
const char *service_type, unsigned port);
|
||||
~AvahiHelper() noexcept;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user