Code owners
Assign users and groups as approvers for specific file changes. Learn more.
llcapabilitylistener.cpp 7.68 KiB
/**
* @file llcapabilitylistener.cpp
* @author Nat Goodspeed
* @date 2009-01-07
* @brief Implementation for llcapabilitylistener.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// Precompiled header
#include "llviewerprecompiledheaders.h"
// associated header
#include "llcapabilitylistener.h"
// STL headers
#include <map>
// std headers
// external library headers
#include <boost/bind.hpp>
// other Linden headers
#include "stringize.h"
#include "llcapabilityprovider.h"
#include "message.h"
class LLCapabilityListener::CapabilityMappers: public LLSingleton<LLCapabilityListener::CapabilityMappers>
{
public:
void registerMapper(const LLCapabilityListener::CapabilityMapper*);
void unregisterMapper(const LLCapabilityListener::CapabilityMapper*);
const LLCapabilityListener::CapabilityMapper* find(const std::string& cap) const;
struct DupCapMapper: public std::runtime_error
{
DupCapMapper(const std::string& what):
std::runtime_error(std::string("DupCapMapper: ") + what)
{}
};
private:
friend class LLSingleton<LLCapabilityListener::CapabilityMappers>;
CapabilityMappers();
typedef std::map<std::string, const LLCapabilityListener::CapabilityMapper*> CapabilityMap;
CapabilityMap mMap;
};
LLCapabilityListener::LLCapabilityListener(const std::string& name,
LLMessageSystem* messageSystem,
const LLCapabilityProvider& provider,
const LLUUID& agentID,
const LLUUID& sessionID):
mEventPump(name),
mMessageSystem(messageSystem),
mProvider(provider),
mAgentID(agentID),
mSessionID(sessionID)
{
mEventPump.listen("self", boost::bind(&LLCapabilityListener::capListener, this, _1));
}
bool LLCapabilityListener::capListener(const LLSD& request)
{
// Extract what we want from the request object. We do it all up front
// partly to document what we expect.
LLSD::String cap(request["message"]);
LLSD payload(request["payload"]);
LLSD::String reply(request["reply"]);
LLSD::String error(request["error"]);
LLSD::Real timeout(request["timeout"]);
// If the LLSD doesn't even have a "message" key, we doubt it was intended
// for this listener.
if (cap.empty())
{
LL_ERRS("capListener") << "capability request event without 'message' key to '"
<< getCapAPI().getName()
<< "' on region\n" << mProvider.getDescription()
<< LL_ENDL;
return false; // in case fatal-error function isn't
}
// Establish default timeout. This test relies on LLSD::asReal() returning
// exactly 0.0 for an undef value.
if (! timeout)
{
timeout = HTTP_REQUEST_EXPIRY_SECS;
}
// Look up the url for the requested capability name.
std::string url = mProvider.getCapability(cap);
if (! url.empty())
{
// This capability is supported by the region to which we're talking.
LLHTTPClient::post(url, payload,
new LLSDMessage::EventResponder(LLEventPumps::instance(),
request,
mProvider.getDescription(),
cap, reply, error),
LLSD(), // headers
timeout);
}
else
{
// Capability not supported -- do we have a registered mapper?
const CapabilityMapper* mapper = CapabilityMappers::instance().find(cap);
if (! mapper) // capability neither supported nor mapped
{
LL_ERRS("capListener") << "unsupported capability '" << cap << "' request to '"
<< getCapAPI().getName() << "' on region\n"
<< mProvider.getDescription()
<< LL_ENDL;
}
else if (! mapper->getReplyName().empty()) // mapper expects reply support
{
LL_ERRS("capListener") << "Mapper for capability '" << cap
<< "' requires unimplemented support for reply message '"
<< mapper->getReplyName()
<< "' on '" << getCapAPI().getName() << "' on region\n"
<< mProvider.getDescription()
<< LL_ENDL;
}
else
{
LL_INFOS("capListener") << "fallback invoked for capability '" << cap
<< "' request to '" << getCapAPI().getName()
<< "' on region\n" << mProvider.getDescription()
<< LL_ENDL;
mapper->buildMessage(mMessageSystem, mAgentID, mSessionID, cap, payload);
mMessageSystem->sendReliable(mProvider.getHost());
}
}
return false;
}
LLCapabilityListener::CapabilityMapper::CapabilityMapper(const std::string& cap, const std::string& reply):
mCapName(cap),
mReplyName(reply)
{
LLCapabilityListener::CapabilityMappers::instance().registerMapper(this);
}
LLCapabilityListener::CapabilityMapper::~CapabilityMapper()
{
LLCapabilityListener::CapabilityMappers::instance().unregisterMapper(this);
}
LLSD LLCapabilityListener::CapabilityMapper::readResponse(LLMessageSystem* messageSystem) const
{
return LLSD();
}
LLCapabilityListener::CapabilityMappers::CapabilityMappers() {}
void LLCapabilityListener::CapabilityMappers::registerMapper(const LLCapabilityListener::CapabilityMapper* mapper)
{
// Try to insert a new map entry by which we can look up the passed mapper
// instance.
std::pair<CapabilityMap::iterator, bool> inserted =
mMap.insert(CapabilityMap::value_type(mapper->getCapName(), mapper));
// If we already have a mapper for that name, insert() merely located the
// existing iterator and returned false. It is a coding error to try to
// register more than one mapper for the same capability name.
if (! inserted.second)
{
throw DupCapMapper(std::string("Duplicate capability name ") + mapper->getCapName());
}
}
void LLCapabilityListener::CapabilityMappers::unregisterMapper(const LLCapabilityListener::CapabilityMapper* mapper)
{
CapabilityMap::iterator found = mMap.find(mapper->getCapName());
if (found != mMap.end())
{
mMap.erase(found);
}
}
const LLCapabilityListener::CapabilityMapper*
LLCapabilityListener::CapabilityMappers::find(const std::string& cap) const
{
CapabilityMap::const_iterator found = mMap.find(cap);
if (found != mMap.end())
{
return found->second;
}
return NULL;
}