PageRenderTime 399ms CodeModel.GetById 136ms app.highlight 163ms RepoModel.GetById 97ms app.codeStats 0ms

/indra/newview/llcapabilitylistener.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 202 lines | 141 code | 14 blank | 47 comment | 11 complexity | b44d7c77ae0ce0ee1f526d096d326493 MD5 | raw file
  1/**
  2 * @file   llcapabilitylistener.cpp
  3 * @author Nat Goodspeed
  4 * @date   2009-01-07
  5 * @brief  Implementation for llcapabilitylistener.
  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// Precompiled header
 30#include "llviewerprecompiledheaders.h"
 31// associated header
 32#include "llcapabilitylistener.h"
 33// STL headers
 34#include <map>
 35// std headers
 36// external library headers
 37#include <boost/bind.hpp>
 38// other Linden headers
 39#include "stringize.h"
 40#include "llcapabilityprovider.h"
 41#include "message.h"
 42
 43class LLCapabilityListener::CapabilityMappers: public LLSingleton<LLCapabilityListener::CapabilityMappers>
 44{
 45public:
 46    void registerMapper(const LLCapabilityListener::CapabilityMapper*);
 47    void unregisterMapper(const LLCapabilityListener::CapabilityMapper*);
 48    const LLCapabilityListener::CapabilityMapper* find(const std::string& cap) const;
 49
 50    struct DupCapMapper: public std::runtime_error
 51    {
 52        DupCapMapper(const std::string& what):
 53            std::runtime_error(std::string("DupCapMapper: ") + what)
 54        {}
 55    };
 56
 57private:
 58    friend class LLSingleton<LLCapabilityListener::CapabilityMappers>;
 59    CapabilityMappers();
 60
 61    typedef std::map<std::string, const LLCapabilityListener::CapabilityMapper*> CapabilityMap;
 62    CapabilityMap mMap;
 63};
 64
 65LLCapabilityListener::LLCapabilityListener(const std::string& name,
 66                                           LLMessageSystem* messageSystem,
 67                                           const LLCapabilityProvider& provider,
 68                                           const LLUUID& agentID,
 69                                           const LLUUID& sessionID):
 70    mEventPump(name),
 71    mMessageSystem(messageSystem),
 72    mProvider(provider),
 73    mAgentID(agentID),
 74    mSessionID(sessionID)
 75{
 76    mEventPump.listen("self", boost::bind(&LLCapabilityListener::capListener, this, _1));
 77}
 78
 79bool LLCapabilityListener::capListener(const LLSD& request)
 80{
 81    // Extract what we want from the request object. We do it all up front
 82    // partly to document what we expect.
 83    LLSD::String cap(request["message"]);
 84    LLSD payload(request["payload"]);
 85    LLSD::String reply(request["reply"]);
 86    LLSD::String error(request["error"]);
 87    LLSD::Real timeout(request["timeout"]);
 88    // If the LLSD doesn't even have a "message" key, we doubt it was intended
 89    // for this listener.
 90    if (cap.empty())
 91    {
 92        LL_ERRS("capListener") << "capability request event without 'message' key to '"
 93                               << getCapAPI().getName()
 94                               << "' on region\n" << mProvider.getDescription()
 95                               << LL_ENDL;
 96        return false;               // in case fatal-error function isn't
 97    }
 98    // Establish default timeout. This test relies on LLSD::asReal() returning
 99    // exactly 0.0 for an undef value.
100    if (! timeout)
101    {
102        timeout = HTTP_REQUEST_EXPIRY_SECS;
103    }
104    // Look up the url for the requested capability name.
105    std::string url = mProvider.getCapability(cap);
106    if (! url.empty())
107    {
108        // This capability is supported by the region to which we're talking.
109        LLHTTPClient::post(url, payload,
110                           new LLSDMessage::EventResponder(LLEventPumps::instance(),
111                                                           request,
112                                                           mProvider.getDescription(),
113                                                           cap, reply, error),
114                           LLSD(),  // headers
115                           timeout);
116    }
117    else
118    {
119        // Capability not supported -- do we have a registered mapper?
120        const CapabilityMapper* mapper = CapabilityMappers::instance().find(cap);
121        if (! mapper)               // capability neither supported nor mapped
122        {
123            LL_ERRS("capListener") << "unsupported capability '" << cap << "' request to '"
124                                   << getCapAPI().getName() << "' on region\n"
125                                   << mProvider.getDescription()
126                                   << LL_ENDL;
127        }
128        else if (! mapper->getReplyName().empty()) // mapper expects reply support
129        {
130            LL_ERRS("capListener") << "Mapper for capability '" << cap
131                                   << "' requires unimplemented support for reply message '"
132                                   << mapper->getReplyName()
133                                   << "' on '" << getCapAPI().getName() << "' on region\n"
134                                   << mProvider.getDescription()
135                                   << LL_ENDL;
136        }
137        else
138        {
139            LL_INFOS("capListener") << "fallback invoked for capability '" << cap
140                                    << "' request to '" << getCapAPI().getName()
141                                    << "' on region\n" << mProvider.getDescription()
142                                    << LL_ENDL;
143            mapper->buildMessage(mMessageSystem, mAgentID, mSessionID, cap, payload);
144            mMessageSystem->sendReliable(mProvider.getHost());
145        }
146    }
147    return false;
148}
149
150LLCapabilityListener::CapabilityMapper::CapabilityMapper(const std::string& cap, const std::string& reply):
151    mCapName(cap),
152    mReplyName(reply)
153{
154    LLCapabilityListener::CapabilityMappers::instance().registerMapper(this);
155}
156
157LLCapabilityListener::CapabilityMapper::~CapabilityMapper()
158{
159    LLCapabilityListener::CapabilityMappers::instance().unregisterMapper(this);
160}
161
162LLSD LLCapabilityListener::CapabilityMapper::readResponse(LLMessageSystem* messageSystem) const
163{
164    return LLSD();
165}
166
167LLCapabilityListener::CapabilityMappers::CapabilityMappers() {}
168
169void LLCapabilityListener::CapabilityMappers::registerMapper(const LLCapabilityListener::CapabilityMapper* mapper)
170{
171    // Try to insert a new map entry by which we can look up the passed mapper
172    // instance.
173    std::pair<CapabilityMap::iterator, bool> inserted =
174        mMap.insert(CapabilityMap::value_type(mapper->getCapName(), mapper));
175    // If we already have a mapper for that name, insert() merely located the
176    // existing iterator and returned false. It is a coding error to try to
177    // register more than one mapper for the same capability name.
178    if (! inserted.second)
179    {
180        throw DupCapMapper(std::string("Duplicate capability name ") + mapper->getCapName());
181    }
182}
183
184void LLCapabilityListener::CapabilityMappers::unregisterMapper(const LLCapabilityListener::CapabilityMapper* mapper)
185{
186    CapabilityMap::iterator found = mMap.find(mapper->getCapName());
187    if (found != mMap.end())
188    {
189        mMap.erase(found);
190    }
191}
192
193const LLCapabilityListener::CapabilityMapper*
194LLCapabilityListener::CapabilityMappers::find(const std::string& cap) const
195{
196    CapabilityMap::const_iterator found = mMap.find(cap);
197    if (found != mMap.end())
198    {
199        return found->second;
200    }
201    return NULL;
202}