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,
|
Publisher::Publisher(Client &_client, const char *_name,
|
||||||
std::forward_list<Service> _services,
|
|
||||||
ErrorHandler &_error_handler) noexcept
|
ErrorHandler &_error_handler) noexcept
|
||||||
:error_handler(_error_handler),
|
:error_handler(_error_handler),
|
||||||
name(MakePidName(_name)),
|
name(MakePidName(_name)),
|
||||||
client(_client),
|
client(_client),
|
||||||
defer_register_services(client.GetEventLoop(),
|
defer_register_services(client.GetEventLoop(),
|
||||||
BIND_THIS_METHOD(DeferredRegisterServices)),
|
BIND_THIS_METHOD(DeferredRegisterServices))
|
||||||
services(std::move(_services))
|
|
||||||
{
|
{
|
||||||
assert(!services.empty());
|
|
||||||
|
|
||||||
client.AddListener(*this);
|
client.AddListener(*this);
|
||||||
|
|
||||||
if (client.IsConnected())
|
|
||||||
defer_register_services.Schedule();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Publisher::~Publisher() noexcept
|
Publisher::~Publisher() noexcept
|
||||||
{
|
{
|
||||||
|
assert(services.empty());
|
||||||
|
|
||||||
client.RemoveListener(*this);
|
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
|
inline void
|
||||||
Publisher::GroupCallback(AvahiEntryGroup *g,
|
Publisher::GroupCallback(AvahiEntryGroup *g,
|
||||||
AvahiEntryGroupState state) noexcept
|
AvahiEntryGroupState state) noexcept
|
||||||
@ -82,6 +95,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* And recreate the services */
|
/* And recreate the services */
|
||||||
|
should_reset_group = false;
|
||||||
RegisterServices(*g);
|
RegisterServices(*g);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -122,7 +136,7 @@ AddService(AvahiEntryGroup &group, const Service &service,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
AddServices(AvahiEntryGroup &group,
|
AddServices(AvahiEntryGroup &group,
|
||||||
const std::forward_list<Service> &services, const char *name)
|
const IntrusiveList<Service> &services, const char *name)
|
||||||
{
|
{
|
||||||
for (const auto &i : services)
|
for (const auto &i : services)
|
||||||
AddService(group, i, name);
|
AddService(group, i, name);
|
||||||
@ -131,11 +145,20 @@ AddServices(AvahiEntryGroup &group,
|
|||||||
void
|
void
|
||||||
Publisher::RegisterServices(AvahiEntryGroup &g)
|
Publisher::RegisterServices(AvahiEntryGroup &g)
|
||||||
{
|
{
|
||||||
|
if (should_reset_group) {
|
||||||
|
should_reset_group = false;
|
||||||
|
avahi_entry_group_reset(&g);
|
||||||
|
}
|
||||||
|
|
||||||
AddServices(g, services, name.c_str());
|
AddServices(g, services, name.c_str());
|
||||||
|
|
||||||
if (int error = avahi_entry_group_commit(&g);
|
if (!services.empty()) {
|
||||||
error != AVAHI_OK)
|
should_reset_group = true;
|
||||||
throw MakeError(error, "Failed to commit Avahi service group");
|
|
||||||
|
if (int error = avahi_entry_group_commit(&g);
|
||||||
|
error != AVAHI_OK)
|
||||||
|
throw MakeError(error, "Failed to commit Avahi service group");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -144,6 +167,8 @@ Publisher::RegisterServices(AvahiClient *c)
|
|||||||
assert(visible);
|
assert(visible);
|
||||||
|
|
||||||
if (!group) {
|
if (!group) {
|
||||||
|
assert(!should_reset_group);
|
||||||
|
|
||||||
group.reset(avahi_entry_group_new(c, GroupCallback, this));
|
group.reset(avahi_entry_group_new(c, GroupCallback, this));
|
||||||
if (!group)
|
if (!group)
|
||||||
throw MakeError(*c, "Failed to create Avahi service group");
|
throw MakeError(*c, "Failed to create Avahi service group");
|
||||||
@ -175,8 +200,12 @@ Publisher::HideServices() noexcept
|
|||||||
|
|
||||||
defer_register_services.Cancel();
|
defer_register_services.Cancel();
|
||||||
|
|
||||||
if (group)
|
if (group) {
|
||||||
|
should_reset_group = false;
|
||||||
avahi_entry_group_reset(group.get());
|
avahi_entry_group_reset(group.get());
|
||||||
|
} else {
|
||||||
|
assert(!should_reset_group);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -194,7 +223,10 @@ Publisher::ShowServices() noexcept
|
|||||||
void
|
void
|
||||||
Publisher::OnAvahiConnect(AvahiClient *c) noexcept
|
Publisher::OnAvahiConnect(AvahiClient *c) noexcept
|
||||||
{
|
{
|
||||||
if (visible)
|
assert(!group);
|
||||||
|
assert(!should_reset_group);
|
||||||
|
|
||||||
|
if (visible && !services.empty())
|
||||||
try {
|
try {
|
||||||
RegisterServices(c);
|
RegisterServices(c);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -206,12 +238,14 @@ void
|
|||||||
Publisher::OnAvahiDisconnect() noexcept
|
Publisher::OnAvahiDisconnect() noexcept
|
||||||
{
|
{
|
||||||
group.reset();
|
group.reset();
|
||||||
|
should_reset_group = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Publisher::OnAvahiChanged() noexcept
|
Publisher::OnAvahiChanged() noexcept
|
||||||
{
|
{
|
||||||
group.reset();
|
group.reset();
|
||||||
|
should_reset_group = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Avahi
|
} // namespace Avahi
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
#include "EntryGroup.hxx"
|
#include "EntryGroup.hxx"
|
||||||
#include "ConnectionListener.hxx"
|
#include "ConnectionListener.hxx"
|
||||||
#include "event/DeferEvent.hxx"
|
#include "event/DeferEvent.hxx"
|
||||||
|
#include "util/IntrusiveList.hxx"
|
||||||
|
|
||||||
#include <avahi-client/publish.h>
|
#include <avahi-client/publish.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <forward_list>
|
|
||||||
|
|
||||||
class SocketAddress;
|
class SocketAddress;
|
||||||
|
|
||||||
@ -36,7 +36,14 @@ class Publisher final : ConnectionListener {
|
|||||||
|
|
||||||
EntryGroupPtr group;
|
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
|
* Shall the published services be visible? This is controlled by
|
||||||
@ -46,13 +53,28 @@ class Publisher final : ConnectionListener {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Publisher(Client &client, const char *_name,
|
Publisher(Client &client, const char *_name,
|
||||||
std::forward_list<Service> _services,
|
|
||||||
ErrorHandler &_error_handler) noexcept;
|
ErrorHandler &_error_handler) noexcept;
|
||||||
~Publisher() noexcept;
|
~Publisher() noexcept;
|
||||||
|
|
||||||
Publisher(const Publisher &) = delete;
|
Publisher(const Publisher &) = delete;
|
||||||
Publisher &operator=(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
|
* Temporarily hide all registered services. You can undo this
|
||||||
* with ShowServices().
|
* with ShowServices().
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/IntrusiveList.hxx"
|
||||||
|
|
||||||
#include <avahi-common/address.h>
|
#include <avahi-common/address.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -14,7 +16,7 @@ namespace Avahi {
|
|||||||
/**
|
/**
|
||||||
* A service that will be published by class #Publisher.
|
* A service that will be published by class #Publisher.
|
||||||
*/
|
*/
|
||||||
struct Service {
|
struct Service : IntrusiveListHook<> {
|
||||||
AvahiIfIndex interface = AVAHI_IF_UNSPEC;
|
AvahiIfIndex interface = AVAHI_IF_UNSPEC;
|
||||||
AvahiProtocol protocol = AVAHI_PROTO_UNSPEC;
|
AvahiProtocol protocol = AVAHI_PROTO_UNSPEC;
|
||||||
std::string type;
|
std::string type;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "Helper.hxx"
|
#include "Helper.hxx"
|
||||||
#include "lib/avahi/Client.hxx"
|
#include "lib/avahi/Client.hxx"
|
||||||
#include "lib/avahi/ErrorHandler.hxx"
|
#include "lib/avahi/ErrorHandler.hxx"
|
||||||
#include "lib/avahi/Service.hxx"
|
|
||||||
#include "lib/fmt/RuntimeError.hxx"
|
#include "lib/fmt/RuntimeError.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
@ -29,12 +28,19 @@ static std::weak_ptr<SharedAvahiClient> shared_avahi_client;
|
|||||||
inline
|
inline
|
||||||
AvahiHelper::AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
AvahiHelper::AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
||||||
const char *service_name,
|
const char *service_name,
|
||||||
std::forward_list<Avahi::Service> &&services)
|
const char *service_type, unsigned port)
|
||||||
:client(std::move(_client)),
|
:client(std::move(_client)),
|
||||||
publisher(client->client, service_name,
|
publisher(client->client, service_name, *client),
|
||||||
std::move(services), *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>
|
std::unique_ptr<AvahiHelper>
|
||||||
AvahiInit(EventLoop &event_loop, const char *service_name,
|
AvahiInit(EventLoop &event_loop, const char *service_name,
|
||||||
@ -49,11 +55,6 @@ AvahiInit(EventLoop &event_loop, const char *service_name,
|
|||||||
shared_avahi_client = client =
|
shared_avahi_client = client =
|
||||||
std::make_shared<SharedAvahiClient>(event_loop);
|
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,
|
return std::make_unique<AvahiHelper>(std::move(client), service_name,
|
||||||
std::move(services));
|
service_type, port);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "lib/avahi/Publisher.hxx"
|
#include "lib/avahi/Publisher.hxx"
|
||||||
|
#include "lib/avahi/Service.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -15,11 +16,12 @@ class SharedAvahiClient;
|
|||||||
class AvahiHelper final {
|
class AvahiHelper final {
|
||||||
std::shared_ptr<SharedAvahiClient> client;
|
std::shared_ptr<SharedAvahiClient> client;
|
||||||
Avahi::Publisher publisher;
|
Avahi::Publisher publisher;
|
||||||
|
Avahi::Service service;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
AvahiHelper(std::shared_ptr<SharedAvahiClient> _client,
|
||||||
const char *service_name,
|
const char *service_name,
|
||||||
std::forward_list<Avahi::Service> &&services);
|
const char *service_type, unsigned port);
|
||||||
~AvahiHelper() noexcept;
|
~AvahiHelper() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user