Added a class to automate pumping the HttpRequest on the mainloop.

Converted AccountingCostManager to use the new LLCore::Http library and coroutines.
master
Rider Linden 2015-04-03 14:23:31 -07:00
parent fbd58959c2
commit 17641c8427
5 changed files with 210 additions and 120 deletions

View File

@ -29,8 +29,6 @@
#define LLAVATARNAMECACHE_H
#include "llavatarname.h" // for convenience
//#include "httpcommon.h"
//#include "httpheaders.h"
#include <boost/signals2.hpp>
class LLSD;

View File

@ -279,6 +279,27 @@ void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::H
result["http_result"] = httpresults;
}
HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request):
mHttpRequest(request)
{
mBoundListener = LLEventPumps::instance().obtain("mainloop").
listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1));
}
HttpRequestPumper::~HttpRequestPumper()
{
if (mBoundListener.connected())
{
mBoundListener.disconnect();
}
}
bool HttpRequestPumper::pollRequest(const LLSD&)
{
mHttpRequest->update(0L);
return false;
}
} // end namespace LLCoreHttpUtil

View File

@ -165,8 +165,6 @@ LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request,
/// +- ["url"] - The URL used to make the call.
/// +- ["headers"] - A map of name name value pairs with the HTTP headers.
///
///
class HttpCoroHandler : public LLCore::HttpHandler
{
public:
@ -182,6 +180,22 @@ private:
LLEventStream &mReplyPump;
};
/// The HttpRequestPumper is a utility class. When constructed it will poll the
/// supplied HttpRequest once per frame until it is destroyed.
///
class HttpRequestPumper
{
public:
HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request);
~HttpRequestPumper();
private:
bool pollRequest(const LLSD&);
LLTempBoundListener mBoundListener;
LLCore::HttpRequest::ptr_t mHttpRequest;
};
} // end namespace LLCoreHttpUtil

View File

