diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llcallbacklist.cpp | 156 | ||||
-rw-r--r-- | indra/llcommon/llcallbacklist.h | 10 | ||||
-rw-r--r-- | indra/llcommon/llevents.cpp | 7 | ||||
-rw-r--r-- | indra/llcommon/lleventtimer.cpp | 2 |
4 files changed, 161 insertions, 14 deletions
diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 52e9860e02..c89f7d12b2 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -24,8 +24,10 @@ * $/LicenseInfo$ */ +#include "lazyeventapi.h" #include "llcallbacklist.h" #include "llexception.h" +#include "llsdutil.h" #include <vector> // @@ -140,22 +142,22 @@ Timers::handle_t Timers::scheduleAt(nullary_func_t callable, LLDate::timestamp t { // tick() assumes you want to run periodically until you return true. // Schedule a task that returns true after a single call. - return scheduleAtRepeating(once(callable), time, 0); + return scheduleAtEvery(once(callable), time, 0); } // Call a given callable once after specified interval. Timers::handle_t Timers::scheduleAfter(nullary_func_t callable, F32 seconds) { - return scheduleRepeating(once(callable), seconds); + return scheduleEvery(once(callable), seconds); } // Call a given callable every specified number of seconds, until it returns true. -Timers::handle_t Timers::scheduleRepeating(bool_func_t callable, F32 seconds) +Timers::handle_t Timers::scheduleEvery(bool_func_t callable, F32 seconds) { - return scheduleAtRepeating(callable, now() + seconds, seconds); + return scheduleAtEvery(callable, now() + seconds, seconds); } -Timers::handle_t Timers::scheduleAtRepeating(bool_func_t callable, +Timers::handle_t Timers::scheduleAtEvery(bool_func_t callable, LLDate::timestamp time, F32 interval) { // Pick token FIRST to store a self-reference in mQueue's managed node as @@ -203,7 +205,7 @@ F32 Timers::timeUntilCall(handle_t timer) const } } -// Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating() +// Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleEvery() bool Timers::cancel(handle_t& timer) { // For exception safety, capture and clear timer before canceling. @@ -383,4 +385,146 @@ bool Timers::tick() return mQueue.empty(); } +/***************************************************************************** +* TimersListener +*****************************************************************************/ + +class TimersListener: public LLEventAPI +{ +public: + TimersListener(const LazyEventAPIParams& params): LLEventAPI(params) {} + + // Forbid a script from requesting callbacks too quickly. + static constexpr LLSD::Real MINTIMER{ 1.0 }; + + void scheduleAfter(const LLSD& params); + void scheduleEvery(const LLSD& params); + LLSD cancel(const LLSD& params); + LLSD isRunning(const LLSD& params); + LLSD timeUntilCall(const LLSD& params); + +private: + using HandleMap = std::unordered_map<LLSD::Integer, Timers::temp_handle_t>; + HandleMap mHandles; +}; + +void TimersListener::scheduleAfter(const LLSD& params) +{ + LLSD::Real after{ params["after"] }; + if (after < MINTIMER) + { + sendReply(llsd::map("error", stringize("after must be at least ", MINTIMER)), params); + return; + } + + mHandles.emplace( + params["reqid"], + Timers::instance().scheduleAfter( + [this, params] + { + // we don't need any content save for the "reqid" + sendReply({}, params); + // ditch mHandles entry + mHandles.erase(params["reqid"]); + }, + after)); +} + +void TimersListener::scheduleEvery(const LLSD& params) +{ + LLSD::Real every{ params["every"] }; + if (every < MINTIMER) + { + sendReply(llsd::map("error", stringize("every must be at least ", MINTIMER)), params); + return; + } + + mHandles.emplace( + params["reqid"], + Timers::instance().scheduleEvery( + [params, i=0]() mutable + { + // we don't need any content save for the "reqid" + sendReply(llsd::map("i", i++), params); + // we can't use a handshake -- always keep the ball rolling + return false; + }, + every)); +} + +LLSD TimersListener::cancel(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool ok = false; + if (found != mHandles.end()) + { + ok = true; + Timers::instance().cancel(found->second); + mHandles.erase(found); + } + return llsd::map("ok", ok); +} + +LLSD TimersListener::isRunning(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool running = false; + if (found != mHandles.end()) + { + running = Timers::instance().isRunning(found->second); + } + return llsd::map("running", running); +} + +LLSD TimersListener::timeUntilCall(const LLSD& params) +{ + auto found{ mHandles.find(params["id"]) }; + bool ok = false; + LLSD::Real remaining = 0; + if (found != mHandles.end()) + { + ok = true; + remaining = Timers::instance().timeUntilCall(found->second); + } + return llsd::map("ok", ok, "remaining", remaining); +} + +class TimersRegistrar: public LazyEventAPI<TimersListener> +{ + using super = LazyEventAPI<TimersListener>; + using super::listener; + +public: + TimersRegistrar(): + super("Timers", "Provide access to viewer timer functionality.") + { + add("scheduleAfter", +R"-(Create a timer with ID "reqid". Post response after "after" seconds.)-", + &listener::scheduleAfter, + llsd::map("reqid", LLSD::Integer(), "after", LLSD::Real())); + add("scheduleEvery", +R"-(Create a timer with ID "reqid". Post response every "every" seconds +until cancel().)-", + &listener::scheduleEvery, + llsd::map("reqid", LLSD::Integer(), "every", LLSD::Real())); + add("cancel", +R"-(Cancel the timer with ID "id". Respond "ok"=true if "id" identifies +a live timer.)-", + &listener::cancel, + llsd::map("reqid", LLSD::Integer(), "id", LLSD::Integer())); + add("isRunning", +R"-(Query the timer with ID "id": respond "running"=true if "id" identifies +a live timer.)-", + &listener::isRunning, + llsd::map("reqid", LLSD::Integer(), "id", LLSD::Integer())); + add("timeUntilCall", +R"-(Query the timer with ID "id": if "id" identifies a live timer, respond +"ok"=true, "remaining"=seconds with the time left before timer expiry; +otherwise "ok"=false, "remaining"=0.)-", + &listener::timeUntilCall, + llsd::map("reqid", LLSD::Integer())); + } +}; +static TimersRegistrar registrar; + } // namespace LL diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index f9b15867ef..2fb27d5ea8 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -168,14 +168,14 @@ public: handle_t scheduleAfter(nullary_func_t callable, F32 seconds); // Call a given callable every specified number of seconds, until it returns true. - handle_t scheduleRepeating(bool_func_t callable, F32 seconds); + handle_t scheduleEvery(bool_func_t callable, F32 seconds); // test whether specified handle is still live bool isRunning(handle_t timer) const; // check remaining time F32 timeUntilCall(handle_t timer) const; - // Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleRepeating(). + // Cancel a future timer set by scheduleAt(), scheduleAfter(), scheduleEvery(). // Return true if and only if the handle corresponds to a live timer. bool cancel(const handle_t& timer); // If we're canceling a non-const handle_t, also clear it so we need not @@ -183,7 +183,7 @@ public: bool cancel(handle_t& timer); // Store a handle_t returned by scheduleAt(), scheduleAfter() or - // scheduleRepeating() in a temp_handle_t to cancel() automatically on + // scheduleEvery() in a temp_handle_t to cancel() automatically on // destruction of the temp_handle_t. class temp_handle_t { @@ -237,7 +237,7 @@ public: }; private: - handle_t scheduleAtRepeating(bool_func_t callable, LLDate::timestamp time, F32 interval); + handle_t scheduleAtEvery(bool_func_t callable, LLDate::timestamp time, F32 interval); LLDate::timestamp now() const { return LLDate::now().secondsSinceEpoch(); } // wrap a nullary_func_t with a bool_func_t that will only execute once bool_func_t once(nullary_func_t callable) @@ -294,7 +294,7 @@ LL::Timers::handle_t doAfterInterval(nullary_func_t callable, F32 seconds) inline LL::Timers::handle_t doPeriodically(bool_func_t callable, F32 seconds) { - return LL::Timers::instance().scheduleRepeating(callable, seconds); + return LL::Timers::instance().scheduleEvery(callable, seconds); } #endif diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index d7870763cc..e10e555f8b 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -759,6 +759,9 @@ bool sendReply(LLSD reply, const LLSD& request, const std::string& replyKey) LLReqID reqID(request); // and copy it to 'reply'. reqID.stamp(reply); - // Send reply on LLEventPump named in request[replyKey]. - return LLEventPumps::instance().obtain(request[replyKey]).post(reply); + // Send reply on LLEventPump named in request[replyKey] -- if that + // LLEventPump exists. If it does not, don't create it. + // This addresses the case in which a requester goes away before a + // particular LLEventAPI responds. + return LLEventPumps::instance().post(request[replyKey], reply); } diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index 1d2da93683..43c1a255ac 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -49,7 +49,7 @@ LLEventTimer::~LLEventTimer() void LLEventTimer::start() { - mTimer = LL::Timers::instance().scheduleRepeating([this]{ return tick(); }, mPeriod); + mTimer = LL::Timers::instance().scheduleEvery([this]{ return tick(); }, mPeriod); } void LLEventTimer::stop() |