summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/lazyeventapi.cpp19
-rw-r--r--indra/llcommon/lazyeventapi.h36
-rw-r--r--indra/llcommon/llleaplistener.cpp70
-rw-r--r--indra/llcommon/tests/lazyeventapi_test.cpp24
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*>(&registrar)))
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