diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/scripts/lua/leap.lua | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua index 708df821e8..6477d1b9fd 100644 --- a/indra/newview/scripts/lua/leap.lua +++ b/indra/newview/scripts/lua/leap.lua @@ -16,6 +16,27 @@ -- was received and the received event data. When the queue is empty, -- get_event_next() blocks the calling Lua script until the next event is -- received. +-- +-- Usage: +-- 1. Launch some number of Lua coroutines. The code in each coroutine may +-- call leap.send(), leap.request() or leap.generate(). leap.send() returns +-- immediately ("fire and forget"). leap.request() blocks the calling +-- coroutine until it receives and returns the viewer's response to its +-- request. leap.generate() expects an arbitrary number of responses to the +-- original request. +-- 2. To handle events from the viewer other than direct responses to +-- requests, instantiate a leap.WaitFor object with a filter(pump, data) +-- override method that returns non-nil for desired events. A coroutine may +-- call wait() on any such WaitFor. +-- 3. Once the coroutines have been launched, call leap.process() on the main +-- coroutine. process() retrieves incoming events from the viewer and +-- dispatches them to waiting request() or generate() calls, or to +-- appropriate WaitFor instances. process() returns when either +-- get_event_next() raises an error or the viewer posts nil to the script's +-- reply pump to indicate it's done. +-- 4. Alternatively, a running coroutine may call leap.done() to break out of +-- leap.process(). process() won't notice until the next event from the +-- viewer, though. local ErrorQueue = require('ErrorQueue') @@ -57,6 +78,8 @@ leap._waitfors = {} -- ["reqid"] values is our very own _reply pump, we can get away with -- an integer. leap._reqid = 0 +-- break leap.process() loop +leap._done = false -- get the name of the reply pump function leap.replypump() @@ -101,6 +124,8 @@ end -- Unless the request data already contains a ["reply"] key, we insert -- reply=self.replypump to try to ensure that the expected reply will be -- returned over the socket. +-- +-- See also send(), generate(). function leap.request(pump, data) local reqid = leap._requestSetup(pump, data) local ok, response = pcall(leap._pending[reqid].wait) @@ -165,20 +190,28 @@ end -- While waiting for responses from the viewer, the C++ coroutine running the -- calling Lua script is blocked: no other Lua coroutine is running. function leap.process() + leap._done = false local ok, pump, data - while true do + while not leap._done do ok, pump, data = pcall(get_event_next) - if not ok then + print_debug('leap.process() got', ok, pump, data) + -- ok false means get_event_next() raised a Lua error + -- data nil means get_event_next() returned (pump, LLSD()) to indicate done + if not (ok and data) then + print_debug('leap.process() done') break end leap._dispatch(pump, data) end -- we're done: clean up all pending coroutines + -- if ok, then we're just done. + -- if not ok, then 'pump' is actually the error message. + message = if ok then 'done' else pump for i, waitfor in pairs(leap._pending) do - waitfor._exception(pump) + waitfor:_exception(message) end for i, waitfor in pairs(leap._waitfors) do - waitfor._exception(pump) + waitfor:_exception(message) end -- now that we're done with cleanup, propagate the error we caught above if not ok then @@ -186,6 +219,10 @@ function leap.process() end end +function leap.done() + leap._done = true +end + -- Route incoming (pump, data) event to the appropriate waiting coroutine. function leap._dispatch(pump, data) local reqid = data['reqid'] @@ -200,7 +237,7 @@ function leap._dispatch(pump, data) end -- found the right WaitForReqid object, let it handle the event data['reqid'] = nil - waitfor._handle(pump, data) + waitfor:_handle(pump, data) end -- Handle an incoming (pump, data) event with no recognizable ['reqid'] @@ -208,7 +245,7 @@ function leap._unsolicited(pump, data) -- we maintain waitfors in descending priority order, so the first waitfor -- to claim this event is the one with the highest priority for i, waitfor in pairs(leap._waitfors) do - if waitfor._handle(pump, data) then + if waitfor:_handle(pump, data) then return end end @@ -284,7 +321,10 @@ function leap.WaitFor:new(priority, name) end obj._queue = ErrorQueue:new() obj._registered = false - obj:enable() + -- if no priority, then don't enable() - remember 0 is truthy + if priority then + obj:enable() + end return obj end @@ -314,7 +354,10 @@ end -- Block the calling coroutine until a suitable unsolicited event (one -- for which filter() returns the event) arrives. function leap.WaitFor:wait() - return self._queue:Dequeue() + print_debug(self.name .. ' about to wait') + item = self._queue:Dequeue() + print_debug(self.name .. ' got ', item) + return item end -- Loop over wait() calls. @@ -335,7 +378,7 @@ end -- return {pump=pump, data=data} -- or some variation. function leap.WaitFor:filter(pump, data) - error('You must subclass WaitFor and override its filter() method') + error('You must override the WaitFor.filter() method') end -- called by leap._unsolicited() for each WaitFor in leap._waitfors @@ -357,6 +400,7 @@ end -- called by leap.process() when get_event_next() raises an error function leap.WaitFor:_exception(message) + print_warning(self.name .. ' error: ' .. message) self._queue:Error(message) end @@ -367,22 +411,13 @@ function leap.WaitForReqid:new(reqid) -- priority is meaningless, since this object won't be added to the -- priority-sorted ViewerClient.waitfors list. Use the reqid as the -- debugging name string. - local obj = leap.WaitFor:new(0, 'WaitForReqid(' .. reqid .. ')') + local obj = leap.WaitFor:new(nil, 'WaitForReqid(' .. reqid .. ')') setmetatable(obj, self) self.__index = self return obj end -function leap.WaitForReqid:enable() - -- Do NOT self-register in the normal way. request() and generate() - -- have an entirely different registry that points directly to the - -- WaitForReqid object of interest. -end - -function leap.WaitForReqid:disable() -end - function leap.WaitForReqid:filter(pump, data) -- Because we expect to directly look up the WaitForReqid object of -- interest based on the incoming ["reqid"] value, it's not necessary |