diff options
| -rw-r--r-- | indra/llcommon/lazyeventapi.cpp | 19 | ||||
| -rw-r--r-- | indra/llcommon/lazyeventapi.h | 36 | ||||
| -rw-r--r-- | indra/llcommon/llleaplistener.cpp | 70 | ||||
| -rw-r--r-- | indra/llcommon/tests/lazyeventapi_test.cpp | 24 | 
4 files changed, 120 insertions, 29 deletions
diff --git a/indra/llcommon/lazyeventapi.cpp b/indra/llcommon/lazyeventapi.cpp index aefc2db6da..028af9f33f 100644 --- a/indra/llcommon/lazyeventapi.cpp +++ b/indra/llcommon/lazyeventapi.cpp @@ -15,9 +15,11 @@  #include "lazyeventapi.h"  // STL headers  // std headers +#include <algorithm>                // std::find_if  // external library headers  // other Linden headers  #include "llevents.h" +#include "llsdutil.h"  LL::LazyEventAPIBase::LazyEventAPIBase(      const std::string& name, const std::string& desc, const std::string& field) @@ -51,3 +53,20 @@ LL::LazyEventAPIBase::~LazyEventAPIBase()          LLEventPumps::instance().unregisterPumpFactory(mParams.name);      }  } + +LLSD LL::LazyEventAPIBase::getMetadata(const std::string& name) const +{ +    // Since mOperations is a vector rather than a map, just search. +    auto found = std::find_if(mOperations.begin(), mOperations.end(), +                              [&name](const auto& namedesc) +                              { return (namedesc.first == name); }); +    if (found == mOperations.end()) +        return {}; + +    // LLEventDispatcher() supplements the returned metadata in different +    // ways, depending on metadata provided to the specific add() method. +    // Don't try to emulate all that. At some point we might consider more +    // closely unifying LLEventDispatcher machinery with LazyEventAPI, but for +    // now this will have to do. +    return llsd::map("name", found->first, "desc", found->second); +} diff --git a/indra/llcommon/lazyeventapi.h b/indra/llcommon/lazyeventapi.h index 7267a3e4ec..a815b119f0 100644 --- a/indra/llcommon/lazyeventapi.h +++ b/indra/llcommon/lazyeventapi.h @@ -63,9 +63,6 @@ namespace LL          LazyEventAPIBase& operator=(const LazyEventAPIBase&) = delete;          LazyEventAPIBase& operator=(LazyEventAPIBase&&) = delete; -        // actually instantiate the companion LLEventAPI subclass -        virtual LLEventPump* construct(const std::string& name) = 0; -          // capture add() calls we want to play back on LLEventAPI construction          template <typename... ARGS>          void add(const std::string& name, const std::string& desc, ARGS&&... rest) @@ -96,12 +93,40 @@ namespace LL                  });          } +        // The following queries mimic the LLEventAPI / LLEventDispatcher +        // query API. + +        // Get the string name of the subject LLEventAPI +        std::string getName() const { return mParams.name; } +        // Get the documentation string +        std::string getDesc() const { return mParams.desc; } +        // Retrieve the LLSD key we use for dispatching +        std::string getDispatchKey() const { return mParams.field; } + +        // operations +        using NameDesc = std::pair<std::string, std::string>; + +    private:          // metadata that might be queried by LLLeapListener -        std::vector<std::pair<std::string, std::string>> mOperations; +        std::vector<NameDesc> mOperations; + +    public: +        using const_iterator = decltype(mOperations)::const_iterator; +        const_iterator begin() const { return mOperations.begin(); } +        const_iterator end()   const { return mOperations.end(); } +        LLSD getMetadata(const std::string& name) const; + +    protected:          // Params with which to instantiate the companion LLEventAPI subclass          LazyEventAPIParams mParams;      private: +        // true if we successfully registered our LLEventAPI on construction +        bool mRegistered; + +        // actually instantiate the companion LLEventAPI subclass +        virtual LLEventPump* construct(const std::string& name) = 0; +          // Passing an overloaded function to any function that accepts an          // arbitrary callable is a PITB because you have to specify the          // correct overload. What we want is for the compiler to select the @@ -117,8 +142,6 @@ namespace LL          {              instance->add(std::forward<ARGS>(args)...);          } - -        bool mRegistered;      };      /** @@ -168,6 +191,7 @@ namespace LL              LazyEventAPIBase(name, desc, field)          {} +    private:          LLEventPump* construct(const std::string& /*name*/) override          {              // base class has carefully assembled LazyEventAPIParams embedded diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index 11bfec1b31..471f52e91c 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -14,14 +14,16 @@  // associated header  #include "llleaplistener.h"  // STL headers -#include <map> +#include <algorithm>                // std::find_if  #include <functional> +#include <map> +#include <set>  // std headers  // external library headers -#include <boost/foreach.hpp>  // other Linden headers -#include "lluuid.h" +#include "lazyeventapi.h"  #include "llsdutil.h" +#include "lluuid.h"  #include "stringize.h"  /***************************************************************************** @@ -110,7 +112,7 @@ LLLeapListener::~LLLeapListener()      // value_type, and Bad Things would happen if you copied an      // LLTempBoundListener. (Destruction of the original would disconnect the      // listener, invalidating every stored connection.) -    BOOST_FOREACH(ListenersMap::value_type& pair, mListeners) +    for (ListenersMap::value_type& pair : mListeners)      {          pair.second.disconnect();      } @@ -208,31 +210,65 @@ void LLLeapListener::getAPIs(const LLSD& request) const  {      Response reply(LLSD(), request); +    // first, traverse existing LLEventAPI instances +    std::set<std::string> instances;      for (auto& ea : LLEventAPI::instance_snapshot())      { -        LLSD info; -        info["desc"] = ea.getDesc(); -        reply[ea.getName()] = info; +        // remember which APIs are actually instantiated +        instances.insert(ea.getName()); +        reply[ea.getName()] = llsd::map("desc", ea.getDesc()); +    } +    // supplement that with *potential* instances: that is, instances of +    // LazyEventAPI that can each instantiate an LLEventAPI on demand +    for (const auto& lea : LL::LazyEventAPIBase::instance_snapshot()) +    { +        // skip any LazyEventAPI that's already instantiated its LLEventAPI +        if (instances.find(lea.getName()) == instances.end()) +        { +            reply[lea.getName()] = llsd::map("desc", lea.getDesc()); +        }      }  } +// Because LazyEventAPI deliberately mimics LLEventAPI's query API, this +// function can be passed either -- even though they're unrelated types. +template <typename API> +void reportAPI(LLEventAPI::Response& reply, const API& api) +{ +    reply["name"] = api.getName(); +    reply["desc"] = api.getDesc(); +    reply["key"]  = api.getDispatchKey(); +    LLSD ops; +    for (const auto& namedesc : api) +    { +        ops.append(api.getMetadata(namedesc.first)); +    } +    reply["ops"] = ops; +} +  void LLLeapListener::getAPI(const LLSD& request) const  {      Response reply(LLSD(), request); -    auto found = LLEventAPI::getInstance(request["api"]); -    if (found) +    // check first among existing LLEventAPI instances +    auto foundea = LLEventAPI::getInstance(request["api"]); +    if (foundea) +    { +        reportAPI(reply, *foundea); +    } +    else      { -        reply["name"] = found->getName(); -        reply["desc"] = found->getDesc(); -        reply["key"] = found->getDispatchKey(); -        LLSD ops; -        for (LLEventAPI::const_iterator oi(found->begin()), oend(found->end()); -             oi != oend; ++oi) +        // Here the requested LLEventAPI doesn't yet exist, but do we have a +        // registered LazyEventAPI for it? +        LL::LazyEventAPIBase::instance_snapshot snap; +        auto foundlea = std::find_if(snap.begin(), snap.end(), +                                     [api = request["api"].asString()] +                                     (const auto& lea) +                                     { return (lea.getName() == api); }); +        if (foundlea != snap.end())          { -            ops.append(found->getMetadata(oi->first)); +            reportAPI(reply, *foundlea);          } -        reply["ops"] = ops;      }  } diff --git a/indra/llcommon/tests/lazyeventapi_test.cpp b/indra/llcommon/tests/lazyeventapi_test.cpp index 4c78fd7105..31b2d6d17f 100644 --- a/indra/llcommon/tests/lazyeventapi_test.cpp +++ b/indra/llcommon/tests/lazyeventapi_test.cpp @@ -109,16 +109,28 @@ namespace tut      {          set_test_name("LazyEventAPI metadata");          MyRegistrar regster; +        // Of course we have 'regster' in hand; we don't need to search for +        // it. But this next test verifies that we can find (all) LazyEventAPI +        // instances using LazyEventAPIBase::instance_snapshot. Normally we +        // wouldn't search; normally we'd just look at each instance in the +        // loop body.          const MyRegistrar* found = nullptr;          for (const auto& registrar : LL::LazyEventAPIBase::instance_snapshot())              if ((found = dynamic_cast<const MyRegistrar*>(®istrar)))                  break;          ensure("Failed to find MyRegistrar via LLInstanceTracker", found); -        ensure_equals("wrong API name", found->mParams.name, "Test"); -        ensure_contains("wrong API desc", found->mParams.desc, "test LLEventAPI"); -        ensure_equals("wrong API field", found->mParams.field, "op"); -        ensure_equals("failed to find operations", found->mOperations.size(), 1); -        ensure_equals("wrong operation name", found->mOperations[0].first, "set"); -        ensure_contains("wrong operation desc", found->mOperations[0].second, "set operation"); + +        ensure_equals("wrong API name", found->getName(), "Test"); +        ensure_contains("wrong API desc", found->getDesc(), "test LLEventAPI"); +        ensure_equals("wrong API field", found->getDispatchKey(), "op"); +        // Normally we'd just iterate over *found. But for test purposes, +        // actually capture the range of NameDesc pairs in a vector. +        std::vector<LL::LazyEventAPIBase::NameDesc> ops{ found->begin(), found->end() }; +        ensure_equals("failed to find operations", ops.size(), 1); +        ensure_equals("wrong operation name", ops[0].first, "set"); +        ensure_contains("wrong operation desc", ops[0].second, "set operation"); +        LLSD metadata{ found->getMetadata(ops[0].first) }; +        ensure_equals("bad metadata name", metadata["name"].asString(), ops[0].first); +        ensure_equals("bad metadata desc", metadata["desc"].asString(), ops[0].second);      }  } // namespace tut  | 
