lleventdispatcher.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /**
  2. * @file lleventdispatcher.h
  3. * Author Nat Goodspeed
  4. * @date 2009-06-18
  5. * @brief Central mechanism for dispatching events by string name. This is
  6. * useful when you have a single LLEventPump listener on which you can
  7. * request different operations, vs. instantiating a different
  8. * LLEventPump for each such operation.
  9. *
  10. * $LicenseInfo:firstyear=2009&license=viewergpl$
  11. *
  12. * Copyright (c) 2010-2022, Linden Research, Inc.
  13. *
  14. * Second Life Viewer Source Code
  15. * The source code in this file ("Source Code") is provided by Linden Lab
  16. * to you under the terms of the GNU General Public License, version 2.0
  17. * ("GPL"), unless you have obtained a separate licensing agreement
  18. * ("Other License"), formally executed by you and Linden Lab. Terms of
  19. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  20. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  21. *
  22. * There are special exceptions to the terms and conditions of the GPL as
  23. * it is applied to this Source Code. View the full text of the exception
  24. * in the file doc/FLOSS-exception.txt in this software distribution, or
  25. * online at
  26. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  27. *
  28. * By copying, modifying or distributing this software, you acknowledge
  29. * that you have read and understood your obligations described above,
  30. * and agree to abide by those obligations.
  31. *
  32. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  33. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  34. * COMPLETENESS OR PERFORMANCE.
  35. * $/LicenseInfo$
  36. *
  37. * The invoker machinery that constructs a boost::fusion argument list for use
  38. * with boost::fusion::invoke() is derived from
  39. * http://www.boost.org/doc/libs/1_45_0/libs/function_types/example/interpreter.hpp
  40. * whose license information is copied below:
  41. *
  42. * "(C) Copyright Tobias Schwinger
  43. *
  44. * Use modification and distribution are subject to the boost Software License,
  45. * Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)."
  46. */
  47. #ifndef LL_LLEVENTDISPATCHER_H
  48. #define LL_LLEVENTDISPATCHER_H
  49. // nil is too generic a term to be allowed to be a global macro. In
  50. // particular, boost::fusion defines a 'class nil' (properly encapsulated in a
  51. // namespace) that a global 'nil' macro breaks badly.
  52. #if defined(nil)
  53. // Capture the value of the macro 'nil', hoping int is an appropriate type.
  54. static const auto nil_(nil);
  55. // Now forget the macro.
  56. #undef nil
  57. // Finally, reintroduce 'nil' as a properly-scoped alias for the previously-
  58. // defined const 'nil_'. Make it static since otherwise it produces duplicate-
  59. // symbol link errors later.
  60. static const auto& nil(nil_);
  61. #endif
  62. #include <functional>
  63. #include <memory>
  64. #include <string>
  65. #include <typeinfo>
  66. #include <type_traits>
  67. #include <utility>
  68. #include "boost/bind.hpp"
  69. #include "boost/function.hpp"
  70. #include "boost/function_types/is_nonmember_callable_builtin.hpp"
  71. #include "boost/function_types/parameter_types.hpp"
  72. #include "boost/function_types/function_arity.hpp"
  73. #include "boost/fusion/include/cons.hpp"
  74. #include "boost/fusion/include/invoke.hpp"
  75. #include "boost/fusion/include/push_back.hpp"
  76. #include "boost/iterator/transform_iterator.hpp"
  77. #include "boost/mpl/begin.hpp"
  78. #include "boost/mpl/deref.hpp"
  79. #include "boost/mpl/end.hpp"
  80. #include "boost/mpl/next.hpp"
  81. #include "boost/type_traits/remove_cv.hpp"
  82. #include "boost/type_traits/remove_reference.hpp"
  83. #include "llevents.h"
  84. #include "llinstancetracker.h"
  85. #include "llsdutil.h"
  86. class LLSD;
  87. ///////////////////////////////////////////////////////////////////////////////
  88. // LLEventDispatcher
  89. ///////////////////////////////////////////////////////////////////////////////
  90. // Given an LLSD map, examine a string-valued key and call a corresponding
  91. // callable. This class is designed to be contained by an LLEventPump listener
  92. // class that will register some of its own methods, though any callable can be
  93. // used.
  94. class LLEventDispatcher
  95. {
  96. protected:
  97. LOG_CLASS(LLEventDispatcher);
  98. public:
  99. LLEventDispatcher(const std::string& desc, const std::string& key);
  100. virtual ~LLEventDispatcher() = default;
  101. // Accept any C++ callable with the right signature, typically a
  102. // boost::bind() expression
  103. typedef boost::function<void(const LLSD&)> Callable;
  104. // Registers a callable by name. The passed callable accepts a single
  105. // LLSD value and uses it in any way desired, e.g. extract parameters and
  106. // call some other function. The optional required parameter is used to
  107. // validate the structure of each incoming event (see llsd_matches()).
  108. void add(const std::string& name, const std::string& desc,
  109. const Callable& callable, const LLSD& required = LLSD());
  110. // The case of a free function (or static method) accepting(const LLSD&)
  111. // could also be intercepted by the arbitrary-args overload below. Ensure
  112. // that it is directed to the Callable overload above instead.
  113. void add(const std::string& name, const std::string& desc,
  114. void (*f)(const LLSD&), const LLSD& required = LLSD())
  115. {
  116. add(name, desc, Callable(f), required);
  117. }
  118. // Special case: a subclass of this class can pass an unbound member
  119. // function pointer (of an LLEventDispatcher subclass) without explicitly
  120. // specifying the boost::bind() expression. The passed method
  121. // accepts a single LLSD value, presumably containing other parameters.
  122. template <class CLASS>
  123. void add(const std::string& name, const std::string& desc,
  124. void (CLASS::*method)(const LLSD&), const LLSD& required = LLSD())
  125. {
  126. addMethod<CLASS>(name, desc, method, required);
  127. }
  128. // Overload for both const and non-const methods. The passed method accepts
  129. // a single LLSD value, presumably containing other parameters.
  130. template <class CLASS>
  131. void add(const std::string& name, const std::string& desc,
  132. void (CLASS::*method)(const LLSD&) const,
  133. const LLSD& required = LLSD())
  134. {
  135. addMethod<CLASS>(name, desc, method, required);
  136. }
  137. // Registers a free function with arbitrary parameters (this also works for
  138. // static class methods). Note: this supports functions with up to about 6
  139. // parameters; after that you start getting dismaying compile errors in
  140. // which boost::fusion::joint_view is mentioned a surprising number of
  141. // times.
  142. //
  143. // When calling this name, pass an LLSD::Array. Each entry in turn will be
  144. // converted to the corresponding parameter type using LLSDParam.
  145. template<typename Function>
  146. typename std::enable_if<
  147. boost::function_types::is_nonmember_callable_builtin<Function>::value
  148. >::type add(const std::string& name,
  149. const std::string& desc,
  150. Function f);
  151. // Registers a nonstatic class method with arbitrary parameters. Note: this
  152. // supports functions with up to about 6 parameters; after that you start
  153. // getting dismaying compile errors in which boost::fusion::joint_view is
  154. // mentioned a surprising number of times.
  155. //
  156. // To cover cases such as a method on an LLSingleton we don't yet want to
  157. // instantiate, instead of directly storing an instance pointer, accept a
  158. // nullary callable returning a pointer/reference to the desired class
  159. // instance. If you already have an instance in hand,
  160. // boost::lambda::var(instance) or boost::lambda::constant(instance_ptr)
  161. // produce suitable callables.
  162. //
  163. // When calling this name, pass an LLSD::Array. Each entry in turn will be
  164. // converted to the corresponding parameter type using LLSDParam.
  165. template<typename Method, typename InstanceGetter>
  166. typename std::enable_if<
  167. boost::function_types::is_member_function_pointer<Method>::value &&
  168. !std::is_convertible<InstanceGetter, LLSD>::value
  169. >::type add(const std::string& name,
  170. const std::string& desc,
  171. Method f,
  172. const InstanceGetter& getter);
  173. // Registers a free function with arbitrary parameters (this also works for
  174. // static class methods). Note: this supports functions with up to about 6
  175. // parameters; after that you start getting dismaying compile errors in
  176. // which boost::fusion::joint_view is mentioned a surprising number of
  177. // times.
  178. // Pass an LLSD::Array of parameter names, and optionally another
  179. // LLSD::Array of default parameter values, a la LLSDArgsMapper.
  180. //
  181. // When calling this name, pass an LLSD::Map. We will internally generate
  182. // an LLSD::Array using LLSDArgsMapper and then convert each entry in turn
  183. // to the corresponding parameter type using LLSDParam.
  184. template<typename Function>
  185. typename std::enable_if<
  186. boost::function_types::is_nonmember_callable_builtin<Function>::value
  187. >::type add(const std::string& name,
  188. const std::string& desc,
  189. Function f,
  190. const LLSD& params,
  191. const LLSD& defaults = LLSD());
  192. // Registers a nonstatic class method with arbitrary parameters. Note: this
  193. // supports functions with up to about 6 parameters; after that you start
  194. // getting dismaying compile errors in which boost::fusion::joint_view is
  195. // mentioned a surprising number of times.
  196. //
  197. // To cover cases such as a method on an LLSingleton we don't yet want to
  198. // instantiate, instead of directly storing an instance pointer, accept a
  199. // nullary callable returning a pointer/reference to the desired class
  200. // instance. If you already have an instance in hand,
  201. // boost::lambda::var(instance) or boost::lambda::constant(instance_ptr)
  202. // produce suitable callables.
  203. //
  204. // Pass an LLSD::Array of parameter names, and optionally another
  205. // LLSD::Array of default parameter values, a la LLSDArgsMapper.
  206. //
  207. // When calling this name, pass an LLSD::Map. We will internally generate
  208. // an LLSD::Array using LLSDArgsMapper and then convert each entry in turn
  209. // to the corresponding parameter type using LLSDParam.
  210. template<typename Method, typename InstanceGetter>
  211. typename std::enable_if<
  212. boost::function_types::is_member_function_pointer<Method>::value &&
  213. !std::is_convertible<InstanceGetter, LLSD>::value
  214. >::type add(const std::string& name,
  215. const std::string& desc,
  216. Method f,
  217. const InstanceGetter& getter,
  218. const LLSD& params,
  219. const LLSD& defaults = LLSD());
  220. // Unregisters a callable
  221. bool remove(const std::string& name);
  222. // Calls a registered callable with an explicitly-specified name. If no
  223. // such callable exists, it is an error. If the event fails to match the
  224. // required prototype specified at add() time, it is an error.
  225. void operator()(const std::string& name, const LLSD& event) const;
  226. // Calls a registered callable with an explicitly-specified name and
  227. // returns true. If no such callable exists, returns false. If the event
  228. // fails to match the required prototype specified at add() time, it is an
  229. // error.
  230. bool try_call(const std::string& name, const LLSD& event) const;
  231. // Extracts the key value from the incoming event, and calls the callable
  232. // whose name is specified by that map key. If no such callable exists,
  233. // it is an error. If the event fails to match the required prototype
  234. // specified at add() time, it is an error.
  235. void operator()(const LLSD& event) const;
  236. // Extracts the key value from the incoming event, calls the callable
  237. // whose name is specified by that map key and returns true. If no such
  238. // callable exists, returns false. If the event fails to match the required
  239. // prototype specified at add() time, it is an error.
  240. bool try_call(const LLSD& event) const;
  241. typedef std::pair<std::string, std::string> NameDesc;
  242. LL_INLINE friend std::ostream& operator<<(std::ostream& out,
  243. const LLEventDispatcher& disp)
  244. {
  245. return out << "LLEventDispatcher(" << disp.mDesc << ")";
  246. }
  247. private:
  248. struct DispatchEntry
  249. {
  250. DispatchEntry(const std::string& desc);
  251. virtual ~DispatchEntry() = default;
  252. virtual void call(const std::string& desc,
  253. const LLSD& event) const = 0;
  254. virtual LLSD addMetadata(LLSD) const = 0;
  255. std::string mDesc;
  256. };
  257. // Tried using boost::ptr_map<std::string, DispatchEntry>, but ptr_map<>
  258. // wants its value type to be "clonable," even just to dereference an
  259. // iterator. I do not want to clone entries -- if I have to copy an entry
  260. // around, I want it to continue pointing to the same DispatchEntry
  261. // subclass object. However, I definitely want DispatchMap to destroy
  262. // DispatchEntry if no references are outstanding at the time an entry is
  263. // removed. This looks like a job for std::shared_ptr.
  264. typedef std::map<std::string, std::shared_ptr<DispatchEntry> > DispatchMap;
  265. public:
  266. // We want the flexibility to redefine what data we store per name,
  267. // therefore our public interface doesn't expose DispatchMap iterators, or
  268. // DispatchMap itself, or DispatchEntry. Instead we explicitly transform
  269. // each DispatchMap item to NameDesc on dereferencing.
  270. typedef boost::transform_iterator<NameDesc(*)(const DispatchMap::value_type&),
  271. DispatchMap::const_iterator> const_iterator;
  272. const_iterator begin() const
  273. {
  274. return boost::make_transform_iterator(mDispatch.begin(), makeNameDesc);
  275. }
  276. const_iterator end() const
  277. {
  278. return boost::make_transform_iterator(mDispatch.end(), makeNameDesc);
  279. }
  280. // Gets information about a specific callable
  281. LLSD getMetadata(const std::string& name) const;
  282. // Retrieve the LLSD key we use for one-arg operator() method
  283. std::string getDispatchKey() const { return mKey; }
  284. private:
  285. template <class CLASS, typename METHOD>
  286. void addMethod(const std::string& name, const std::string& desc,
  287. const METHOD& method, const LLSD& required)
  288. {
  289. CLASS* downcast = dynamic_cast<CLASS*>(this);
  290. if (! downcast)
  291. {
  292. addFail(name, typeid(CLASS).name());
  293. }
  294. else
  295. {
  296. add(name, desc, boost::bind(method, downcast, _1), required);
  297. }
  298. }
  299. void addFail(const std::string& name, const std::string& classname) const;
  300. std::string try_call_log(const std::string& key, const std::string& name,
  301. const LLSD& event) const;
  302. std::string try_call(const std::string& key, const std::string& name,
  303. const LLSD& event) const;
  304. // Implements "it is an error" semantics for attempted call operations: if
  305. // the incoming event includes a "reply" key, logs and sends an error
  306. // reply.
  307. void callFail(const LLSD& event, const std::string& message) const;
  308. static NameDesc makeNameDesc(const DispatchMap::value_type& item)
  309. {
  310. return NameDesc(item.first, item.second->mDesc);
  311. }
  312. // Step 2 of parameter analysis. Instantiating invoker<some_function_type>
  313. // implicitly sets its From and To parameters to the (compile time) begin
  314. // and end iterators over that function's parameter types.
  315. template<typename Function,
  316. class From = typename boost::mpl::begin<boost::function_types::parameter_types<Function> >::type,
  317. class To = typename boost::mpl::end<boost::function_types::parameter_types<Function> >::type
  318. >
  319. struct invoker;
  320. // Delivers LLSD arguments one at a time
  321. typedef boost::function<LLSD()> args_source;
  322. // Obtains args from an args_source to build param list and calls target
  323. // function
  324. typedef boost::function<void(const args_source&)> invoker_function;
  325. template <typename Function>
  326. invoker_function make_invoker(Function f);
  327. template <typename Method, typename InstanceGetter>
  328. invoker_function make_invoker(Method f, const InstanceGetter& getter);
  329. void addArrayParamsDispatchEntry(const std::string& name,
  330. const std::string& desc,
  331. const invoker_function& invoker,
  332. size_t arity);
  333. void addMapParamsDispatchEntry(const std::string& name,
  334. const std::string& desc,
  335. const invoker_function& invoker,
  336. const LLSD& params,
  337. const LLSD& defaults);
  338. private:
  339. struct LLSDDispatchEntry;
  340. struct ParamsDispatchEntry;
  341. struct ArrayParamsDispatchEntry;
  342. struct MapParamsDispatchEntry;
  343. std::string mDesc;
  344. std::string mKey;
  345. DispatchMap mDispatch;
  346. };
  347. // Step 3 of parameter analysis, the recursive case.
  348. template<typename Function, class From, class To>
  349. struct LLEventDispatcher::invoker
  350. {
  351. template<typename T>
  352. struct remove_cv_ref
  353. : boost::remove_cv<typename boost::remove_reference<T>::type>
  354. {
  355. };
  356. // apply() accepts an arbitrary boost::fusion sequence as args. It
  357. // examines the next parameter type in the parameter-types sequence
  358. // bounded by From and To, obtains the next LLSD object from the passed
  359. // args_source and constructs an LLSDParam of appropriate type to try
  360. // to convert the value. It then recurs with the next parameter-types
  361. // iterator, passing the args sequence thus far.
  362. template<typename Args>
  363. static LL_INLINE
  364. void apply(Function func, const args_source& argsrc, Args const & args)
  365. {
  366. typedef typename boost::mpl::deref<From>::type arg_type;
  367. typedef typename boost::mpl::next<From>::type next_iter_type;
  368. typedef typename remove_cv_ref<arg_type>::type plain_arg_type;
  369. invoker<Function, next_iter_type, To>::apply(func, argsrc,
  370. boost::fusion::push_back(args,
  371. LLSDParam<plain_arg_type>(argsrc())));
  372. }
  373. // Special treatment for instance (first) parameter of a non-static member
  374. // function. Accept the instance-getter callable, calling that to produce
  375. // the first args value. Since we know we are at the top of the recursion
  376. // chain, we need not also require a partial args sequence from our caller.
  377. template <typename InstanceGetter>
  378. static LL_INLINE
  379. void method_apply(Function func, const args_source& argsrc,
  380. const InstanceGetter& getter)
  381. {
  382. typedef typename boost::mpl::next<From>::type next_iter_type;
  383. // Instead of grabbing the first item from argsrc and making an
  384. // LLSDParam of it, call getter() and pass that as the instance param.
  385. invoker<Function,
  386. next_iter_type,
  387. To>::apply(func, argsrc,
  388. boost::fusion::push_back(boost::fusion::nil(),
  389. bindable(getter())));
  390. }
  391. template <typename T>
  392. static LL_INLINE
  393. auto bindable(T&& value,
  394. typename std::enable_if<std::is_pointer<T>::value,
  395. bool>::type = true)
  396. {
  397. // If passed a pointer, just return that pointer
  398. return std::forward<T>(value);
  399. }
  400. template <typename T>
  401. static LL_INLINE
  402. auto bindable(T&& value,
  403. typename std::enable_if<!std::is_pointer<T>::value,
  404. bool>::type = true)
  405. {
  406. // If passed a reference, wrap it for binding
  407. return std::ref(std::forward<T>(value));
  408. }
  409. };
  410. // Step 4 of parameter analysis, the leaf case. When the general
  411. // invoker<Function, From, To> logic has advanced From until it matches To,
  412. // the compiler will pick this template specialization.
  413. template<typename Function, class To>
  414. struct LLEventDispatcher::invoker<Function, To, To>
  415. {
  416. // the argument list is complete, now call the function
  417. template<typename Args>
  418. static LL_INLINE
  419. void apply(Function func, const args_source&, Args const& args)
  420. {
  421. boost::fusion::invoke(func, args);
  422. }
  423. };
  424. template<typename Function>
  425. typename std::enable_if<
  426. boost::function_types::is_nonmember_callable_builtin<Function>::value
  427. >::type
  428. LLEventDispatcher::add(const std::string& name, const std::string& desc,
  429. Function f)
  430. {
  431. // Construct an invoker_function, a callable accepting const args_source&.
  432. // Add to DispatchMap an ArrayParamsDispatchEntry that will handle the
  433. // caller's LLSD::Array.
  434. addArrayParamsDispatchEntry(name, desc, make_invoker(f),
  435. boost::function_types::function_arity<Function>::value);
  436. }
  437. template<typename Method, typename InstanceGetter>
  438. typename std::enable_if<
  439. boost::function_types::is_member_function_pointer<Method>::value &&
  440. !std::is_convertible<InstanceGetter, LLSD>::value
  441. >::type
  442. LLEventDispatcher::add(const std::string& name, const std::string& desc,
  443. Method f, const InstanceGetter& getter)
  444. {
  445. // Subtract 1 from the compile-time arity because the getter takes care of
  446. // the first parameter. We only need (arity - 1) additional arguments.
  447. addArrayParamsDispatchEntry(name, desc, make_invoker(f, getter),
  448. boost::function_types::function_arity<Method>::value - 1);
  449. }
  450. template<typename Function>
  451. typename std::enable_if<
  452. boost::function_types::is_nonmember_callable_builtin<Function>::value
  453. >::type
  454. LLEventDispatcher::add(const std::string& name, const std::string& desc,
  455. Function f,
  456. const LLSD& params, const LLSD& defaults)
  457. {
  458. // See comments for previous is_nonmember_callable_builtin add().
  459. addMapParamsDispatchEntry(name, desc, make_invoker(f), params, defaults);
  460. }
  461. template<typename Method, typename InstanceGetter>
  462. typename std::enable_if<
  463. boost::function_types::is_member_function_pointer<Method>::value &&
  464. !std::is_convertible<InstanceGetter, LLSD>::value
  465. >::type
  466. LLEventDispatcher::add(const std::string& name, const std::string& desc,
  467. Method f, const InstanceGetter& getter,
  468. const LLSD& params, const LLSD& defaults)
  469. {
  470. addMapParamsDispatchEntry(name, desc, make_invoker(f, getter), params,
  471. defaults);
  472. }
  473. template <typename Function>
  474. LLEventDispatcher::invoker_function
  475. LLEventDispatcher::make_invoker(Function f)
  476. {
  477. // Step 1 of parameter analysis, the top of the recursion. Passing a
  478. // suitable f (see add()'s enable_if condition) to this method causes it
  479. // to infer the function type; specifying that function type to invoker<>
  480. // causes it to fill in the begin/end MPL iterators over the function's
  481. // list of parameter types.
  482. // While normally invoker::apply() could infer its template type from the
  483. // boost::fusion::nil parameter value, here we must be explicit since
  484. // we're boost::bind()ing it rather than calling it directly.
  485. return boost::bind(&invoker<Function>::template apply<boost::fusion::nil>,
  486. f, _1, boost::fusion::nil());
  487. }
  488. template <typename Method, typename InstanceGetter>
  489. LLEventDispatcher::invoker_function
  490. LLEventDispatcher::make_invoker(Method f, const InstanceGetter& getter)
  491. {
  492. // Use invoker::method_apply() to treat the instance (first) arg specially.
  493. return boost::bind(&invoker<Method>::template method_apply<InstanceGetter>,
  494. f, _1, getter);
  495. }
  496. ///////////////////////////////////////////////////////////////////////////////
  497. // LLDispatchListener
  498. ///////////////////////////////////////////////////////////////////////////////
  499. // Bundle an LLEventPump and a listener with an LLEventDispatcher. A class that
  500. // contains (or derives from) LLDispatchListener need only specify the
  501. // LLEventPump name and dispatch key, and add() its methods. Incoming events
  502. // will automatically be dispatched.
  503. class LLDispatchListener: public LLEventDispatcher
  504. {
  505. public:
  506. LLDispatchListener(const std::string& pumpname, const std::string& key);
  507. LL_INLINE std::string getPumpName() const { return mPump.getName(); }
  508. private:
  509. bool process(const LLSD& event);
  510. private:
  511. LLEventStream mPump;
  512. LLTempBoundListener mBoundListener;
  513. };
  514. ///////////////////////////////////////////////////////////////////////////////
  515. // LLEventAPI
  516. ///////////////////////////////////////////////////////////////////////////////
  517. // LLEventAPI not only provides operation dispatch functionality, inherited
  518. // from LLDispatchListener -- it also gives us event API introspection.
  519. // Deriving from LLInstanceTracker lets us enumerate instances.
  520. class LLEventAPI : public LLDispatchListener,
  521. public LLInstanceTracker<LLEventAPI, std::string>
  522. {
  523. protected:
  524. LOG_CLASS(LLEventAPI);
  525. typedef LLDispatchListener lbase;
  526. typedef LLInstanceTracker<LLEventAPI, std::string> ibase;
  527. public:
  528. // name = LLEventPump name on which this LLEventAPI will listen. This
  529. // also serves as the LLInstanceTracker instance key.
  530. // desc = Documentation string shown to a client trying to discover
  531. // available event APIs.
  532. // field = LLSD::Map key used by LLDispatchListener to look up the subclass
  533. // method to invoke [default "op"].
  534. LLEventAPI(const std::string& name, const std::string& desc,
  535. const std::string& field = "op");
  536. // Gets the string name of this LLEventAPI
  537. LL_INLINE std::string getName() const { return ibase::getKey(); }
  538. // Gets the documentation string
  539. LL_INLINE std::string getDesc() const { return mDesc; }
  540. // Instantiate a Response object in any LLEventAPI subclass method that
  541. // wants to guarantee a reply (if requested) will be sent on exit from the
  542. // method. The reply will be sent if request.has(@a replyKey), default
  543. // "reply". If specified, the value of request[replyKey] is the name of the
  544. // LLEventPump on which to send the reply. Conventionally you might code
  545. // something like:
  546. //
  547. // void MyEventAPI::someMethod(const LLSD& request)
  548. // {
  549. // // Send a reply event as long as request.has("reply")
  550. // Response response(LLSD(), request);
  551. // ...
  552. // // will be sent in reply event
  553. // response["somekey"] = some_data;
  554. // }
  555. class Response
  556. {
  557. public:
  558. // Instantiating a Response object in an LLEventAPI subclass method
  559. // ensures that, if desired, a reply event will be sent.
  560. // 'seed' is the initial reply LLSD that will be further decorated
  561. // before being sent as the reply.
  562. // 'request' is the incoming request LLSD; we particularly care about
  563. // [replyKey] and ["reqid"].
  564. // 'reply_key' (defaulting to "reply") is the string name of the
  565. // LLEventPump on which the caller wants a reply.
  566. // ff (!request.has(reply_key)), no reply will be sent.
  567. Response(const LLSD& seed, const LLSD& request,
  568. const LLSD::String& reply_key = "reply");
  569. ~Response();
  570. // Example:
  571. // if (some condition)
  572. // {
  573. // response.warn("warnings logged and collected in [\"warnings\"]");
  574. // }
  575. void warn(const std::string& warning);
  576. // Example:
  577. // if (some condition is not met)
  578. // {
  579. // // In a function returning void, you can validly 'return
  580. // // expression' if the expression is itself of type void. But
  581. // // returning is up to you; response.error() has no effect on
  582. // // flow of control.
  583. // return response.error("error message, logged and also sent as [\"error\"]");
  584. // }
  585. void error(const std::string& error);
  586. // Sets any attributes you want to be sent in the reply.
  587. LL_INLINE LLSD& operator[](const LLSD::String& key)
  588. {
  589. return mResp[key];
  590. }
  591. // Sets the response to the given data
  592. LL_INLINE void setResponse(const LLSD& response)
  593. {
  594. mResp = response;
  595. }
  596. public:
  597. LLSD mResp;
  598. LLSD mReq;
  599. LLSD::String mKey;
  600. };
  601. private:
  602. std::string mDesc;
  603. };
  604. #endif // LL_LLEVENTDISPATCHER_H