@ -27,90 +27,171 @@
#include "llviewerprecompiledheaders.h"
#include "llaccountingcostmanager.h"
#include "llagent.h"
#include "llcurl.h"
#include "llhttpclient.h"
#include "httpcommon.h"
#include "llcoros.h"
#include "lleventcoro.h"
#include "llcorehttputil.h"
//===============================================================================
LLAccountingCostManager::LLAccountingCostManager()
LLAccountingCostManager::LLAccountingCostManager():
mHttpRequest(),
mHttpHeaders(),
mHttpOptions(),
mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mHttpPriority(0)
{
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest());
mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false);
//mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID;
}
//===============================================================================
class LLAccountingCostResponder : public LLCurl::Responder
// Coroutine for sending and processing avatar name cache requests.
// Do not call directly. See documentation in lleventcoro.h and llcoro.h for
// further explanation.
void LLAccountingCostManager::accountingCostCoro(LLCoros::self& self, std::string url,
eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle)
{
LOG_CLASS(LLAccountingCostResponder);
public:
LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle )
: mObjectIDs( objectIDs ),
mObserverHandle( observer_handle )
{
LLAccountingCostObserver* observer = mObserverHandle.get();
if (observer)
{
mTransactionID = observer->getTransactionID();
}
}
LLEventStream replyPump("AccountingCostReply", true);
LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =
LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump));
void clearPendingRequests ( void )
{
for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter )
{
LLAccountingCostManager::getInstance()->removePendingObject( iter->asUUID() );
}
}
protected:
void httpFailure()
{
LL_WARNS() << dumpResponse() << LL_ENDL;
clearPendingRequests();
LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName(self)
<< " with url '" << url << LL_ENDL;
LLAccountingCostObserver* observer = mObserverHandle.get();
if (observer && observer->getTransactionID() == mTransactionID)
{
observer->setErrorStatus(getStatus(), getReason());
}
}
void httpSuccess()
{
const LLSD& content = getContent();
//Check for error
if ( !content.isMap() || content.has("error") )
{
failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content);
return;
}
else if (content.has("selected"))
{
F32 physicsCost = 0.0f;
F32 networkCost = 0.0f;
F32 simulationCost = 0.0f;
try
{
LLSD objectList;
U32 objectIndex = 0;
physicsCost = content["selected"]["physics"].asReal();
networkCost = content["selected"]["streaming"].asReal();
simulationCost = content["selected"]["simulation"].asReal();
SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost );
IDIt IDIter = mObjectList.begin();
IDIt IDIterEnd = mObjectList.end();
LLAccountingCostObserver* observer = mObserverHandle.get();
if (observer && observer->getTransactionID() == mTransactionID)
{
observer->onWeightsUpdate(selectionCost);
}
}
for (; IDIter != IDIterEnd; ++IDIter)
{
// Check to see if a request for this object has already been made.
if (mPendingObjectQuota.find(*IDIter) == mPendingObjectQuota.end())
{
mPendingObjectQuota.insert(*IDIter);
objectList[objectIndex++] = *IDIter;
}
}
clearPendingRequests();
}
private:
//List of posted objects
LLSD mObjectIDs;
mObjectList.clear();
// Current request ID
LLUUID mTransactionID;
//Post results
if (objectList.size() == 0)
return;
std::string keystr;
if (selectionType == Roots)
{
keystr = "selected_roots";
}
else if (selectionType == Prims)
{
keystr = "selected_prims";
}
else
{
LL_INFOS() << "Invalid selection type " << LL_ENDL;
mObjectList.clear();
mPendingObjectQuota.clear();
return;
}
LLSD dataToPost = LLSD::emptyMap();
dataToPost[keystr.c_str()] = objectList;
LLAccountingCostObserver* observer = observerHandle.get();
LLUUID transactionId = observer->getTransactionID();
observer = NULL;
LLSD results;
{ // Scoping block for pumper object
LL_INFOS() << "Requesting transaction " << transactionId << LL_ENDL;
LLCoreHttpUtil::HttpRequestPumper pumper(mHttpRequest);
LLCore::HttpHandle hhandle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,
mHttpPolicy, mHttpPriority, url, dataToPost, mHttpOptions, mHttpHeaders,
httpHandler.get());
if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
{
LLCore::HttpStatus status = mHttpRequest->getStatus();
LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
" message = " << status.getMessage() << LL_ENDL;
mPendingObjectQuota.clear();
return;
}
results = waitForEventOn(self, replyPump);
LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
}
LLSD httpResults;
httpResults = results["http_result"];
do
{
observer = observerHandle.get();
if ((!observer) || (observer->getTransactionID() != transactionId))
{
if (!observer)
break;
LL_WARNS() << "Request transaction Id(" << transactionId
<< ") does not match observer's transaction Id("
<< observer->getTransactionID() << ")." << LL_ENDL;
break;
}
if (!httpResults["success"].asBoolean())
{
LL_WARNS() << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
<< httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
if (observer)
{
observer->setErrorStatus(httpResults["status"].asInteger(), httpResults["message"].asStringRef());
}
break;
}
if (!results.isMap() || results.has("error"))
{
LL_WARNS() << "Error on fetched data" << LL_ENDL;
observer->setErrorStatus(499, "Error on fetched data");
break;
}
if (results.has("selected"))
{
F32 physicsCost = 0.0f;
F32 networkCost = 0.0f;
F32 simulationCost = 0.0f;
physicsCost = results["selected"]["physics"].asReal();
networkCost = results["selected"]["streaming"].asReal();
simulationCost = results["selected"]["simulation"].asReal();
SelectionCost selectionCost( physicsCost, networkCost, simulationCost);
observer->onWeightsUpdate(selectionCost);
}
} while (false);
}
catch (std::exception e)
{
LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
}
catch (...)
{
LL_WARNS() << "Caught unknown exception." << LL_ENDL;
}
mPendingObjectQuota.clear();
}
// Cost update observer handle
LLHandle<LLAccountingCostObserver> mObserverHandle;
};
//===============================================================================
void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
const std::string& url,
@ -119,50 +200,11 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,
// Invoking system must have already determined capability availability
if ( !url.empty() )
{
LLSD objectList;
U32 objectIndex = 0;
IDIt IDIter = mObjectList.begin();
IDIt IDIterEnd = mObjectList.end();
for ( ; IDIter != IDIterEnd; ++IDIter )
{
// Check to see if a request for this object has already been made.
if ( mPendingObjectQuota.find( *IDIter ) == mPendingObjectQuota.end() )
{
mPendingObjectQuota.insert( *IDIter );
objectList[objectIndex++] = *IDIter;
}
}
mObjectList.clear();
//Post results
if ( objectList.size() > 0 )
{
std::string keystr;
if ( selectionType == Roots )
{
keystr="selected_roots";
}
else
if ( selectionType == Prims )
{
keystr="selected_prims";
}
else
{
LL_INFOS()<<"Invalid selection type "<<LL_ENDL;
mObjectList.clear();
mPendingObjectQuota.clear();
return;
}
LLSD dataToPost = LLSD::emptyMap();
dataToPost[keystr.c_str()] = objectList;
std::string coroname =
LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro",
boost::bind(&LLAccountingCostManager::accountingCostCoro, this, _1, url, selectionType, observer_handle));
LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL;
LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle ));
}
}
else
{

View File

@ -30,6 +30,13 @@
#include "llhandle.h"
#include "llaccountingcost.h"
#include "httpcommon.h"
#include "llcoros.h"
#include "lleventcoro.h"
#include "httprequest.h"
#include "httpheaders.h"
#include "httpoptions.h"
//===============================================================================
// An interface class for panels which display the parcel accounting information.
class LLAccountingCostObserver
@ -69,6 +76,14 @@ private:
//a fetch has been instigated.
std::set<LLUUID> mPendingObjectQuota;
typedef std::set<LLUUID>::iterator IDIt;
void accountingCostCoro(LLCoros::self& self, std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle);
LLCore::HttpRequest::ptr_t mHttpRequest;
LLCore::HttpHeaders::ptr_t mHttpHeaders;
LLCore::HttpOptions::ptr_t mHttpOptions;
LLCore::HttpRequest::policy_t mHttpPolicy;
LLCore::HttpRequest::priority_t mHttpPriority;
};
//===============================================================================