PageRenderTime 42ms CodeModel.GetById 17ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llmessage/llsdmessage.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 166 lines | 59 code | 16 blank | 91 comment | 0 complexity | d19a409cb5d2d0548f18288d199a0d61 MD5 | raw file
  1/**
  2 * @file   llsdmessage.h
  3 * @author Nat Goodspeed
  4 * @date   2008-10-30
  5 * @brief  API intended to unify sending capability, UDP and TCP messages:
  6 *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes
  7 * 
  8 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  9 * Second Life Viewer Source Code
 10 * Copyright (C) 2010, Linden Research, Inc.
 11 * 
 12 * This library is free software; you can redistribute it and/or
 13 * modify it under the terms of the GNU Lesser General Public
 14 * License as published by the Free Software Foundation;
 15 * version 2.1 of the License only.
 16 * 
 17 * This library is distributed in the hope that it will be useful,
 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 20 * Lesser General Public License for more details.
 21 * 
 22 * You should have received a copy of the GNU Lesser General Public
 23 * License along with this library; if not, write to the Free Software
 24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 25 * 
 26 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 27 * $/LicenseInfo$
 28 */
 29
 30#if ! defined(LL_LLSDMESSAGE_H)
 31#define LL_LLSDMESSAGE_H
 32
 33#include "llerror.h"                // LOG_CLASS()
 34#include "llevents.h"               // LLEventPumps
 35#include "llhttpclient.h"
 36#include <string>
 37#include <stdexcept>
 38
 39class LLSD;
 40
 41/**
 42 * Class managing the messaging API described in
 43 * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes
 44 */
 45class LLSDMessage
 46{
 47    LOG_CLASS(LLSDMessage);
 48
 49public:
 50    LLSDMessage();
 51
 52    /// Exception if you specify arguments badly
 53    struct ArgError: public std::runtime_error
 54    {
 55        ArgError(const std::string& what):
 56            std::runtime_error(std::string("ArgError: ") + what) {}
 57    };
 58
 59    /**
 60     * The response idiom used by LLSDMessage -- LLEventPump names on which to
 61     * post reply or error -- is designed for the case in which your
 62     * reply/error handlers are methods on the same class as the method
 63     * sending the message. Any state available to the sending method that
 64     * must be visible to the reply/error methods can conveniently be stored
 65     * on that class itself, if it's not already.
 66     *
 67     * The LLHTTPClient::Responder idiom requires a separate instance of a
 68     * separate class so that it can dispatch to the code of interest by
 69     * calling canonical virtual methods. Interesting state must be copied
 70     * into that new object. 
 71     *
 72     * With some trepidation, because existing response code is packaged in
 73     * LLHTTPClient::Responder subclasses, we provide this adapter class
 74     * <i>for transitional purposes only.</i> Instantiate a new heap
 75     * ResponderAdapter with your new LLHTTPClient::ResponderPtr. Pass
 76     * ResponderAdapter::getReplyName() and/or getErrorName() in your
 77     * LLSDMessage (or LLViewerRegion::getCapAPI()) request event. The
 78     * ResponderAdapter will call the appropriate Responder method, then
 79     * @c delete itself.
 80     */
 81    class ResponderAdapter
 82    {
 83    public:
 84        /**
 85         * Bind the new LLHTTPClient::Responder subclass instance.
 86         *
 87         * Passing the constructor a name other than the default is only
 88         * interesting if you suspect some usage will lead to an exception or
 89         * log message.
 90         */
 91        ResponderAdapter(LLHTTPClient::ResponderPtr responder,
 92                         const std::string& name="ResponderAdapter");
 93
 94        /// EventPump name on which LLSDMessage should post reply event
 95        std::string getReplyName() const { return mReplyPump.getName(); }
 96        /// EventPump name on which LLSDMessage should post error event
 97        std::string getErrorName() const { return mErrorPump.getName(); }
 98
 99    private:
100        // We have two different LLEventStreams, though we route them both to
101        // the same listener, so that we can bind an extra flag identifying
102        // which case (reply or error) reached that listener.
103        bool listener(const LLSD&, bool success);
104
105        LLHTTPClient::ResponderPtr mResponder;
106        LLEventStream mReplyPump, mErrorPump;
107    };
108
109    /**
110     * Force our implementation file to be linked with caller. The .cpp file
111     * contains a static instance of this class, which must be linked into the
112     * executable to support the canonical listener. But since the primary
113     * interface to that static instance is via a named LLEventPump rather
114     * than by direct reference, the linker doesn't necessarily perceive the
115     * necessity to bring in the translation unit. Referencing this dummy
116     * method forces the issue.
117     */
118    static void link();
119
120private:
121    friend class LLCapabilityListener;
122    /// Responder used for internal purposes by LLSDMessage and
123    /// LLCapabilityListener. Others should use higher-level APIs.
124    class EventResponder: public LLHTTPClient::Responder
125    {
126    public:
127        /**
128         * LLHTTPClient::Responder that dispatches via named LLEventPump instances.
129         * We bind LLEventPumps, even though it's an LLSingleton, for testability.
130         * We bind the string names of the desired LLEventPump instances rather
131         * than actually obtain()ing them so we only obtain() the one we're going
132         * to use. If the caller doesn't bother to listen() on it, the other pump
133         * may never materialize at all.
134         * @a target and @a message are only to clarify error processing.
135         * For a capability message, @a target should be the region description,
136         * @a message should be the capability name.
137         * For a service with a visible URL, pass the URL as @a target and the HTTP verb
138         * (e.g. "POST") as @a message.
139         */
140        EventResponder(LLEventPumps& pumps,
141                       const LLSD& request,
142                       const std::string& target, const std::string& message,
143                       const std::string& replyPump, const std::string& errorPump):
144            mPumps(pumps),
145            mReqID(request),
146            mTarget(target),
147            mMessage(message),
148            mReplyPump(replyPump),
149            mErrorPump(errorPump)
150        {}
151    
152        virtual void result(const LLSD& data);
153        virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
154    
155    private:
156        LLEventPumps& mPumps;
157        LLReqID mReqID;
158        const std::string mTarget, mMessage, mReplyPump, mErrorPump;
159    };
160
161private:
162    bool httpListener(const LLSD&);
163    LLEventStream mEventPump;
164};
165
166#endif /* ! defined(LL_LLSDMESSAGE_H) */