From 5fb224bb8196e77259bef2a0ef60e82533c358a2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 30 Aug 2011 09:52:25 -0400 Subject: CHOP-763: make sendReply() treat replyKey as optional. It's not worth bothering to tweak reply LLSD or attempt to send it if the incoming request has no replyKey, in effect not requesting a reply. This supports LLEventAPI operations for which the caller might or might not care about a reply, invoked using either send() (fire and forget) or request() (send request, wait for response). This logic should be central, instead of having to perform that test in every caller that cares. The major alternative would have been to treat missing replyKey as an error (whether LL_ERRS or exception). But since there's already a mechanism by which an LLEventAPI operation method can stipulate its replyKey as required, at this level we can let it be optional. --- indra/llcommon/llevents.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index ff03506e84..db1ea4792b 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -591,6 +591,17 @@ void LLReqID::stamp(LLSD& response) const bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey) { + // If the original request has no value for replyKey, it's pointless to + // construct or send a reply event: on which LLEventPump should we send + // it? Allow that to be optional: if the caller wants to require replyKey, + // it can so specify when registering the operation method. + if (! request.has(replyKey)) + { + return false; + } + + // Here the request definitely contains replyKey; reasonable to proceed. + // Copy 'reply' to modify it. LLSD newreply(reply); // Get the ["reqid"] element from request -- cgit v1.2.3 From 3ddf3aef9b2f2bb85932bd33b9daac5e59d3018a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 1 Sep 2011 13:12:23 -0400 Subject: CHOP-763: Promote Response class from llwindowlistener.cpp to LLEventAPI. This is a generally-useful idiom, extending the sendReply() convenience function -- it shouldn't remain buried in a single .cpp file. --- indra/llcommon/lleventapi.cpp | 30 +++++++++++++++++ indra/llcommon/lleventapi.h | 78 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/lleventapi.cpp b/indra/llcommon/lleventapi.cpp index 4270c8b511..ff5459c1eb 100644 --- a/indra/llcommon/lleventapi.cpp +++ b/indra/llcommon/lleventapi.cpp @@ -34,6 +34,7 @@ // std headers // external library headers // other Linden headers +#include "llerror.h" LLEventAPI::LLEventAPI(const std::string& name, const std::string& desc, const std::string& field): lbase(name, field), @@ -45,3 +46,32 @@ LLEventAPI::LLEventAPI(const std::string& name, const std::string& desc, const s LLEventAPI::~LLEventAPI() { } + +LLEventAPI::Response::Response(const LLSD& seed, const LLSD& request, const LLSD::String& replyKey): + mResp(seed), + mReq(request), + mKey(replyKey) +{} + +LLEventAPI::Response::~Response() +{ + // When you instantiate a stack Response object, if the original + // request requested a reply, send it when we leave this block, no + // matter how. + sendReply(mResp, mReq, mKey); +} + +void LLEventAPI::Response::warn(const std::string& warning) +{ + LL_WARNS("LLEventAPI::Response") << warning << LL_ENDL; + mResp["warnings"].append(warning); +} + +void LLEventAPI::Response::error(const std::string& error) +{ + // Use LL_WARNS rather than LL_ERROR: we don't want the viewer to shut + // down altogether. + LL_WARNS("LLEventAPI::Response") << error << LL_ENDL; + + mResp["error"] = error; +} diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h index d75d521e8e..332dee9550 100644 --- a/indra/llcommon/lleventapi.h +++ b/indra/llcommon/lleventapi.h @@ -76,6 +76,84 @@ public: LLEventDispatcher::add(name, desc, callable, required); } + /** + * Instantiate a Response object in any LLEventAPI subclass method that + * wants to guarantee a reply (if requested) will be sent on exit from the + * method. The reply will be sent if request.has(@a replyKey), default + * "reply". If specified, the value of request[replyKey] is the name of + * the LLEventPump on which to send the reply. Conventionally you might + * code something like: + * + * @code + * void MyEventAPI::someMethod(const LLSD& request) + * { + * // Send a reply event as long as request.has("reply") + * Response response(LLSD(), request); + * // ... + * // will be sent in reply event + * response["somekey"] = some_data; + * } + * @endcode + */ + class Response + { + public: + /** + * Instantiating a Response object in an LLEventAPI subclass method + * ensures that, if desired, a reply event will be sent. + * + * @a seed is the initial reply LLSD that will be further decorated before + * being sent as the reply + * + * @a request is the incoming request LLSD; we particularly care about + * [replyKey] and ["reqid"] + * + * @a replyKey [default "reply"] is the string name of the LLEventPump + * on which the caller wants a reply. If (! + * request.has(replyKey)), no reply will be sent. + */ + Response(const LLSD& seed, const LLSD& request, const LLSD::String& replyKey="reply"); + ~Response(); + + /** + * @code + * if (some condition) + * { + * response.warn("warnings are logged and collected in [\"warnings\"]"); + * } + * @endcode + */ + void warn(const std::string& warning); + /** + * @code + * if (some condition isn't met) + * { + * // In a function returning void, you can validly 'return + * // expression' if the expression is itself of type void. But + * // returning is up to you; response.error() has no effect on + * // flow of control. + * return response.error("error message, logged and also sent as [\"error\"]"); + * } + * @endcode + */ + void error(const std::string& error); + + /** + * set other keys... + * + * @code + * // set any attributes you want to be sent in the reply + * response["info"] = some_value; + * // ... + * response["ok"] = went_well; + * @endcode + */ + LLSD& operator[](const LLSD::String& key) { return mResp[key]; } + + LLSD mResp, mReq; + LLSD::String mKey; + }; + private: std::string mDesc; }; -- cgit v1.2.3 From ecba41419f6470cc3d85bbb277ef88ebbf266feb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 6 Sep 2011 13:25:27 -0400 Subject: CHOP-763: Nested LLEventAPI::Response class needs LL_COMMON_API too. Apparently the outer class's LL_COMMON_API marker affects all outer class members, but not nested classes. Making it explicit fixes Windows link errors. --- indra/llcommon/lleventapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h index 332dee9550..64d038ade4 100644 --- a/indra/llcommon/lleventapi.h +++ b/indra/llcommon/lleventapi.h @@ -95,7 +95,7 @@ public: * } * @endcode */ - class Response + class LL_COMMON_API Response { public: /** -- cgit v1.2.3