PageRenderTime 14ms CodeModel.GetById 2ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/lleventfilter.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 203 lines | 55 code | 21 blank | 127 comment | 0 complexity | 66f3db20b812af1785de6c4618cd5740 MD5 | raw file
  1/**
  2 * @file   lleventfilter.h
  3 * @author Nat Goodspeed
  4 * @date   2009-03-05
  5 * @brief  Define LLEventFilter: LLEventStream subclass with conditions
  6 * 
  7 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#if ! defined(LL_LLEVENTFILTER_H)
 30#define LL_LLEVENTFILTER_H
 31
 32#include "llevents.h"
 33#include "stdtypes.h"
 34#include "lltimer.h"
 35#include <boost/function.hpp>
 36
 37/**
 38 * Generic base class
 39 */
 40class LL_COMMON_API LLEventFilter: public LLEventStream
 41{
 42public:
 43    /// construct a standalone LLEventFilter
 44    LLEventFilter(const std::string& name="filter", bool tweak=true):
 45        LLEventStream(name, tweak)
 46    {}
 47    /// construct LLEventFilter and connect it to the specified LLEventPump
 48    LLEventFilter(LLEventPump& source, const std::string& name="filter", bool tweak=true);
 49
 50    /// Post an event to all listeners
 51    virtual bool post(const LLSD& event) = 0;
 52};
 53
 54/**
 55 * Pass through only events matching a specified pattern
 56 */
 57class LLEventMatching: public LLEventFilter
 58{
 59public:
 60    /// Pass an LLSD map with keys and values the incoming event must match
 61    LLEventMatching(const LLSD& pattern);
 62    /// instantiate and connect
 63    LLEventMatching(LLEventPump& source, const LLSD& pattern);
 64
 65    /// Only pass through events matching the pattern
 66    virtual bool post(const LLSD& event);
 67
 68private:
 69    LLSD mPattern;
 70};
 71
 72/**
 73 * Wait for an event to be posted. If no such event arrives within a specified
 74 * time, take a specified action. See LLEventTimeout for production
 75 * implementation.
 76 *
 77 * @NOTE This is an abstract base class so that, for testing, we can use an
 78 * alternate "timer" that doesn't actually consume real time.
 79 */
 80class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter
 81{
 82public:
 83    /// construct standalone
 84    LLEventTimeoutBase();
 85    /// construct and connect
 86    LLEventTimeoutBase(LLEventPump& source);
 87
 88    /// Callable, can be constructed with boost::bind()
 89    typedef boost::function<void()> Action;
 90
 91    /**
 92     * Start countdown timer for the specified number of @a seconds. Forward
 93     * all events. If any event arrives before timer expires, cancel timer. If
 94     * no event arrives before timer expires, take specified @a action.
 95     *
 96     * This is a one-shot timer. Once it has either expired or been canceled,
 97     * it is inert until another call to actionAfter().
 98     *
 99     * Calling actionAfter() while an existing timer is running cheaply
100     * replaces that original timer. Thus, a valid use case is to detect
101     * idleness of some event source by calling actionAfter() on each new
102     * event. A rapid sequence of events will keep the timer from expiring;
103     * the first gap in events longer than the specified timer will fire the
104     * specified Action.
105     *
106     * Any post() call cancels the timer. To be satisfied with only a
107     * particular event, chain on an LLEventMatching that only passes such
108     * events:
109     *
110     * @code
111     * event                                                 ultimate
112     * source ---> LLEventMatching ---> LLEventTimeout  ---> listener
113     * @endcode
114     *
115     * @NOTE
116     * The implementation relies on frequent events on the LLEventPump named
117     * "mainloop".
118     */
119    void actionAfter(F32 seconds, const Action& action);
120
121    /**
122     * Like actionAfter(), but where the desired Action is LL_ERRS
123     * termination. Pass the timeout time and the desired LL_ERRS @a message.
124     *
125     * This method is useful when, for instance, some async API guarantees an
126     * event, whether success or failure, within a stated time window.
127     * Instantiate an LLEventTimeout listening to that API and call
128     * errorAfter() on each async request with a timeout comfortably longer
129     * than the API's time guarantee (much longer than the anticipated
130     * "mainloop" granularity).
131     *
132     * Then if the async API breaks its promise, the program terminates with
133     * the specified LL_ERRS @a message. The client of the async API can
134     * therefore assume the guarantee is upheld.
135     *
136     * @NOTE
137     * errorAfter() is implemented in terms of actionAfter(), so all remarks
138     * about calling actionAfter() also apply to errorAfter().
139     */
140    void errorAfter(F32 seconds, const std::string& message);
141
142    /**
143     * Like actionAfter(), but where the desired Action is a particular event
144     * for all listeners. Pass the timeout time and the desired @a event data.
145     * 
146     * Suppose the timeout should only be satisfied by a particular event, but
147     * the ultimate listener must see all other incoming events as well, plus
148     * the timeout @a event if any:
149     * 
150     * @code
151     * some        LLEventMatching                           LLEventMatching
152     * event  ---> for particular  ---> LLEventTimeout  ---> for timeout
153     * source      event                                     event \
154     *       \                                                      \ ultimate
155     *        `-----------------------------------------------------> listener
156     * @endcode
157     * 
158     * Since a given listener can listen on more than one LLEventPump, we can
159     * set things up so it sees the set union of events from LLEventTimeout
160     * and the original event source. However, as LLEventTimeout passes
161     * through all incoming events, the "particular event" that satisfies the
162     * left LLEventMatching would reach the ultimate listener twice. So we add
163     * an LLEventMatching that only passes timeout events.
164     *
165     * @NOTE
166     * eventAfter() is implemented in terms of actionAfter(), so all remarks
167     * about calling actionAfter() also apply to eventAfter().
168     */
169    void eventAfter(F32 seconds, const LLSD& event);
170
171    /// Pass event through, canceling the countdown timer
172    virtual bool post(const LLSD& event);
173
174    /// Cancel timer without event
175    void cancel();
176
177protected:
178    virtual void setCountdown(F32 seconds) = 0;
179    virtual bool countdownElapsed() const = 0;
180
181private:
182    bool tick(const LLSD&);
183
184    LLBoundListener mMainloop;
185    Action mAction;
186};
187
188/// Production implementation of LLEventTimoutBase
189class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase
190{
191public:
192    LLEventTimeout();
193    LLEventTimeout(LLEventPump& source);
194
195protected:
196    virtual void setCountdown(F32 seconds);
197    virtual bool countdownElapsed() const;
198
199private:
200    LLTimer mTimer;
201};
202
203#endif /* ! defined(LL_LLEVENTFILTER_H) */