swift
dbusdispatcher.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2018 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "dbusdispatcher.h"
5 
6 #include <algorithm>
7 
8 #include "dbusconnection.h"
9 
10 namespace XSwiftBus
11 {
12 
14  struct EventDeleter
15  {
17  void operator()(event *obj) const
18  {
19  event_del(obj);
20  event_free(obj);
21  }
22  };
23 
26  {
27  public:
29  WatchHandler(event_base *base, DBusWatch *watch) : m_base(base), m_watch(watch)
30  {
31  const unsigned int flags = dbus_watch_get_flags(watch);
32  short monitoredEvents = EV_PERSIST;
33 
34  if (flags & DBUS_WATCH_READABLE) { monitoredEvents |= EV_READ; }
35  if (flags & DBUS_WATCH_WRITABLE) { monitoredEvents |= EV_WRITE; }
36 
37  const int fd = dbus_watch_get_unix_fd(watch);
38  m_event.reset(event_new(m_base, fd, monitoredEvents, callback, this));
39  event_add(m_event.get(), nullptr);
40  }
41 
43  DBusWatch *getWatch() { return m_watch; }
44 
46  const DBusWatch *getWatch() const { return m_watch; }
47 
48  private:
50  static void callback(evutil_socket_t fd, short event, void *data)
51  {
52  (void)fd; // Not really unused, but GCC/Clang still complain about it.
53  auto *watchHandler = static_cast<WatchHandler *>(data);
54 
55  unsigned int flags = 0;
56  if (event & EV_READ) { flags |= DBUS_WATCH_READABLE; }
57  if (event & EV_WRITE) { flags |= DBUS_WATCH_WRITABLE; }
58  dbus_watch_handle(watchHandler->m_watch, flags);
59  }
60 
61  event_base *m_base = nullptr;
62  std::unique_ptr<event, EventDeleter> m_event;
63  DBusWatch *m_watch = nullptr;
64  };
65 
68  {
69  public:
71  TimeoutHandler(event_base *base, DBusTimeout *timeout) : m_base(base), m_timeout(timeout)
72  {
73  timeval timer;
74  const int interval = dbus_timeout_get_interval(timeout);
75  timer.tv_sec = interval / 1000;
76  timer.tv_usec = (interval % 1000) * 1000;
77 
78  m_event.reset(evtimer_new(m_base, callback, this));
79  evtimer_add(m_event.get(), &timer);
80  }
81 
83  const DBusTimeout *getTimeout() const { return m_timeout; }
84 
85  private:
87  static void callback(evutil_socket_t fd, short event, void *data)
88  {
89  (void)fd; // unused
90  (void)event; // unused
91  auto *timeoutHandler = static_cast<TimeoutHandler *>(data);
92  dbus_timeout_handle(timeoutHandler->m_timeout);
93  }
94 
95  event_base *m_base = nullptr;
96  std::unique_ptr<event, EventDeleter> m_event;
97  DBusTimeout *m_timeout = nullptr;
98  };
99 
101  class Timer
102  {
103  public:
104  Timer() = default;
106  Timer(event_base *base, const timeval &timeout, const std::function<void()> &func) : m_base(base), m_func(func)
107  {
108  m_event.reset(evtimer_new(m_base, callback, this));
109  evtimer_add(m_event.get(), &timeout);
110  }
111 
112  private:
114  static void callback(evutil_socket_t fd, short event, void *data)
115  {
116  (void)fd; // unused
117  (void)event; // unused
118  auto *timer = static_cast<Timer *>(data);
119  timer->m_func();
120  delete timer;
121  }
122 
123  event_base *m_base = nullptr;
124  std::unique_ptr<event, EventDeleter> m_event;
125  std::function<void()> m_func;
126  };
127 
128  CDBusDispatcher::CDBusDispatcher() : m_eventBase(event_base_new())
129  {
130  using namespace std::placeholders;
131  m_watchCallbacks = WatchCallbacks(std::bind(&CDBusDispatcher::dbusAddWatch, this, _1),
132  std::bind(&CDBusDispatcher::dbusRemoveWatch, this, _1),
133  std::bind(&CDBusDispatcher::dbusWatchToggled, this, _1));
134 
135  m_timeoutCallbacks = TimeoutCallbacks(std::bind(&CDBusDispatcher::dbusAddTimeout, this, _1),
136  std::bind(&CDBusDispatcher::dbusRemoveTimeout, this, _1),
137  std::bind(&CDBusDispatcher::dbusTimeoutToggled, this, _1));
138  }
139 
141 
142  void CDBusDispatcher::add(IDispatchable *dispatchable) { m_dispatchList.push_back(dispatchable); }
143 
145  {
146  auto it = std::find(m_dispatchList.begin(), m_dispatchList.end(), dispatchable);
147  if (it != m_dispatchList.end()) { m_dispatchList.erase(it); }
148  }
149 
151  {
152  if (!m_eventBase) { return; }
153  event_base_dispatch(m_eventBase.get());
154  }
155 
157  {
158  if (!m_eventBase) { return; }
159  event_base_loop(m_eventBase.get(), EVLOOP_NONBLOCK);
160  dispatch();
161  }
162 
163  void CDBusDispatcher::dispatch()
164  {
165  if (m_dispatchList.empty()) { return; }
166 
167  for (IDispatchable *dispatchable : m_dispatchList) { dispatchable->dispatch(); }
168  }
169 
170  dbus_bool_t CDBusDispatcher::dbusAddWatch(DBusWatch *watch)
171  {
172  if (dbus_watch_get_enabled(watch) == FALSE) { return true; }
173 
174  int fd = dbus_watch_get_unix_fd(watch);
175  m_watchers.emplace(fd, std::make_unique<WatchHandler>(m_eventBase.get(), watch));
176  return true;
177  }
178 
179  void CDBusDispatcher::dbusRemoveWatch(const DBusWatch *watch)
180  {
181  for (auto it = m_watchers.begin(); it != m_watchers.end();)
182  {
183  if (it->second->getWatch() == watch) { it = m_watchers.erase(it); }
184  else { ++it; }
185  }
186  }
187 
188  void CDBusDispatcher::dbusWatchToggled(DBusWatch *watch)
189  {
190  if (dbus_watch_get_enabled(watch) == TRUE) { dbusAddWatch(watch); }
191  else { dbusRemoveWatch(watch); }
192  }
193 
194  dbus_bool_t CDBusDispatcher::dbusAddTimeout(DBusTimeout *timeout)
195  {
196  if (dbus_timeout_get_enabled(timeout) == FALSE) { return TRUE; }
197  m_timeouts.emplace(m_timeouts.end(), std::make_unique<TimeoutHandler>(m_eventBase.get(), timeout));
198  return true;
199  }
200 
201  void CDBusDispatcher::dbusRemoveTimeout(DBusTimeout *timeout)
202  {
203  auto predicate = [timeout](const std::unique_ptr<TimeoutHandler> &ptr) { return ptr->getTimeout() == timeout; };
204 
205  m_timeouts.erase(std::remove_if(m_timeouts.begin(), m_timeouts.end(), predicate), m_timeouts.end());
206  }
207 
208  void CDBusDispatcher::dbusTimeoutToggled(DBusTimeout *timeout)
209  {
210  if (dbus_timeout_get_enabled(timeout) == TRUE)
211  dbusAddTimeout(timeout);
212  else
213  dbusRemoveTimeout(timeout);
214  }
215 
216 } // namespace XSwiftBus
void add(IDispatchable *dispatchable)
Add dispatchable object.
virtual ~CDBusDispatcher()
Destructor.
void remove(IDispatchable *dispatchable)
Remove dispatchable object.
void runOnce()
Dispatches ready handlers and returns without waiting.
void waitAndRun()
Waits for events to be dispatched and handles them.
Dispatchable Interface.
DBus timeout handler.
TimeoutHandler(event_base *base, DBusTimeout *timeout)
Constructor.
const DBusTimeout * getTimeout() const
Get DBus timeout.
Generic Timer.
Timer(event_base *base, const timeval &timeout, const std::function< void()> &func)
Constructor.
DBus watch handler.
DBusWatch * getWatch()
Get DBus watch.
WatchHandler(event_base *base, DBusWatch *watch)
Constructor.
const DBusWatch * getWatch() const
Get DBus watch.
Plugin loaded by X-Plane which publishes a DBus service.
Definition: command.h:14
Functor struct deleteing an event.
void operator()(event *obj) const
Delete functor.