Fcitx
objectvtable_sdbus.cpp
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include <cstdint>
9 #include <cstdlib>
10 #include <exception>
11 #include <memory>
12 #include <mutex>
13 #include <string>
14 #include <unordered_set>
15 #include <utility>
16 #include <vector>
17 #include "../../log.h"
18 #include "../../macros.h"
19 #include "../objectvtable.h"
20 #include "bus_p.h"
21 #include "message_p.h"
22 #include "objectvtable_p_sdbus.h"
23 #include "objectvtablewrapper_p.h"
24 #include "sd-bus-wrap.h"
25 
26 namespace fcitx::dbus {
27 
28 class ObjectVTablePrivate {
29 public:
30  const std::string &vtableString(const std::string &str) {
31  auto iter = stringPool_.find(str);
32  if (iter == stringPool_.end()) {
33  iter = stringPool_.insert(str).first;
34  }
35  return *iter;
36  }
37 
38  bool hasVTable_ = false;
39  std::vector<sd_bus_vtable> vtable_;
40  std::unordered_set<std::string> stringPool_;
41 };
42 
43 int SDMethodCallback(sd_bus_message *m, void *userdata,
44  sd_bus_error * /*unused*/) {
45  auto *vtable = static_cast<ObjectVTableBase *>(userdata);
46  if (!vtable) {
47  return 0;
48  }
49  auto *method = vtable->findMethod(sd_bus_message_get_member(m));
50  if (!method) {
51  return 0;
52  }
53  try {
54  method->handler()(MessagePrivate::fromSDBusMessage(m));
55  return 1;
56  } catch (const std::exception &e) {
57  // some abnormal things threw
58  FCITX_ERROR() << e.what();
59  std::abort();
60  }
61  return 0;
62 }
63 
64 int SDPropertyGetCallback(sd_bus * /*unused*/, const char * /*unused*/,
65  const char * /*unused*/, const char *property,
66  sd_bus_message *reply, void *userdata,
67  sd_bus_error * /*unused*/) {
68  auto *vtable = static_cast<ObjectVTableBase *>(userdata);
69  if (!vtable) {
70  return 0;
71  }
72  auto *prop = vtable->findProperty(property);
73  if (!prop) {
74  return 0;
75  }
76  try {
77  auto msg = MessagePrivate::fromSDBusMessage(reply);
78  prop->getMethod()(msg);
79  return 1;
80  } catch (const std::exception &e) {
81  // some abnormal things threw
82  FCITX_ERROR() << e.what();
83  std::abort();
84  }
85  return 0;
86 }
87 
88 int SDPropertySetCallback(sd_bus * /*unused*/, const char * /*unused*/,
89  const char * /*unused*/, const char *property,
90  sd_bus_message *value, void *userdata,
91  sd_bus_error * /*unused*/) {
92  auto *vtable = static_cast<ObjectVTableBase *>(userdata);
93  if (!vtable) {
94  return 0;
95  }
96  auto *prop = vtable->findProperty(property);
97  if (!prop || !prop->writable()) {
98  return 0;
99  }
100  try {
101  auto msg = MessagePrivate::fromSDBusMessage(value);
102  static_cast<ObjectVTableWritableProperty *>(prop)->setMethod()(msg);
103  return 1;
104  } catch (const std::exception &e) {
105  // some abnormal things threw
106  FCITX_ERROR() << e.what();
107  std::abort();
108  }
109  return 0;
110 }
111 
112 ObjectVTableBasePrivate::~ObjectVTableBasePrivate() {}
113 
114 uint32_t PropertyOptionsToSDBusFlags(PropertyOptions options) {
115  uint32_t result = 0;
116  if (options.test(PropertyOption::Hidden)) {
117  result |= SD_BUS_VTABLE_HIDDEN;
118  }
119  return result;
120 }
121 
122 const sd_bus_vtable *
123 ObjectVTableBasePrivate::toSDBusVTable(ObjectVTableBase *q) {
124  std::lock_guard<std::mutex> lock(q->privateDataMutexForType());
125  auto *p = q->privateDataForType();
126  if (!p->hasVTable_) {
127  std::vector<sd_bus_vtable> &result = p->vtable_;
128  result.push_back(vtable_start());
129 
130  for (const auto &m : methods_) {
131  auto *method = m.second;
132  result.push_back(vtable_method(
133  p->vtableString(method->name()).c_str(),
134  p->vtableString(method->signature()).c_str(),
135  p->vtableString(method->ret()).c_str(), 0, SDMethodCallback));
136  }
137 
138  for (const auto &s : sigs_) {
139  auto *sig = s.second;
140  result.push_back(
141  vtable_signal(p->vtableString(sig->name()).c_str(),
142  p->vtableString(sig->signature()).c_str()));
143  }
144 
145  for (const auto &pr : properties_) {
146  auto *prop = pr.second;
147  if (prop->writable()) {
148  result.push_back(vtable_writable_property(
149  p->vtableString(prop->name()).c_str(),
150  p->vtableString(prop->signature()).c_str(),
151  SDPropertyGetCallback, SDPropertySetCallback,
152  PropertyOptionsToSDBusFlags(prop->options())));
153  } else {
154  result.push_back(vtable_property(
155  p->vtableString(prop->name()).c_str(),
156  p->vtableString(prop->signature()).c_str(),
157  SDPropertyGetCallback,
158  PropertyOptionsToSDBusFlags(prop->options())));
159  }
160  }
161 
162  result.push_back(vtable_end());
163  p->hasVTable_ = true;
164  }
165 
166  return p->vtable_.data();
167 }
168 
169 ObjectVTableBase::ObjectVTableBase()
170  : d_ptr(std::make_unique<ObjectVTableBasePrivate>()) {}
171 
172 ObjectVTableBase::~ObjectVTableBase() {}
173 
174 void ObjectVTableBase::addMethod(ObjectVTableMethod *method) {
175  FCITX_D();
176  d->methods_[method->name()] = method;
177 }
178 
179 void ObjectVTableBase::addProperty(ObjectVTableProperty *property) {
180  FCITX_D();
181  d->properties_[property->name()] = property;
182 }
183 
184 void ObjectVTableBase::addSignal(ObjectVTableSignal *signal) {
185  FCITX_D();
186  d->sigs_[signal->name()] = signal;
187 }
188 
189 ObjectVTableMethod *ObjectVTableBase::findMethod(const std::string &name) {
190  FCITX_D();
191  auto iter = d->methods_.find(name);
192  if (iter == d->methods_.end()) {
193  return nullptr;
194  }
195  return iter->second;
196 }
197 
198 ObjectVTableProperty *ObjectVTableBase::findProperty(const std::string &name) {
199  FCITX_D();
200  auto iter = d->properties_.find(name);
201  if (iter == d->properties_.end()) {
202  return nullptr;
203  }
204  return iter->second;
205 }
206 
207 void ObjectVTableBase::releaseSlot() { setSlot(nullptr); }
208 
209 Bus *ObjectVTableBase::bus() { return std::as_const(*this).bus(); }
210 
211 Bus *ObjectVTableBase::bus() const {
212  FCITX_D();
213  return d->slot_ ? d->slot_->bus_ : nullptr;
214 }
215 
216 bool ObjectVTableBase::isRegistered() const {
217  FCITX_D();
218  return !!d->slot_;
219 }
220 
221 const std::string &ObjectVTableBase::path() const {
222  FCITX_D();
223  return d->slot_->path_;
224 }
225 
226 const std::string &ObjectVTableBase::interface() const {
227  FCITX_D();
228  return d->slot_->interface_;
229 }
230 
231 Message *ObjectVTableBase::currentMessage() const {
232  FCITX_D();
233  return d->msg_;
234 }
235 
236 void ObjectVTableBase::setCurrentMessage(Message *message) {
237  FCITX_D();
238  d->msg_ = message;
239 }
240 
241 std::shared_ptr<ObjectVTablePrivate> ObjectVTableBase::newSharedPrivateData() {
242  return std::make_shared<ObjectVTablePrivate>();
243 }
244 
245 void ObjectVTableBase::setSlot(Slot *slot) {
246  FCITX_D();
247  d->slot_.reset(static_cast<SDVTableSlot *>(slot));
248 }
249 } // namespace fcitx::dbus
bool isRegistered() const
Return whether this object is registered to a bus.
Bus * bus()
Return the bus that the object is registered to.
Definition: matchrule.h:78
void setCurrentMessage(Message *message)
Set the current dbus message.
void releaseSlot()
Unregister the dbus object from the bus.
const std::string & interface() const
Return the registered dbus interface of the object.
Message * currentMessage() const
Return the current dbus message for current method.
const std::string & path() const
Return the registered dbus object path of the object.