/** * @file LLAccountingQuotaManager.cpp * @ Handles the setting and accessing for costs associated with mesh * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2011, 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$ */ #include "llviewerprecompiledheaders.h" #include "llaccountingcostmanager.h" #include "llagent.h" #include "httpcommon.h" #include "llcoros.h" #include "lleventcoro.h" #include "llcorehttputil.h" //=============================================================================== LLAccountingCostManager::LLAccountingCostManager(): mHttpRequest(), mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID) { mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); //mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; } // 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(std::string url, eSelectionType selectionType, const LLHandle observerHandle) { LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName() << " with url '" << url << LL_ENDL; try { 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) 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; LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("AccountingCost", mHttpPolicy); LLSD results = httpAdapter.postAndYield(mHttpRequest, url, dataToPost); LLSD httpResults; httpResults = results["http_result"]; // do/while(false) allows error conditions to break out of following // block while normal flow goes forward once. do { observer = observerHandle.get(); if ((!observer) || (observer->getTransactionID() != transactionId)) { // *TODO: Rider: I've noticed that getTransactionID() does not // always match transactionId (the new transaction Id does not show a // corresponding request.) (ask Vir) 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(); } //=============================================================================== void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, const std::string& url, const LLHandle& observer_handle ) { // Invoking system must have already determined capability availability if ( !url.empty() ) { std::string coroname = LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro", boost::bind(&LLAccountingCostManager::accountingCostCoro, this, url, selectionType, observer_handle)); LL_DEBUGS() << coroname << " with url '" << url << LL_ENDL; } else { //url was empty - warn & continue LL_WARNS()<<"Supplied url is empty "<