mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-26 02:35:38 +08:00
Move DBus event processing from DBusConnection to DBusDispatcher
ref T291
This commit is contained in:
committed by
Klaus Basan
parent
59da68da5e
commit
a764fa0d03
@@ -19,137 +19,21 @@
|
||||
namespace XSwiftBus
|
||||
{
|
||||
|
||||
//! Functor struct deleteing an event
|
||||
struct EventDeleter
|
||||
{
|
||||
//! Delete functor
|
||||
void operator()(event *obj) const
|
||||
{
|
||||
event_del(obj);
|
||||
event_free(obj);
|
||||
}
|
||||
};
|
||||
|
||||
//! DBus watch handler
|
||||
class WatchHandler
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
WatchHandler(CDBusConnection *parent, DBusWatch *watch)
|
||||
: m_parent(parent), m_watch(watch)
|
||||
{
|
||||
const unsigned int flags = dbus_watch_get_flags(watch);
|
||||
short monitoredEvents = EV_PERSIST;
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) { monitoredEvents |= EV_READ; }
|
||||
if (flags & DBUS_WATCH_WRITABLE) { monitoredEvents |= EV_WRITE; }
|
||||
|
||||
const int fd = dbus_watch_get_unix_fd(watch);
|
||||
m_event.reset(event_new(parent->m_eventBase.get(), fd, monitoredEvents, callback, this));
|
||||
event_add(m_event.get(), nullptr);
|
||||
}
|
||||
|
||||
//! Get DBus watch
|
||||
DBusWatch *getWatch() { return m_watch; }
|
||||
|
||||
//! Get DBus watch
|
||||
const DBusWatch *getWatch() const { return m_watch; }
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
auto *watchHandler = static_cast<WatchHandler *>(data);
|
||||
watchHandler->m_parent->handleSocketReady(fd, event);
|
||||
}
|
||||
|
||||
CDBusConnection *m_parent = nullptr;
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
DBusWatch *m_watch = nullptr;
|
||||
};
|
||||
|
||||
//! DBus timeout handler
|
||||
class TimeoutHandler
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
TimeoutHandler(CDBusConnection *parent, DBusTimeout *timeout)
|
||||
: m_timeout(timeout)
|
||||
{
|
||||
timeval timer;
|
||||
const int interval = dbus_timeout_get_interval(timeout);
|
||||
timer.tv_sec = interval / 1000;
|
||||
timer.tv_usec = (interval % 1000) * 1000;
|
||||
|
||||
m_event.reset(evtimer_new(parent->m_eventBase.get(), callback, this));
|
||||
evtimer_add(m_event.get(), &timer);
|
||||
}
|
||||
|
||||
//! Get DBus timeout
|
||||
const DBusTimeout *getTimeout() const { return m_timeout; }
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
(void) fd; // unused
|
||||
(void) event; // unused
|
||||
auto *timeoutHandler = static_cast<TimeoutHandler *>(data);
|
||||
dbus_timeout_handle(timeoutHandler->m_timeout);
|
||||
}
|
||||
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
DBusTimeout *m_timeout = nullptr;
|
||||
};
|
||||
|
||||
//! Generic Timer
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer() = default;
|
||||
//! Constructor
|
||||
Timer(CDBusConnection *parent, const timeval &timeout, const std::function<void()> &func)
|
||||
: m_func(func)
|
||||
{
|
||||
m_event.reset(evtimer_new(parent->m_eventBase.get(), callback, this));
|
||||
evtimer_add(m_event.get(), &timeout);
|
||||
}
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
(void) fd; // unused
|
||||
(void) event; // unused
|
||||
auto *timer = static_cast<Timer *>(data);
|
||||
timer->m_func();
|
||||
delete timer;
|
||||
}
|
||||
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
std::function<void()> m_func;
|
||||
};
|
||||
|
||||
CDBusConnection::CDBusConnection()
|
||||
: m_eventBase(event_base_new())
|
||||
{
|
||||
dbus_threads_init_default();
|
||||
using namespace std::placeholders;
|
||||
m_watchCallbacks = WatchCallbacks(std::bind(&CDBusConnection::dbusAddWatch, this, _1),
|
||||
std::bind(&CDBusConnection::dbusRemoveWatch, this, _1),
|
||||
std::bind(&CDBusConnection::dbusWatchToggled, this, _1));
|
||||
}
|
||||
|
||||
m_timeoutCallbacks = TimeoutCallbacks(std::bind(&CDBusConnection::dbusAddTimeout, this, _1),
|
||||
std::bind(&CDBusConnection::dbusRemoveTimeout, this, _1),
|
||||
std::bind(&CDBusConnection::dbusTimeoutToggled, this, _1));
|
||||
}
|
||||
|
||||
CDBusConnection::~CDBusConnection()
|
||||
{
|
||||
close();
|
||||
if (m_connection) { dispatch(); }
|
||||
if (m_dispatcher) { m_dispatcher->remove(this); }
|
||||
}
|
||||
|
||||
bool CDBusConnection::connect(BusType type, const std::string &service)
|
||||
bool CDBusConnection::connect(BusType type)
|
||||
{
|
||||
assert(type == SessionBus);
|
||||
DBusError error;
|
||||
@@ -170,23 +54,39 @@ namespace XSwiftBus
|
||||
|
||||
// Don't exit application, if the connection is disconnected
|
||||
dbus_connection_set_exit_on_disconnect(m_connection.get(), false);
|
||||
|
||||
if (!setupMainloop())
|
||||
{
|
||||
m_connection.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
dbus_bus_request_name(m_connection.get(), service.c_str(), 0, &error);
|
||||
if (dbus_error_is_set(&error))
|
||||
{
|
||||
m_lastError = CDBusError(&error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDBusConnection::setDispatcher(CDBusDispatcher *dispatcher)
|
||||
{
|
||||
assert(dispatcher);
|
||||
|
||||
m_dispatcher = dispatcher;
|
||||
|
||||
m_dispatcher->add(this);
|
||||
|
||||
dbus_connection_set_watch_functions(
|
||||
m_connection.get(),
|
||||
dispatcher->m_watchCallbacks.add,
|
||||
dispatcher->m_watchCallbacks.remove,
|
||||
dispatcher->m_watchCallbacks.toggled,
|
||||
&dispatcher->m_watchCallbacks, nullptr);
|
||||
|
||||
dbus_connection_set_timeout_functions(
|
||||
m_connection.get(),
|
||||
dispatcher->m_timeoutCallbacks.add,
|
||||
dispatcher->m_timeoutCallbacks.remove,
|
||||
dispatcher->m_timeoutCallbacks.toggled,
|
||||
&dispatcher->m_timeoutCallbacks, nullptr);
|
||||
}
|
||||
|
||||
void CDBusConnection::requestName(const std::string &name)
|
||||
{
|
||||
DBusError error;
|
||||
dbus_error_init(&error);
|
||||
dbus_bus_request_name(m_connection.get(), name.c_str(), 0, &error);
|
||||
}
|
||||
|
||||
bool CDBusConnection::isConnected() const
|
||||
{
|
||||
return static_cast<bool>(m_connection);
|
||||
@@ -212,155 +112,35 @@ namespace XSwiftBus
|
||||
if (m_connection) { dbus_connection_close(m_connection.get()); }
|
||||
}
|
||||
|
||||
void CDBusConnection::runEventLoop()
|
||||
void CDBusConnection::dispatch()
|
||||
{
|
||||
if (!m_eventBase || !isConnected()) { return; }
|
||||
event_base_loop(m_eventBase.get(), EVLOOP_NONBLOCK);
|
||||
}
|
||||
|
||||
void CDBusConnection::runBlockingEventLoop()
|
||||
{
|
||||
if (!m_eventBase || !isConnected()) { return; }
|
||||
event_base_dispatch(m_eventBase.get());
|
||||
}
|
||||
|
||||
bool CDBusConnection::setupMainloop()
|
||||
{
|
||||
DBusDispatchStatus status;
|
||||
|
||||
if (dbus_connection_set_watch_functions(
|
||||
m_connection.get(),
|
||||
m_watchCallbacks.add,
|
||||
m_watchCallbacks.remove,
|
||||
m_watchCallbacks.toggled,
|
||||
&m_watchCallbacks, nullptr) == FALSE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (dbus_connection_set_timeout_functions(
|
||||
m_connection.get(),
|
||||
m_timeoutCallbacks.add,
|
||||
m_timeoutCallbacks.remove,
|
||||
m_timeoutCallbacks.toggled,
|
||||
&m_timeoutCallbacks, nullptr) == FALSE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dbus_connection_set_dispatch_status_function(
|
||||
m_connection.get(),
|
||||
dbusUpdateDispatchStatus,
|
||||
this, nullptr);
|
||||
|
||||
status = dbus_connection_get_dispatch_status(m_connection.get());
|
||||
if (status == DBUS_DISPATCH_DATA_REMAINS) { scheduleDBusDispatch(); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
dbus_bool_t CDBusConnection::dbusAddWatch(DBusWatch *watch)
|
||||
{
|
||||
if (dbus_watch_get_enabled(watch) == FALSE) { return true; }
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(watch);
|
||||
m_watchers.emplace(fd, std::make_unique<WatchHandler>(this, watch));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusRemoveWatch(DBusWatch *watch)
|
||||
{
|
||||
for (auto it = m_watchers.begin(); it != m_watchers.end();)
|
||||
{
|
||||
if (it->second->getWatch() == watch) { it = m_watchers.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusWatchToggled(DBusWatch *watch)
|
||||
{
|
||||
if (dbus_watch_get_enabled(watch) == TRUE) { dbusAddWatch(watch); }
|
||||
else { dbusRemoveWatch(watch); }
|
||||
}
|
||||
|
||||
dbus_bool_t CDBusConnection::dbusAddTimeout(DBusTimeout *timeout)
|
||||
{
|
||||
if (dbus_timeout_get_enabled(timeout) == FALSE) { return TRUE; }
|
||||
m_timeouts.emplace(m_timeouts.end(), std::make_unique<TimeoutHandler>(this, timeout));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusRemoveTimeout(DBusTimeout *timeout)
|
||||
{
|
||||
auto predicate = [timeout](const std::unique_ptr<TimeoutHandler> &ptr)
|
||||
{
|
||||
return ptr->getTimeout() == timeout;
|
||||
};
|
||||
|
||||
m_timeouts.erase(std::remove_if(m_timeouts.begin(), m_timeouts.end(), predicate), m_timeouts.end());
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusTimeoutToggled(DBusTimeout *timeout)
|
||||
{
|
||||
if (dbus_timeout_get_enabled(timeout) == TRUE)
|
||||
dbusAddTimeout(timeout);
|
||||
else
|
||||
dbusRemoveTimeout(timeout);
|
||||
}
|
||||
|
||||
void CDBusConnection::scheduleDBusDispatch()
|
||||
{
|
||||
const timeval timeout = {0, 0};
|
||||
// This is no memory leak. The allocated timer will be deleted in its own callback
|
||||
new Timer(this, timeout, [this]() { dbusDispatch(); });
|
||||
}
|
||||
|
||||
void CDBusConnection::handleSocketReady(evutil_socket_t fd, short event)
|
||||
{
|
||||
DBusDispatchStatus status;
|
||||
unsigned int flags = 0;
|
||||
|
||||
auto watcher = m_watchers.find(fd);
|
||||
if (watcher == m_watchers.end()) { return; }
|
||||
|
||||
dbus_connection_ref(m_connection.get());
|
||||
|
||||
if (evutil_socket_geterror(fd) != 0) { flags |= DBUS_WATCH_ERROR; }
|
||||
if (event & EV_READ) { flags |= DBUS_WATCH_READABLE; }
|
||||
if (event & EV_WRITE) { flags |= DBUS_WATCH_WRITABLE; }
|
||||
|
||||
dbus_watch_handle(watcher->second->getWatch(), flags);
|
||||
|
||||
status = dbus_connection_get_dispatch_status(m_connection.get());
|
||||
if (status == DBUS_DISPATCH_DATA_REMAINS) { dbusDispatch(); }
|
||||
|
||||
if (dbus_connection_get_dispatch_status(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS)
|
||||
{
|
||||
while (dbus_connection_dispatch(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
dbus_connection_unref(m_connection.get());
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusDispatch()
|
||||
void CDBusConnection::setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status)
|
||||
{
|
||||
dbus_connection_ref(m_connection.get());
|
||||
while (dbus_connection_dispatch(m_connection.get()) == DBUS_DISPATCH_DATA_REMAINS);
|
||||
dbus_connection_unref(m_connection.get());
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus newStatus)
|
||||
{
|
||||
(void)newStatus; // unused
|
||||
|
||||
DBusDispatchStatus status;
|
||||
|
||||
if (dbus_connection_get_is_connected(connection) == FALSE) { return; }
|
||||
|
||||
status = dbus_connection_get_dispatch_status(connection);
|
||||
if (status == DBUS_DISPATCH_DATA_REMAINS) { scheduleDBusDispatch(); }
|
||||
switch (status)
|
||||
{
|
||||
case DBUS_DISPATCH_DATA_REMAINS:
|
||||
//m_dispatcher->add(this);
|
||||
break;
|
||||
case DBUS_DISPATCH_COMPLETE:
|
||||
case DBUS_DISPATCH_NEED_MEMORY:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDBusConnection::dbusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus newStatus, void *data)
|
||||
void CDBusConnection::setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status, void *data)
|
||||
{
|
||||
auto *obj = static_cast<CDBusConnection *>(data);
|
||||
return obj->dbusUpdateDispatchStatus(connection, newStatus);
|
||||
return obj->setDispatchStatus(connection, status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "dbusmessage.h"
|
||||
#include "dbuserror.h"
|
||||
#include "dbuscallbacks.h"
|
||||
#include "dbusdispatcher.h"
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <dbus/dbus.h>
|
||||
@@ -24,12 +25,10 @@
|
||||
namespace XSwiftBus
|
||||
{
|
||||
|
||||
class WatchHandler;
|
||||
class TimeoutHandler;
|
||||
class CDBusObject;
|
||||
|
||||
//! DBus connection
|
||||
class CDBusConnection
|
||||
class CDBusConnection : public IDispatchable
|
||||
{
|
||||
public:
|
||||
//! Bus type
|
||||
@@ -47,7 +46,13 @@ namespace XSwiftBus
|
||||
CDBusConnection &operator=(const CDBusConnection &) = delete;
|
||||
|
||||
//! Connect to bus
|
||||
bool connect(BusType type, const std::string &service);
|
||||
bool connect(BusType type);
|
||||
|
||||
//! Set dispatcher
|
||||
void setDispatcher(CDBusDispatcher *dispatcher);
|
||||
|
||||
//! Request name to the bus
|
||||
void requestName(const std::string &name);
|
||||
|
||||
//! Is connected?
|
||||
bool isConnected() const;
|
||||
@@ -65,58 +70,24 @@ namespace XSwiftBus
|
||||
//! Close connection
|
||||
void close();
|
||||
|
||||
//! Run DBus event loop (non-blocking)
|
||||
void runEventLoop();
|
||||
|
||||
//! Run DBus event loop (blocking)
|
||||
void runBlockingEventLoop();
|
||||
|
||||
//! Get the last error
|
||||
CDBusError lastError() const { return m_lastError; }
|
||||
|
||||
protected:
|
||||
virtual void dispatch();
|
||||
|
||||
private:
|
||||
friend class WatchHandler;
|
||||
friend class TimeoutHandler;
|
||||
friend class Timer;
|
||||
|
||||
using WatchCallbacks = DBusAsyncCallbacks<DBusWatch>;
|
||||
using TimeoutCallbacks = DBusAsyncCallbacks<DBusTimeout>;
|
||||
|
||||
bool setupMainloop();
|
||||
|
||||
dbus_bool_t dbusAddWatch(DBusWatch *watch);
|
||||
void dbusRemoveWatch(DBusWatch *watch);
|
||||
void dbusWatchToggled(DBusWatch *watch);
|
||||
|
||||
dbus_bool_t dbusAddTimeout(DBusTimeout *timeout);
|
||||
void dbusRemoveTimeout(DBusTimeout *timeout);
|
||||
void dbusTimeoutToggled(DBusTimeout *timeout);
|
||||
|
||||
void scheduleDBusDispatch();
|
||||
void handleSocketReady(evutil_socket_t fd, short event);
|
||||
void dbusDispatch();
|
||||
void dbusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus newStatus);
|
||||
|
||||
static void dbusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus newStatus, void *data);
|
||||
|
||||
struct EventBaseDeleter
|
||||
{
|
||||
void operator()(event_base *obj) const { event_base_free(obj); }
|
||||
};
|
||||
void setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status);
|
||||
static void setDispatchStatus(DBusConnection *connection, DBusDispatchStatus status, void *data);
|
||||
|
||||
struct DBusConnectionDeleter
|
||||
{
|
||||
void operator()(DBusConnection *obj) const { dbus_connection_unref(obj); }
|
||||
};
|
||||
|
||||
std::unique_ptr<event_base, EventBaseDeleter> m_eventBase;
|
||||
CDBusDispatcher *m_dispatcher = nullptr;
|
||||
std::unique_ptr<DBusConnection, DBusConnectionDeleter> m_connection;
|
||||
CDBusError m_lastError;
|
||||
WatchCallbacks m_watchCallbacks;
|
||||
TimeoutCallbacks m_timeoutCallbacks;
|
||||
|
||||
std::unordered_multimap<evutil_socket_t, std::unique_ptr<WatchHandler>> m_watchers;
|
||||
std::vector<std::unique_ptr<TimeoutHandler>> m_timeouts;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
236
src/xswiftbus/dbusdispatcher.cpp
Normal file
236
src/xswiftbus/dbusdispatcher.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/* Copyright (C) 2018
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "dbusdispatcher.h"
|
||||
#include "dbusconnection.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace XSwiftBus
|
||||
{
|
||||
|
||||
//! Functor struct deleteing an event
|
||||
struct EventDeleter
|
||||
{
|
||||
//! Delete functor
|
||||
void operator()(event *obj) const
|
||||
{
|
||||
event_del(obj);
|
||||
event_free(obj);
|
||||
}
|
||||
};
|
||||
|
||||
//! DBus watch handler
|
||||
class WatchHandler
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
WatchHandler(event_base *base, DBusWatch *watch)
|
||||
: m_base(base), m_watch(watch)
|
||||
{
|
||||
const unsigned int flags = dbus_watch_get_flags(watch);
|
||||
short monitoredEvents = EV_PERSIST;
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE) { monitoredEvents |= EV_READ; }
|
||||
if (flags & DBUS_WATCH_WRITABLE) { monitoredEvents |= EV_WRITE; }
|
||||
|
||||
const int fd = dbus_watch_get_unix_fd(watch);
|
||||
m_event.reset(event_new(m_base, fd, monitoredEvents, callback, this));
|
||||
event_add(m_event.get(), nullptr);
|
||||
}
|
||||
|
||||
//! Get DBus watch
|
||||
DBusWatch *getWatch() { return m_watch; }
|
||||
|
||||
//! Get DBus watch
|
||||
const DBusWatch *getWatch() const { return m_watch; }
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
(void) fd; // Not really unused, but GCC/Clang still complain about it.
|
||||
auto *watchHandler = static_cast<WatchHandler *>(data);
|
||||
|
||||
unsigned int flags = 0;
|
||||
if (evutil_socket_geterror(fd) != 0) { flags |= DBUS_WATCH_ERROR; }
|
||||
if (event & EV_READ) { flags |= DBUS_WATCH_READABLE; }
|
||||
if (event & EV_WRITE) { flags |= DBUS_WATCH_WRITABLE; }
|
||||
dbus_watch_handle(watchHandler->m_watch, flags);
|
||||
}
|
||||
|
||||
event_base *m_base = nullptr;
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
DBusWatch *m_watch = nullptr;
|
||||
};
|
||||
|
||||
//! DBus timeout handler
|
||||
class TimeoutHandler
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
TimeoutHandler(event_base *base, DBusTimeout *timeout)
|
||||
: m_base(base), m_timeout(timeout)
|
||||
{
|
||||
timeval timer;
|
||||
const int interval = dbus_timeout_get_interval(timeout);
|
||||
timer.tv_sec = interval / 1000;
|
||||
timer.tv_usec = (interval % 1000) * 1000;
|
||||
|
||||
m_event.reset(evtimer_new(m_base, callback, this));
|
||||
evtimer_add(m_event.get(), &timer);
|
||||
}
|
||||
|
||||
//! Get DBus timeout
|
||||
const DBusTimeout *getTimeout() const { return m_timeout; }
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
(void) fd; // unused
|
||||
(void) event; // unused
|
||||
auto *timeoutHandler = static_cast<TimeoutHandler *>(data);
|
||||
dbus_timeout_handle(timeoutHandler->m_timeout);
|
||||
}
|
||||
|
||||
event_base *m_base = nullptr;
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
DBusTimeout *m_timeout = nullptr;
|
||||
};
|
||||
|
||||
//! Generic Timer
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer() = default;
|
||||
//! Constructor
|
||||
Timer(event_base *base, const timeval &timeout, const std::function<void()> &func)
|
||||
: m_base(base), m_func(func)
|
||||
{
|
||||
m_event.reset(evtimer_new(m_base, callback, this));
|
||||
evtimer_add(m_event.get(), &timeout);
|
||||
}
|
||||
|
||||
private:
|
||||
//! Event callback
|
||||
static void callback(evutil_socket_t fd, short event, void *data)
|
||||
{
|
||||
(void) fd; // unused
|
||||
(void) event; // unused
|
||||
auto *timer = static_cast<Timer *>(data);
|
||||
timer->m_func();
|
||||
delete timer;
|
||||
}
|
||||
|
||||
event_base *m_base = nullptr;
|
||||
std::unique_ptr<event, EventDeleter> m_event;
|
||||
std::function<void()> m_func;
|
||||
};
|
||||
|
||||
CDBusDispatcher::CDBusDispatcher() :
|
||||
m_eventBase(event_base_new())
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
m_watchCallbacks = WatchCallbacks(std::bind(&CDBusDispatcher::dbusAddWatch, this, _1),
|
||||
std::bind(&CDBusDispatcher::dbusRemoveWatch, this, _1),
|
||||
std::bind(&CDBusDispatcher::dbusWatchToggled, this, _1));
|
||||
|
||||
m_timeoutCallbacks = TimeoutCallbacks(std::bind(&CDBusDispatcher::dbusAddTimeout, this, _1),
|
||||
std::bind(&CDBusDispatcher::dbusRemoveTimeout, this, _1),
|
||||
std::bind(&CDBusDispatcher::dbusTimeoutToggled, this, _1));
|
||||
}
|
||||
|
||||
CDBusDispatcher::~CDBusDispatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void CDBusDispatcher::add(IDispatchable *dispatchable)
|
||||
{
|
||||
m_dispatchList.push_back(dispatchable);
|
||||
}
|
||||
|
||||
void CDBusDispatcher::remove(IDispatchable *dispatchable)
|
||||
{
|
||||
auto it = std::find(m_dispatchList.begin(), m_dispatchList.end(), dispatchable);
|
||||
if (it != m_dispatchList.end()) { m_dispatchList.erase(it); }
|
||||
}
|
||||
|
||||
void CDBusDispatcher::waitAndRun()
|
||||
{
|
||||
if (!m_eventBase) { return; }
|
||||
event_base_dispatch(m_eventBase.get());
|
||||
}
|
||||
|
||||
void CDBusDispatcher::runOnce()
|
||||
{
|
||||
if (!m_eventBase) { return; }
|
||||
event_base_loop(m_eventBase.get(), EVLOOP_NONBLOCK);
|
||||
dispatch();
|
||||
}
|
||||
|
||||
void CDBusDispatcher::dispatch()
|
||||
{
|
||||
if (m_dispatchList.empty()) { return; }
|
||||
|
||||
for (IDispatchable *dispatchable : m_dispatchList)
|
||||
{
|
||||
dispatchable->dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
dbus_bool_t CDBusDispatcher::dbusAddWatch(DBusWatch *watch)
|
||||
{
|
||||
if (dbus_watch_get_enabled(watch) == FALSE) { return true; }
|
||||
|
||||
int fd = dbus_watch_get_unix_fd(watch);
|
||||
m_watchers.emplace(fd, std::make_unique<WatchHandler>(m_eventBase.get(), watch));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDBusDispatcher::dbusRemoveWatch(DBusWatch *watch)
|
||||
{
|
||||
for (auto it = m_watchers.begin(); it != m_watchers.end();)
|
||||
{
|
||||
if (it->second->getWatch() == watch) { it = m_watchers.erase(it); }
|
||||
else { ++it; }
|
||||
}
|
||||
}
|
||||
|
||||
void CDBusDispatcher::dbusWatchToggled(DBusWatch *watch)
|
||||
{
|
||||
if (dbus_watch_get_enabled(watch) == TRUE) { dbusAddWatch(watch); }
|
||||
else { dbusRemoveWatch(watch); }
|
||||
}
|
||||
|
||||
dbus_bool_t CDBusDispatcher::dbusAddTimeout(DBusTimeout *timeout)
|
||||
{
|
||||
if (dbus_timeout_get_enabled(timeout) == FALSE) { return TRUE; }
|
||||
m_timeouts.emplace(m_timeouts.end(), std::make_unique<TimeoutHandler>(m_eventBase.get(), timeout));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDBusDispatcher::dbusRemoveTimeout(DBusTimeout *timeout)
|
||||
{
|
||||
auto predicate = [timeout](const std::unique_ptr<TimeoutHandler> &ptr)
|
||||
{
|
||||
return ptr->getTimeout() == timeout;
|
||||
};
|
||||
|
||||
m_timeouts.erase(std::remove_if(m_timeouts.begin(), m_timeouts.end(), predicate), m_timeouts.end());
|
||||
}
|
||||
|
||||
void CDBusDispatcher::dbusTimeoutToggled(DBusTimeout *timeout)
|
||||
{
|
||||
if (dbus_timeout_get_enabled(timeout) == TRUE)
|
||||
dbusAddTimeout(timeout);
|
||||
else
|
||||
dbusRemoveTimeout(timeout);
|
||||
}
|
||||
|
||||
}
|
||||
104
src/xswiftbus/dbusdispatcher.h
Normal file
104
src/xswiftbus/dbusdispatcher.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Copyright (C) 2018
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKSIM_XSWIFTBUS_DBUSDISPATCHER_H
|
||||
#define BLACKSIM_XSWIFTBUS_DBUSDISPATCHER_H
|
||||
|
||||
#include "dbuscallbacks.h"
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace XSwiftBus
|
||||
{
|
||||
|
||||
class WatchHandler;
|
||||
class TimeoutHandler;
|
||||
class CDBusConnection;
|
||||
class CDBusDispatcher;
|
||||
|
||||
//! Dispatchable Interface
|
||||
class IDispatchable
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
IDispatchable() = default;
|
||||
|
||||
//! Default destructor
|
||||
virtual ~IDispatchable() = default;
|
||||
|
||||
//! Dispatch execution method
|
||||
virtual void dispatch() = 0;
|
||||
|
||||
private:
|
||||
friend CDBusDispatcher;
|
||||
};
|
||||
|
||||
//! DBus Dispatcher
|
||||
class CDBusDispatcher
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
CDBusDispatcher();
|
||||
|
||||
//! Destructor
|
||||
virtual ~CDBusDispatcher();
|
||||
|
||||
//! Add dispatchable object
|
||||
void add(IDispatchable *dispatchable);
|
||||
|
||||
//! Remove dispatchable object
|
||||
void remove(IDispatchable *dispatchable);
|
||||
|
||||
//! Waits for events to be dispatched and handles them
|
||||
void waitAndRun();
|
||||
|
||||
//! Dispatches ready handlers and returns without waiting
|
||||
void runOnce();
|
||||
|
||||
private:
|
||||
friend class WatchHandler;
|
||||
friend class TimeoutHandler;
|
||||
friend class Timer;
|
||||
friend class CDBusConnection;
|
||||
friend class CDBusServer;
|
||||
|
||||
struct EventBaseDeleter
|
||||
{
|
||||
void operator()(event_base *obj) const { event_base_free(obj); }
|
||||
};
|
||||
|
||||
using WatchCallbacks = DBusAsyncCallbacks<DBusWatch>;
|
||||
using TimeoutCallbacks = DBusAsyncCallbacks<DBusTimeout>;
|
||||
|
||||
void dispatch();
|
||||
|
||||
dbus_bool_t dbusAddWatch(DBusWatch *watch);
|
||||
void dbusRemoveWatch(DBusWatch *watch);
|
||||
void dbusWatchToggled(DBusWatch *watch);
|
||||
|
||||
dbus_bool_t dbusAddTimeout(DBusTimeout *timeout);
|
||||
void dbusRemoveTimeout(DBusTimeout *timeout);
|
||||
void dbusTimeoutToggled(DBusTimeout *timeout);
|
||||
|
||||
WatchCallbacks m_watchCallbacks;
|
||||
TimeoutCallbacks m_timeoutCallbacks;
|
||||
std::unordered_multimap<evutil_socket_t, std::unique_ptr<WatchHandler>> m_watchers;
|
||||
std::vector<std::unique_ptr<TimeoutHandler>> m_timeouts;
|
||||
std::unique_ptr<event_base, EventBaseDeleter> m_eventBase;
|
||||
|
||||
std::vector<IDispatchable*> m_dispatchList;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -68,7 +68,7 @@ namespace XSwiftBus
|
||||
m_traffic->setPlaneViewMenu(m_planeViewSubMenu);
|
||||
|
||||
// Todo: retry if it fails
|
||||
bool success = m_dbusConnection->connect(CDBusConnection::SessionBus, xswiftbusServiceName());
|
||||
bool success = m_dbusConnection->connect(CDBusConnection::SessionBus);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -76,6 +76,9 @@ namespace XSwiftBus
|
||||
return;
|
||||
}
|
||||
|
||||
m_dbusConnection->setDispatcher(&m_dbusDispatcher);
|
||||
m_dbusConnection->requestName(xswiftbusServiceName());
|
||||
|
||||
m_service->setDBusConnection(m_dbusConnection);
|
||||
m_service->registerDBusObjectPath(m_service->InterfaceName(), m_service->ObjectPath());
|
||||
m_traffic->setDBusConnection(m_dbusConnection);
|
||||
@@ -83,6 +86,7 @@ namespace XSwiftBus
|
||||
m_weather->setDBusConnection(m_dbusConnection);
|
||||
m_weather->registerDBusObjectPath(m_weather->InterfaceName(), m_weather->ObjectPath());
|
||||
|
||||
|
||||
INFO_LOG("XSwiftBus started.");
|
||||
}
|
||||
|
||||
@@ -117,6 +121,7 @@ namespace XSwiftBus
|
||||
float CPlugin::flightLoopCallback(float, float, int, void *refcon)
|
||||
{
|
||||
auto *plugin = static_cast<CPlugin *>(refcon);
|
||||
plugin->m_dbusDispatcher.runOnce();
|
||||
if (plugin->m_service) { plugin->m_service->processDBus(); }
|
||||
if (plugin->m_weather) { plugin->m_weather->processDBus(); }
|
||||
if (plugin->m_traffic) { plugin->m_traffic->processDBus(); }
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include "dbusconnection.h"
|
||||
#include "dbusdispatcher.h"
|
||||
#include "datarefs.h"
|
||||
#include "XPLM/XPLMCamera.h"
|
||||
#include "menus.h"
|
||||
@@ -53,6 +54,7 @@ namespace XSwiftBus
|
||||
void onAircraftRepositioned();
|
||||
|
||||
private:
|
||||
CDBusDispatcher m_dbusDispatcher;
|
||||
std::shared_ptr<CDBusConnection> m_dbusConnection;
|
||||
std::unique_ptr<CService> m_service;
|
||||
std::unique_ptr<CTraffic> m_traffic;
|
||||
|
||||
Reference in New Issue
Block a user