diff options
author | rider <rider@lindenlab.com> | 2015-10-01 12:36:52 -0700 |
---|---|---|
committer | rider <rider@lindenlab.com> | 2015-10-01 12:36:52 -0700 |
commit | ca81b19e80d0e0301b08bad9bd32ada937dea10d (patch) | |
tree | 86e33382a19aa9b9f1555b8987a1a6b511b8cbe5 /indra/newview | |
parent | 17ff449ae6b2759f212daa4fd3de0a7ea2664866 (diff) | |
parent | 4334fd27e2215c1bfad3aa7ab7130b8c6b289de5 (diff) |
Merge for Xcode 7
Diffstat (limited to 'indra/newview')
207 files changed, 10934 insertions, 17469 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 536c7740bb..07c0cb795e 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -123,8 +123,6 @@ set(viewer_SOURCE_FILES llappearancemgr.cpp llappviewer.cpp llappviewerlistener.cpp - llassetuploadqueue.cpp - llassetuploadresponders.cpp llattachmentsmgr.cpp llaudiosourcevo.cpp llautoreplace.cpp @@ -140,10 +138,7 @@ set(viewer_SOURCE_FILES llbreadcrumbview.cpp llbrowsernotification.cpp llbuycurrencyhtml.cpp - llcallbacklist.cpp llcallingcard.cpp - llcapabilitylistener.cpp - llcaphttpsender.cpp llchannelmanager.cpp llchatbar.cpp llchathistory.cpp @@ -152,7 +147,6 @@ set(viewer_SOURCE_FILES llchiclet.cpp llchicletbar.cpp llclassifiedinfo.cpp - llclassifiedstatsresponder.cpp llcofwearables.cpp llcolorswatch.cpp llcommanddispatcherlistener.cpp @@ -197,7 +191,6 @@ set(viewer_SOURCE_FILES lleventnotifier.cpp lleventpoll.cpp llexpandabletextbox.cpp - llexperienceassociationresponder.cpp llexperiencelog.cpp llexternaleditor.cpp llface.cpp @@ -234,7 +227,6 @@ set(viewer_SOURCE_FILES llfloaterconversationpreview.cpp llfloaterdeleteenvpreset.cpp llfloaterdestinations.cpp - llfloaterdisplayname.cpp llfloatereditdaycycle.cpp llfloatereditsky.cpp llfloatereditwater.cpp @@ -277,7 +269,6 @@ set(viewer_SOURCE_FILES llfloaternotificationsconsole.cpp llfloaterobjectweights.cpp llfloateropenobject.cpp - llfloateroutbox.cpp llfloaterpathfindingcharacters.cpp llfloaterpathfindingconsole.cpp llfloaterpathfindinglinksets.cpp @@ -334,7 +325,6 @@ set(viewer_SOURCE_FILES llgroupmgr.cpp llhasheduniqueid.cpp llhints.cpp - llhomelocationresponder.cpp llhttpretrypolicy.cpp llhudeffect.cpp llhudeffectbeam.cpp @@ -569,7 +559,6 @@ set(viewer_SOURCE_FILES lltextureinfo.cpp lltextureinfodetails.cpp lltexturestats.cpp - lltexturestatsuploader.cpp lltextureview.cpp lltoast.cpp lltoastalertpanel.cpp @@ -605,7 +594,6 @@ set(viewer_SOURCE_FILES lltwitterconnect.cpp lluilistener.cpp lluploaddialog.cpp - lluploadfloaterobservers.cpp llurl.cpp llurldispatcher.cpp llurldispatcherlistener.cpp @@ -618,6 +606,7 @@ set(viewer_SOURCE_FILES llviewerassetstats.cpp llviewerassetstorage.cpp llviewerassettype.cpp + llviewerassetupload.cpp llviewerattachmenu.cpp llvieweraudio.cpp llviewercamera.cpp @@ -625,7 +614,6 @@ set(viewer_SOURCE_FILES llviewercontrol.cpp llviewercontrollistener.cpp llviewerdisplay.cpp - llviewerdisplayname.cpp llviewerfloaterreg.cpp llviewerfoldertype.cpp llviewergenericmessage.cpp @@ -740,8 +728,6 @@ set(viewer_HEADER_FILES llappearancemgr.h llappviewer.h llappviewerlistener.h - llassetuploadqueue.h - llassetuploadresponders.h llattachmentsmgr.h llaudiosourcevo.h llautoreplace.h @@ -756,11 +742,8 @@ set(viewer_HEADER_FILES llbox.h llbreadcrumbview.h llbuycurrencyhtml.h - llcallbacklist.h llcallingcard.h - llcapabilitylistener.h llcapabilityprovider.h - llcaphttpsender.h llchannelmanager.h llchatbar.h llchathistory.h @@ -769,7 +752,6 @@ set(viewer_HEADER_FILES llchiclet.h llchicletbar.h llclassifiedinfo.h - llclassifiedstatsresponder.h llcofwearables.h llcolorswatch.h llcommanddispatcherlistener.h @@ -814,7 +796,6 @@ set(viewer_HEADER_FILES lleventnotifier.h lleventpoll.h llexpandabletextbox.h - llexperienceassociationresponder.h llexperiencelog.h llexternaleditor.h llface.h @@ -851,7 +832,6 @@ set(viewer_HEADER_FILES llfloaterconversationpreview.h llfloaterdeleteenvpreset.h llfloaterdestinations.h - llfloaterdisplayname.h llfloatereditdaycycle.h llfloatereditsky.h llfloatereditwater.h @@ -897,7 +877,6 @@ set(viewer_HEADER_FILES llfloaternotificationsconsole.h llfloaterobjectweights.h llfloateropenobject.h - llfloateroutbox.h llfloaterpathfindingcharacters.h llfloaterpathfindingconsole.h llfloaterpathfindinglinksets.h @@ -954,7 +933,6 @@ set(viewer_HEADER_FILES llhasheduniqueid.h llhints.h llhttpretrypolicy.h - llhomelocationresponder.h llhudeffect.h llhudeffectbeam.h llhudeffectlookat.h @@ -1177,7 +1155,6 @@ set(viewer_HEADER_FILES lltextureinfo.h lltextureinfodetails.h lltexturestats.h - lltexturestatsuploader.h lltextureview.h lltoast.h lltoastalertpanel.h @@ -1227,6 +1204,7 @@ set(viewer_HEADER_FILES llviewerassetstats.h llviewerassetstorage.h llviewerassettype.h + llviewerassetupload.h llviewerattachmenu.h llvieweraudio.h llviewercamera.h @@ -1234,7 +1212,6 @@ set(viewer_HEADER_FILES llviewercontrol.h llviewercontrollistener.h llviewerdisplay.h - llviewerdisplayname.h llviewerfloaterreg.h llviewerfoldertype.h llviewergenericmessage.h @@ -1985,8 +1962,8 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} - ${BOOST_CONTEXT_LIBRARY} ${BOOST_COROUTINE_LIBRARY} + ${BOOST_CONTEXT_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} # must come after LLAudio @@ -2240,10 +2217,9 @@ if (LL_TESTS) SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp lldateutil.cpp - llmediadataclient.cpp +# llmediadataclient.cpp lllogininstance.cpp - llremoteparcelrequest.cpp - lltranslate.cpp +# llremoteparcelrequest.cpp llviewerhelputil.cpp llversioninfo.cpp llworldmap.cpp @@ -2265,15 +2241,9 @@ if (LL_TESTS) ) set_source_files_properties( - lltranslate.cpp - PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" - ) - - set_source_files_properties( llmediadataclient.cpp PROPERTIES - LL_TEST_ADDITIONAL_LIBRARIES "${CURL_LIBRARIES}" + LL_TEST_ADDITIONAL_LIBRARIES "${test_libs}" ) set_source_files_properties( @@ -2329,7 +2299,6 @@ if (LL_TESTS) LL_ADD_PROJECT_UNIT_TESTS(${VIEWER_BINARY_NAME} "${viewer_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) - set(test_sources llcapabilitylistener.cpp) ################################################## # DISABLING PRECOMPILED HEADERS USAGE FOR TESTS ################################################## @@ -2345,26 +2314,29 @@ if (LL_TESTS) ${GOOGLEMOCK_LIBRARIES} ) - LL_ADD_INTEGRATION_TEST(llcapabilitylistener - "${test_sources}" - "${test_libs}" - ${PYTHON_EXECUTABLE} - "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py" - ) + if (LINUX) + # llcommon uses `clock_gettime' which is provided by librt on linux. + set(LIBRT_LIBRARY + rt + ) + endif (LINUX) set(test_libs - ${LLMESSAGE_LIBRARIES} - ${LLCOREHTTP_LIBRARIES} ${WINDOWS_LIBRARIES} ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOREHTTP_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} + ${LIBRT_LIBRARY} + ${BOOST_COROUTINE_LIBRARY} + ${BOOST_CONTEXT_LIBRARY} ) - LL_ADD_INTEGRATION_TEST(llsechandler_basic + LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" ) @@ -2395,13 +2367,12 @@ if (LL_TESTS) "${test_libs}" ) - LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") +# LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") #ADD_VIEWER_BUILD_TEST(llmemoryview viewer) #ADD_VIEWER_BUILD_TEST(llagentaccess viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer) - #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer) include(LLAddBuildTest) SET(viewer_TEST_SOURCE_FILES diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index ff313b8c21..0cbfaed0d9 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -3.8.4 +3.8.5 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0371a819dd..81da856d7e 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2,6 +2,39 @@ <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> <map> + <key>ImporterDebug</key> + <map> + <key>Comment</key> + <string>Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ImporterLegacyMatching</key> + <map> + <key>Comment</key> + <string>Enable index based model matching.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ImporterModelLimit</key> + <map> + <key>Comment</key> + <string>Limits amount of importer generated models for dae files</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>768</integer> + </map> <key>IMShowTime</key> <map> <key>Comment</key> @@ -2370,6 +2403,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>DebugSlshareLogTag</key> + <map> + <key>Comment</key> + <string>Request slshare-service debug logging</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string/> + </map> <key>DebugStatModeFPS</key> <map> <key>Comment</key> @@ -14384,6 +14428,24 @@ <key>Value</key> <integer>1</integer> </map> + <key>PoolSizeAIS</key> + <map> + <key>Comment</key> + <string>Coroutine Pool size for AIS</string> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>25</integer> + </map> + <key>PoolSizeUpload</key> + <map> + <key>Comment</key> + <string>Coroutine Pool size for Upload</string> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <real>1</real> + </map> <!-- Settings below are for back compatibility only. They are not used in current viewer anymore. But they can't be removed to avoid diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index a42286a9e4..92a5413adb 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -27,90 +27,145 @@ #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" +#include <algorithm> +#include <iterator> + //=============================================================================== LLAccountingCostManager::LLAccountingCostManager() { + } -//=============================================================================== -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(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(); - } - } + LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName() + << " with url '" << url << LL_ENDL; - 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(); - - 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; - - physicsCost = content["selected"]["physics"].asReal(); - networkCost = content["selected"]["streaming"].asReal(); - simulationCost = content["selected"]["simulation"].asReal(); - - SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost ); - - LLAccountingCostObserver* observer = mObserverHandle.get(); - if (observer && observer->getTransactionID() == mTransactionID) - { - observer->onWeightsUpdate(selectionCost); - } - } - - clearPendingRequests(); - } - -private: - //List of posted objects - LLSD mObjectIDs; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AccountingCost", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + try + { + uuid_set_t diffSet; + + std::set_difference(mObjectList.begin(), mObjectList.end(), + mPendingObjectQuota.begin(), mPendingObjectQuota.end(), + std::inserter(diffSet, diffSet.begin())); + + if (diffSet.empty()) + return; + + mObjectList.clear(); + + std::string keystr; + if (selectionType == Roots) + { + keystr = "selected_roots"; + } + else if (selectionType == Prims) + { + keystr = "selected_prims"; + } + else + { + LL_INFOS() << "Invalid selection type " << LL_ENDL; + return; + } + + LLSD objectList(LLSD::emptyMap()); + + for (uuid_set_t::iterator it = diffSet.begin(); it != diffSet.end(); ++it) + { + objectList.append(*it); + } + + mPendingObjectQuota.insert(diffSet.begin(), diffSet.end()); + + LLSD dataToPost = LLSD::emptyMap(); + dataToPost[keystr.c_str()] = objectList; - // Current request ID - LLUUID mTransactionID; + LLAccountingCostObserver* observer = observerHandle.get(); + LLUUID transactionId = observer->getTransactionID(); + observer = NULL; + + + + LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost); + + LLSD httpResults = results["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + // do/while(false) allows error conditions to break out of following + // block while normal flow goes forward once. + do + { + observer = observerHandle.get(); + + if (!status || results.has("error")) + { + LL_WARNS() << "Error on fetched data" << LL_ENDL; + if (!status) + observer->setErrorStatus(status.getType(), status.toString()); + else + observer->setErrorStatus(499, "Error on fetched data"); + + 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.has("selected")) + { + LLSD selected = results["selected"]; + + F32 physicsCost = 0.0f; + F32 networkCost = 0.0f; + F32 simulationCost = 0.0f; + + physicsCost = selected["physics"].asReal(); + networkCost = selected["streaming"].asReal(); + simulationCost = 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 +174,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; - - LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle )); - } + 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 { diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 3ade34c81d..f251ceffd4 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -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 @@ -64,11 +71,13 @@ public: private: //Set of objects that will be used to generate a cost - std::set<LLUUID> mObjectList; + uuid_set_t mObjectList; //During fetchCosts we move object into a the pending set to signify that //a fetch has been instigated. - std::set<LLUUID> mPendingObjectQuota; - typedef std::set<LLUUID>::iterator IDIt; + uuid_set_t mPendingObjectQuota; + + void accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle); + }; //=============================================================================== diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 092d868bb9..3316f1e654 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -38,7 +38,6 @@ #include "llappearancemgr.h" #include "llanimationstates.h" #include "llcallingcard.h" -#include "llcapabilitylistener.h" #include "llchannelmanager.h" #include "llchicletbar.h" #include "llconsole.h" @@ -52,7 +51,6 @@ #include "llfloatertools.h" #include "llgroupactions.h" #include "llgroupmgr.h" -#include "llhomelocationresponder.h" #include "llhudmanager.h" #include "lljoystickbutton.h" #include "llmorphview.h" @@ -63,7 +61,6 @@ #include "llpaneltopinfobar.h" #include "llparcel.h" #include "llrendersphere.h" -#include "llsdmessage.h" #include "llsdutil.h" #include "llsky.h" #include "llslurl.h" @@ -95,6 +92,7 @@ #include "lscript_byteformat.h" #include "stringize.h" #include "boost/foreach.hpp" +#include "llcorehttputil.h" using namespace LLAvatarAppearanceDefines; @@ -361,7 +359,8 @@ LLAgent::LLAgent() : mMaturityPreferenceNumRetries(0U), mLastKnownRequestMaturity(SIM_ACCESS_MIN), mLastKnownResponseMaturity(SIM_ACCESS_MIN), - mTeleportState( TELEPORT_NONE ), + mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mTeleportState(TELEPORT_NONE), mRegionp(NULL), mAgentOriginGlobal(), @@ -461,6 +460,10 @@ void LLAgent::init() mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this)); } + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT); + mInitialized = TRUE; } @@ -927,7 +930,7 @@ LLHost LLAgent::getRegionHost() const } else { - return LLHost::invalid; + return LLHost(); } } @@ -950,6 +953,15 @@ BOOL LLAgent::inPrelude() } +std::string LLAgent::getRegionCapability(const std::string &name) +{ + if (!mRegionp) + return std::string(); + + return mRegionp->getCapability(name); +} + + //----------------------------------------------------------------------------- // canManageEstate() //----------------------------------------------------------------------------- @@ -2326,27 +2338,9 @@ void LLAgent::setStartPosition( U32 location_id ) body["HomeLocation"] = homeLocation; - // This awkward idiom warrants explanation. - // For starters, LLSDMessage::ResponderAdapter is ONLY for testing the new - // LLSDMessage functionality with a pre-existing LLHTTPClient::Responder. - // In new code, define your reply/error methods on the same class as the - // sending method, bind them to local LLEventPump objects and pass those - // LLEventPump names in the request LLSD object. - // When testing old code, the new LLHomeLocationResponder object - // is referenced by an LLHTTPClient::ResponderPtr, so when the - // ResponderAdapter is deleted, the LLHomeLocationResponder will be too. - // We must trust that the underlying LLHTTPClient code will eventually - // fire either the reply callback or the error callback; either will cause - // the ResponderAdapter to delete itself. - LLSDMessage::ResponderAdapter* - adapter(new LLSDMessage::ResponderAdapter(new LLHomeLocationResponder())); - - request["message"] = "HomeLocation"; - request["payload"] = body; - request["reply"] = adapter->getReplyName(); - request["error"] = adapter->getErrorName(); - - gAgent.getRegion()->getCapAPI().post(request); + if (!requestPostCapability("HomeLocation", body, + boost::bind(&LLAgent::setStartPositionSuccess, this, _1))) + LL_WARNS() << "Unable to post to HomeLocation capability." << LL_ENDL; const U32 HOME_INDEX = 1; if( HOME_INDEX == location_id ) @@ -2355,32 +2349,51 @@ void LLAgent::setStartPosition( U32 location_id ) } } -struct HomeLocationMapper: public LLCapabilityListener::CapabilityMapper +void LLAgent::setStartPositionSuccess(const LLSD &result) { - // No reply message expected - HomeLocationMapper(): LLCapabilityListener::CapabilityMapper("HomeLocation") {} - virtual void buildMessage(LLMessageSystem* msg, - const LLUUID& agentID, - const LLUUID& sessionID, - const std::string& capabilityName, - const LLSD& payload) const + LLVector3 agent_pos; + bool error = true; + + do { + // was the call to /agent/<agent-id>/home-location successful? + // If not, we keep error set to true + if (!result.has("success")) + break; + + if (0 != strncmp("true", result["success"].asString().c_str(), 4)) + break; + + // did the simulator return a "justified" home location? + // If no, we keep error set to true + if (!result.has("HomeLocation")) + break; + + if ((!result["HomeLocation"].has("LocationPos")) || + (!result["HomeLocation"]["LocationPos"].has("X")) || + (!result["HomeLocation"]["LocationPos"].has("Y")) || + (!result["HomeLocation"]["LocationPos"].has("Z"))) + break; + + agent_pos.mV[VX] = result["HomeLocation"]["LocationPos"]["X"].asInteger(); + agent_pos.mV[VY] = result["HomeLocation"]["LocationPos"]["Y"].asInteger(); + agent_pos.mV[VZ] = result["HomeLocation"]["LocationPos"]["Z"].asInteger(); + + error = false; + + } while (0); + + if (error) { - msg->newMessageFast(_PREHASH_SetStartLocationRequest); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, agentID); - msg->addUUIDFast(_PREHASH_SessionID, sessionID); - msg->nextBlockFast( _PREHASH_StartLocationData); - // corrected by sim - msg->addStringFast(_PREHASH_SimName, ""); - msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger()); - msg->addVector3Fast(_PREHASH_LocationPos, - ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"])); - msg->addVector3Fast(_PREHASH_LocationLookAt, - ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"])); + LL_WARNS() << "Error in response to home position set." << LL_ENDL; } -}; -// Need an instance of this class so it will self-register -static HomeLocationMapper homeLocationMapper; + else + { + LL_INFOS() << "setting home position" << LL_ENDL; + + LLViewerRegion *viewer_region = gAgent.getRegion(); + setHomePosRegion(viewer_region->getHandle(), agent_pos); + } +} void LLAgent::requestStopMotion( LLMotion* motion ) { @@ -2517,87 +2530,6 @@ int LLAgent::convertTextToMaturity(char text) return LLAgentAccess::convertTextToMaturity(text); } -class LLMaturityPreferencesResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLMaturityPreferencesResponder); -public: - LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); - virtual ~LLMaturityPreferencesResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -protected: - -private: - U8 parseMaturityFromServerResponse(const LLSD &pContent) const; - - LLAgent *mAgent; - U8 mPreferredMaturity; - U8 mPreviousMaturity; -}; - -LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) - : LLHTTPClient::Responder(), - mAgent(pAgent), - mPreferredMaturity(pPreferredMaturity), - mPreviousMaturity(pPreviousMaturity) -{ -} - -LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() -{ -} - -void LLMaturityPreferencesResponder::httpSuccess() -{ - U8 actualMaturity = parseMaturityFromServerResponse(getContent()); - - if (actualMaturity != mPreferredMaturity) - { - LL_WARNS() << "while attempting to change maturity preference from '" - << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) - << "', the server responded with '" - << LLViewerRegion::accessToString(actualMaturity) - << "' [value:" << static_cast<U32>(actualMaturity) - << "], " << dumpResponse() << LL_ENDL; - } - mAgent->handlePreferredMaturityResult(actualMaturity); -} - -void LLMaturityPreferencesResponder::httpFailure() -{ - LL_WARNS() << "while attempting to change maturity preference from '" - << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) - << "', " << dumpResponse() << LL_ENDL; - mAgent->handlePreferredMaturityError(); -} - -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const -{ - U8 maturity = SIM_ACCESS_MIN; - - llassert(pContent.isDefined()); - llassert(pContent.isMap()); - llassert(pContent.has("access_prefs")); - llassert(pContent.get("access_prefs").isMap()); - llassert(pContent.get("access_prefs").has("max")); - llassert(pContent.get("access_prefs").get("max").isString()); - if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs") - && pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") - && pContent.get("access_prefs").get("max").isString()) - { - LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString(); - LLStringUtil::trim(actualPreference); - maturity = LLViewerRegion::shortStringToAccess(actualPreference); - } - - return maturity; -} - void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity) { // Update the number of responses received @@ -2726,42 +2658,96 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // Update the last know maturity request mLastKnownRequestMaturity = pPreferredMaturity; - // Create a response handler - LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); - // If we don't have a region, report it as an error if (getRegion() == NULL) { - responderPtr->failureResult(0U, "region is not defined", LLSD()); + LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL; + return; } - else - { - // Find the capability to send maturity preference - std::string url = getRegion()->getCapability("UpdateAgentInformation"); - // If the capability is not defined, report it as an error - if (url.empty()) - { - responderPtr->failureResult(0U, - "capability 'UpdateAgentInformation' is not defined for region", LLSD()); - } - else - { - // Set new access preference - LLSD access_prefs = LLSD::emptyMap(); - access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); - - LLSD body = LLSD::emptyMap(); - body["access_prefs"] = access_prefs; - LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) - << "' via capability to: " << url << LL_ENDL; - LLSD headers; - LLHTTPClient::post(url, body, responderPtr, headers, 30.0f); - } - } + LLSD access_prefs = LLSD::emptyMap(); + access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); + + LLSD postData = LLSD::emptyMap(); + postData["access_prefs"] = access_prefs; + LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) << LL_ENDL; + + if (!requestPostCapability("UpdateAgentInformation", postData, + static_cast<httpCallback_t>(boost::bind(&LLAgent::processMaturityPreferenceFromServer, this, _1, pPreferredMaturity)), + static_cast<httpCallback_t>(boost::bind(&LLAgent::handlePreferredMaturityError, this)) + )) + { + LL_WARNS("Agent") << "Maturity request post failed." << LL_ENDL; + } } } + +void LLAgent::processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity) +{ + U8 maturity = SIM_ACCESS_MIN; + + llassert(result.isDefined()); + llassert(result.isMap()); + llassert(result.has("access_prefs")); + llassert(result.get("access_prefs").isMap()); + llassert(result.get("access_prefs").has("max")); + llassert(result.get("access_prefs").get("max").isString()); + if (result.isDefined() && result.isMap() && result.has("access_prefs") + && result.get("access_prefs").isMap() && result.get("access_prefs").has("max") + && result.get("access_prefs").get("max").isString()) + { + LLSD::String actualPreference = result.get("access_prefs").get("max").asString(); + LLStringUtil::trim(actualPreference); + maturity = LLViewerRegion::shortStringToAccess(actualPreference); + } + + if (maturity != perferredMaturity) + { + LL_WARNS() << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mLastKnownResponseMaturity) + << "' to '" << LLViewerRegion::accessToString(perferredMaturity) + << "', the server responded with '" + << LLViewerRegion::accessToString(maturity) + << "' [value:" << static_cast<U32>(maturity) + << "], " << LL_ENDL; + } + handlePreferredMaturityResult(maturity); +} + + +bool LLAgent::requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getRegion()->getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, mHttpPolicy, postData, cbSuccess, cbFailure); + return true; +} + +bool LLAgent::requestGetCapability(const std::string &capName, httpCallback_t cbSuccess, httpCallback_t cbFailure) +{ + std::string url; + + url = getRegion()->getCapability(capName); + + if (url.empty()) + { + LL_WARNS("Agent") << "Could not retrieve region capability \"" << capName << "\"" << LL_ENDL; + return false; + } + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(url, mHttpPolicy, cbSuccess, cbFailure); + return true; +} + BOOL LLAgent::getAdminOverride() const { return mAgentAccess->getAdminOverride(); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 4830cb754b..5731f4db89 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -34,7 +34,9 @@ #include "llcoordframe.h" // for mFrameAgent #include "llavatarappearancedefines.h" #include "llpermissionsflags.h" +#include "llevents.h" #include "v3dmath.h" +#include "llcorehttputil.h" #include <boost/function.hpp> #include <boost/shared_ptr.hpp> @@ -61,6 +63,8 @@ class LLPauseRequestHandle; class LLUIColor; class LLTeleportRequest; + + typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr; //-------------------------------------------------------------------- @@ -112,6 +116,8 @@ public: void init(); void cleanup(); +private: + //-------------------------------------------------------------------- // Login //-------------------------------------------------------------------- @@ -227,6 +233,8 @@ public: void setHomePosRegion(const U64& region_handle, const LLVector3& pos_region); BOOL getHomePosGlobal(LLVector3d* pos_global); private: + void setStartPositionSuccess(const LLSD &result); + BOOL mHaveHomePosition; U64 mHomeRegionHandle; LLVector3 mHomePosRegion; @@ -254,6 +262,9 @@ public: LLHost getRegionHost() const; BOOL inPrelude(); + // Capability + std::string getRegionCapability(const std::string &name); // short hand for if (getRegion()) { getRegion()->getCapability(name) } + /** * Register a boost callback to be called when the agent changes regions * Note that if you need to access a capability for the region, you may need to wait @@ -631,6 +642,8 @@ public: void setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange); private: + + friend class LLTeleportRequest; friend class LLTeleportRequestViaLandmark; friend class LLTeleportRequestViaLure; @@ -758,11 +771,12 @@ private: unsigned int mMaturityPreferenceNumRetries; U8 mLastKnownRequestMaturity; U8 mLastKnownResponseMaturity; + LLCore::HttpRequest::policy_t mHttpPolicy; bool isMaturityPreferenceSyncedWithServer() const; void sendMaturityPreferenceToServer(U8 pPreferredMaturity); + void processMaturityPreferenceFromServer(const LLSD &result, U8 perferredMaturity); - friend class LLMaturityPreferencesResponder; void handlePreferredMaturityResult(U8 pServerMaturity); void handlePreferredMaturityError(); void reportPreferredMaturitySuccess(); @@ -911,6 +925,22 @@ public: /******************************************************************************** ** ** + ** UTILITY + **/ +public: + typedef LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t httpCallback_t; + + /// Utilities for allowing the the agent sub managers to post and get via + /// HTTP using the agent's policy settings and headers. + bool requestPostCapability(const std::string &capName, LLSD &postData, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); + bool requestGetCapability(const std::string &capName, httpCallback_t cbSuccess = NULL, httpCallback_t cbFailure = NULL); + +/** Utility + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** ** DEBUGGING **/ diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp index fe6236a32a..cdb0e3302d 100755 --- a/indra/newview/llagentlanguage.cpp +++ b/indra/newview/llagentlanguage.cpp @@ -32,6 +32,7 @@ #include "llviewerregion.h" // library includes #include "llui.h" // getLanguage() +#include "httpcommon.h" // static void LLAgentLanguage::init() @@ -54,22 +55,17 @@ void LLAgentLanguage::onChange() // static bool LLAgentLanguage::update() { - LLSD body; - std::string url; + LLSD body; - if (gAgent.getRegion()) - { - url = gAgent.getRegion()->getCapability("UpdateAgentLanguage"); - } - - if (!url.empty()) - { - std::string language = LLUI::getLanguage(); + std::string language = LLUI::getLanguage(); - body["language"] = language; - body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); + body["language"] = language; + body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); - LLHTTPClient::post(url, body, new LLHTTPClient::Responder); - } + if (!gAgent.requestPostCapability("UpdateAgentLanguage", body)) + { + LL_WARNS("Language") << "Language capability unavailable." << LL_ENDL; + } + return true; } diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 714b456ae7..afc6e208e6 100755 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -40,317 +40,381 @@ /// Classes for AISv3 support. ///---------------------------------------------------------------------------- -// AISCommand - base class for retry-able HTTP requests using the AISv3 cap. -AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback): - mCommandFunc(NULL), - mCallback(callback) -{ - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); -} +//========================================================================= +const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3"); +const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3"); + +//------------------------------------------------------------------------- +/*static*/ +bool AISAPI::isAvailable() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->isCapabilityAvailable(INVENTORY_CAP_NAME); + } + return false; +} + +/*static*/ +void AISAPI::getCapNames(LLSD& capNames) +{ + capNames.append(INVENTORY_CAP_NAME); + capNames.append(LIBRARY_CAP_NAME); +} -bool AISCommand::run_command() -{ - if (NULL == mCommandFunc) - { - // This may happen if a command failed to initiate itself. - LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL; - return false; - } - else - { - mCommandFunc(); - return true; - } -} +/*static*/ +std::string AISAPI::getInvCap() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->getCapability(INVENTORY_CAP_NAME); + } + return std::string(); +} + +/*static*/ +std::string AISAPI::getLibCap() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->getCapability(LIBRARY_CAP_NAME); + } + return std::string(); +} + +/*static*/ +void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback) +{ + std::string cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + LLUUID tid; + tid.generate(); -void AISCommand::setCommandFunc(command_func_type command_func) + std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + // I may be suffering from golden hammer here, but the first part of this bind + // is actually a static cast for &HttpCoroutineAdapter::postAndSuspend so that + // the compiler can identify the correct signature to select. + // + // Reads as follows: + // LLSD - method returning LLSD + // (LLCoreHttpUtil::HttpCoroutineAdapter::*) - pointer to member function of HttpCoroutineAdapter + // (LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) - signature of method + // + invokationFn_t postFn = boost::bind( + // Humans ignore next line. It is just a cast. + static_cast<LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, _4, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY)); + EnqueueAISCommand("CreateInventory", proc); +} + +/*static*/ +void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback) { - mCommandFunc = command_func; -} - -// virtual -bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id) -{ - return false; -} - -/* virtual */ -void AISCommand::httpSuccess() -{ - // Command func holds a reference to self, need to release it - // after a success or final failure. - setCommandFunc(no_op); - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - mRetryPolicy->onSuccess(); - - gInventory.onAISUpdateReceived("AISCommand", content); + std::string cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + LLUUID tid; + tid.generate(); + + std::string url = cap + std::string("/category/") + folderId.asString() + "/links?tid=" + tid.asString(); - if (mCallback) - { - LLUUID id; // will default to null if parse fails. - getResponseUUID(content,id); - mCallback->fire(id); - } -} + // see comment above in CreateInventoryCommand + invokationFn_t putFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndSuspend), _1, _2, _3, _4, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, putFn, url, folderId, newInventory, callback, SLAMFOLDER)); + + EnqueueAISCommand("SlamFolder", proc); +} + +void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + std::string url = cap + std::string("/category/") + categoryId.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + invokationFn_t delFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, delFn, url, categoryId, LLSD(), callback, REMOVECATEGORY)); + + EnqueueAISCommand("RemoveCategory", proc); +} + +/*static*/ +void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + std::string url = cap + std::string("/item/") + itemId.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + invokationFn_t delFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, delFn, url, itemId, LLSD(), callback, REMOVEITEM)); + + EnqueueAISCommand("RemoveItem", proc); +} + +void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback) +{ + std::string cap; + + cap = getLibCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL; + return; + } -/*virtual*/ -void AISCommand::httpFailure() -{ - LL_WARNS("Inventory") << dumpResponse() << LL_ENDL; - S32 status = getStatus(); - const LLSD& headers = getResponseHeaders(); - mRetryPolicy->onFailure(status, headers); - F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(seconds_to_wait)) - { - doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait); - } - else - { - // Command func holds a reference to self, need to release it - // after a success or final failure. - // *TODO: Notify user? This seems bad. - setCommandFunc(no_op); - } -} + LL_DEBUGS("Inventory") << "Copying library category: " << sourceId << " => " << destId << LL_ENDL; -//static -bool AISCommand::isAPIAvailable() -{ - if (gAgent.getRegion()) - { - return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3"); - } - return false; -} + LLUUID tid; + tid.generate(); -//static -bool AISCommand::getInvCap(std::string& cap) -{ - if (gAgent.getRegion()) - { - cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); - } - if (!cap.empty()) - { - return true; - } - return false; -} + std::string url = cap + std::string("/category/") + sourceId.asString() + "?tid=" + tid.asString(); + if (!copySubfolders) + { + url += ",depth=0"; + } + LL_INFOS() << url << LL_ENDL; -//static -bool AISCommand::getLibCap(std::string& cap) -{ - if (gAgent.getRegion()) - { - cap = gAgent.getRegion()->getCapability("LibraryAPIv3"); - } - if (!cap.empty()) - { - return true; - } - return false; -} + std::string destination = destId.asString(); -//static -void AISCommand::getCapabilityNames(LLSD& capabilityNames) + invokationFn_t copyFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const std::string, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::copyAndSuspend), _1, _2, _3, destination, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, copyFn, url, destId, LLSD(), callback, COPYLIBRARYCATEGORY)); + + EnqueueAISCommand("CopyLibraryCategory", proc); +} + +/*static*/ +void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback) { - capabilityNames.append("InventoryAPIv3"); - capabilityNames.append("LibraryAPIv3"); -} + std::string cap; -RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback): - AISCommand(callback) -{ - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - std::string url = cap + std::string("/item/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LLHTTPClient::ResponderPtr responder = this; - LLSD headers; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); - setCommandFunc(cmd); -} + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } -RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback): - AISCommand(callback) -{ - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - std::string url = cap + std::string("/category/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LLHTTPClient::ResponderPtr responder = this; - LLSD headers; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); - setCommandFunc(cmd); -} + std::string url = cap + std::string("/category/") + categoryId.asString() + "/children"; + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; -PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback): - AISCommand(callback) -{ - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout); - setCommandFunc(cmd); -} + invokationFn_t delFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndSuspend), _1, _2, _3, _5, _6); -UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id, - const LLSD& updates, - LLPointer<LLInventoryCallback> callback): - mUpdates(updates), - AISCommand(callback) -{ - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - std::string url = cap + std::string("/item/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - headers["Content-Type"] = "application/llsd+xml"; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); - setCommandFunc(cmd); + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, delFn, url, categoryId, LLSD(), callback, PURGEDESCENDENTS)); + + EnqueueAISCommand("PurgeDescendents", proc); } -UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id, - const LLSD& updates, - LLPointer<LLInventoryCallback> callback): - mUpdates(updates), - AISCommand(callback) -{ - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - std::string url = cap + std::string("/category/") + cat_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - headers["Content-Type"] = "application/llsd+xml"; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout); - setCommandFunc(cmd); -} -CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id, - const LLSD& new_inventory, - LLPointer<LLInventoryCallback> callback): - mNewInventory(new_inventory), - AISCommand(callback) +/*static*/ +void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback) { - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - LLUUID tid; - tid.generate(); - std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString(); - LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - headers["Content-Type"] = "application/llsd+xml"; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout); - setCommandFunc(cmd); + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + categoryId.asString(); + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, categoryId, updates, callback, UPDATECATEGORY)); + + EnqueueAISCommand("UpdateCategory", proc); } -SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback): - mContents(contents), - AISCommand(callback) +/*static*/ +void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback) { - std::string cap; - if (!getInvCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - LLUUID tid; - tid.generate(); - std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); - LL_INFOS() << url << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - headers["Content-Type"] = "application/llsd+xml"; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout); - setCommandFunc(cmd); + + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/item/") + itemId.asString(); + + invokationFn_t patchFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> body + // _5 -> httpOptions + // _6 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndSuspend), _1, _2, _3, _4, _5, _6); + + LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, + _1, patchFn, url, itemId, updates, callback, UPDATEITEM)); + + EnqueueAISCommand("UpdateItem", proc); } -CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id, - const LLUUID& dest_id, - LLPointer<LLInventoryCallback> callback, - bool copy_subfolders): - AISCommand(callback) +/*static*/ +void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc) { - std::string cap; - if (!getLibCap(cap)) - { - LL_WARNS() << "No cap found" << LL_ENDL; - return; - } - LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL; - LLUUID tid; - tid.generate(); - std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString(); - if (!copy_subfolders) - { - url += ",depth=0"; - } - LL_INFOS() << url << LL_ENDL; - LLCurl::ResponderPtr responder = this; - LLSD headers; - F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout); - setCommandFunc(cmd); + std::string procFullName = "AIS(" + procName + ")"; + LLCoprocedureManager::instance().enqueueCoprocedure("AIS", procFullName, proc); + } -bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id) +/*static*/ +void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, + invokationFn_t invoke, std::string url, + LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type) { - if (content.has("category_id")) - { - id = content["category_id"]; - return true; - } - return false; + LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest()); + LLCore::HttpHeaders::ptr_t httpHeaders; + + httpOptions->setTimeout(LLCoreHttpUtil::HTTP_REQUEST_EXPIRY_SECS); + + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + LLSD result = invoke(httpAdapter, httpRequest, url, body, httpOptions, httpHeaders); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status || !result.isMap()) + { + if (!result.isMap()) + { + status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents"); + } + LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL; + LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; + } + + gInventory.onAISUpdateReceived("AISCommand", result); + + if (callback && !callback.empty()) + { + LLUUID id(LLUUID::null); + + if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) + { + id = result["category_id"]; + } + + callback(id); + } + } +//------------------------------------------------------------------------- AISUpdate::AISUpdate(const LLSD& update) { parseUpdate(update); diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index bb483fb133..e97059014b 100755 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -31,112 +31,55 @@ #include <map> #include <set> #include <string> -#include "llcurl.h" -#include "llhttpclient.h" #include "llhttpretrypolicy.h" #include "llviewerinventory.h" +#include "llcorehttputil.h" +#include "llcoproceduremanager.h" -class AISCommand: public LLHTTPClient::Responder +class AISAPI { public: - typedef boost::function<void()> command_func_type; + typedef boost::function<void(const LLUUID &invItem)> completion_t; - AISCommand(LLPointer<LLInventoryCallback> callback); + static bool isAvailable(); + static void getCapNames(LLSD& capNames); - virtual ~AISCommand() {} + static void CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback = completion_t()); + static void SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback = completion_t()); + static void RemoveCategory(const LLUUID &categoryId, completion_t callback = completion_t()); + static void RemoveItem(const LLUUID &itemId, completion_t callback = completion_t()); + static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t()); + static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t()); + static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t()); + static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t()); - bool run_command(); - - void setCommandFunc(command_func_type command_func); - - // Need to do command-specific parsing to get an id here, for - // LLInventoryCallback::fire(). May or may not need to bother, - // since most LLInventoryCallbacks do their work in the - // destructor. - - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - - static bool isAPIAvailable(); - static bool getInvCap(std::string& cap); - static bool getLibCap(std::string& cap); - static void getCapabilityNames(LLSD& capabilityNames); - -protected: - virtual bool getResponseUUID(const LLSD& content, LLUUID& id); - -private: - command_func_type mCommandFunc; - LLPointer<LLHTTPRetryPolicy> mRetryPolicy; - LLPointer<LLInventoryCallback> mCallback; -}; - -class RemoveItemCommand: public AISCommand -{ -public: - RemoveItemCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback); -}; - -class RemoveCategoryCommand: public AISCommand -{ -public: - RemoveCategoryCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback); -}; - -class PurgeDescendentsCommand: public AISCommand -{ -public: - PurgeDescendentsCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback); -}; - -class UpdateItemCommand: public AISCommand -{ -public: - UpdateItemCommand(const LLUUID& item_id, - const LLSD& updates, - LLPointer<LLInventoryCallback> callback); private: - LLSD mUpdates; -}; + typedef enum { + COPYINVENTORY, + SLAMFOLDER, + REMOVECATEGORY, + REMOVEITEM, + PURGEDESCENDENTS, + UPDATECATEGORY, + UPDATEITEM, + COPYLIBRARYCATEGORY + } COMMAND_TYPE; -class UpdateCategoryCommand: public AISCommand -{ -public: - UpdateCategoryCommand(const LLUUID& cat_id, - const LLSD& updates, - LLPointer<LLInventoryCallback> callback); -private: - LLSD mUpdates; -}; + static const std::string INVENTORY_CAP_NAME; + static const std::string LIBRARY_CAP_NAME; -class SlamFolderCommand: public AISCommand -{ -public: - SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback); - -private: - LLSD mContents; -}; + typedef boost::function < LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t, LLCore::HttpRequest::ptr_t, + const std::string, LLSD, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t; -class CopyLibraryCategoryCommand: public AISCommand -{ -public: - CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback, bool copy_subfolders = true); + static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc); -protected: - /* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id); -}; + static std::string getInvCap(); + static std::string getLibCap(); -class CreateInventoryCommand: public AISCommand -{ -public: - CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback); + static void InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, + invokationFn_t invoke, std::string url, LLUUID targetId, LLSD body, + completion_t callback, COMMAND_TYPE type); -private: - LLSD mNewInventory; }; class AISUpdate diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f5f224b83e..91a5148e4c 100755 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -31,6 +31,10 @@ #include "llappviewer.h" #include "llviewercontrol.h" +#include <openssl/x509_vfy.h> +#include <openssl/ssl.h> +#include "llsecapi.h" +#include <curl/curl.h> // Here is where we begin to get our connection usage under control. // This establishes llcorehttp policy classes that, among other @@ -93,6 +97,16 @@ static const struct 4, 1, 4, 0, false, "", "inventory" + }, + { // AP_MATERIALS + 2, 1, 8, 0, false, + "RenderMaterials", + "material manager requests" + }, + { // AP_AGENT + 2, 1, 32, 0, true, + "Agent", + "Agent requests" } }; @@ -124,6 +138,9 @@ LLAppCoreHttp::~LLAppCoreHttp() void LLAppCoreHttp::init() { + + LLCore::LLHttp::initialize(); + LLCore::HttpStatus status = LLCore::HttpRequest::createService(); if (! status) { @@ -151,6 +168,15 @@ void LLAppCoreHttp::init() << LL_ENDL; } + // Set up SSL Verification call back. + status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_SSL_VERIFY_CALLBACK, + LLCore::HttpRequest::GLOBAL_POLICY_ID, + sslVerify, NULL); + if (!status) + { + LL_WARNS("Init") << "Failed to set SSL Verification. Reason: " << status.toString() << LL_ENDL; + } + // Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy): // 0 - None // 1 - Basic start, stop simple transitions @@ -182,6 +208,8 @@ void LLAppCoreHttp::init() } mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass(); + // We have run out of available HTTP policies. Adjust HTTP_POLICY_CLASS_LIMIT in _httpinternal.h + llassert(mHttpClasses[app_policy].mPolicy != LLCore::HttpRequest::INVALID_POLICY_ID); if (! mHttpClasses[app_policy].mPolicy) { // Use default policy (but don't accidentally modify default) @@ -457,6 +485,62 @@ void LLAppCoreHttp::refreshSettings(bool initial) } } +LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, + LLCore::HttpHandler const * const handler, void *appdata) +{ + X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata); + LLCore::HttpStatus result; + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); + LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); + LLSD validation_params = LLSD::emptyMap(); + LLURI uri(url); + + validation_params[CERT_HOSTNAME] = uri.hostName(); + + // *TODO: In the case of an exception while validating the cert, we need a way + // to pass the offending(?) cert back out. *Rider* + + try + { + // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects + store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); + } + catch (LLCertValidationTrustException &cert_exception) + { + // this exception is is handled differently than the general cert + // exceptions, as we allow the user to actually add the certificate + // for trust. + // therefore we pass back a different error code + // NOTE: We're currently 'wired' to pass around CURL error codes. This is + // somewhat clumsy, as we may run into errors that do not map directly to curl + // error codes. Should be refactored with login refactoring, perhaps. + result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT); + result.setMessage(cert_exception.getMessage()); + LLPointer<LLCertificate> cert = cert_exception.getCert(); + cert->ref(); // adding an extra ref here + result.setErrorData(cert.get()); + // We should probably have a more generic way of passing information + // back to the error handlers. + } + catch (LLCertException &cert_exception) + { + result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE); + result.setMessage(cert_exception.getMessage()); + LLPointer<LLCertificate> cert = cert_exception.getCert(); + cert->ref(); // adding an extra ref here + result.setErrorData(cert.get()); + } + catch (...) + { + // any other odd error, we just handle as a connect error. + result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR); + } + + return result; +} + + + void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *) { diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h index 37d7a737e7..410d7c6b07 100755 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -164,7 +164,29 @@ public: /// Pipelined: no AP_INVENTORY, AP_REPORTING = AP_INVENTORY, // Piggy-back on inventory - + + /// Material resource requests and puts. + /// + /// Destination: simhost:12043 + /// Protocol: https: + /// Transfer size: KB + /// Long poll: no + /// Concurrency: low + /// Request rate: low + /// Pipelined: no + AP_MATERIALS, + + /// Appearance resource requests and puts. + /// + /// Destination: simhost:12043 + /// Protocol: https: + /// Transfer size: KB + /// Long poll: no + /// Concurrency: mid + /// Request rate: low + /// Pipelined: yes + AP_AGENT, + AP_COUNT // Must be last }; @@ -233,7 +255,9 @@ private: bool mStopped; HttpClass mHttpClasses[AP_COUNT]; bool mPipelined; // Global setting - boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting + boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting + + static LLCore::HttpStatus sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata); }; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 35593dd4ff..eea585e998 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -23,7 +23,7 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "llviewerprecompiledheaders.h" #include <boost/lexical_cast.hpp> @@ -54,12 +54,26 @@ #include "llsdserialize.h" #include "llhttpretrypolicy.h" #include "llaisapi.h" +#include "llhttpsdhandler.h" +#include "llcorehttputil.h" +#include "llappviewer.h" #if LL_MSVC // disable boost::lexical_cast warning #pragma warning (disable:4702) #endif +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id) +{ + if (cb.notNull()) + cb->fire(id); +} +#endif + + std::string self_av_string() { // On logout gAgentAvatarp can already be invalid @@ -1257,6 +1271,8 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) items = new_items; } +//========================================================================= + const LLUUID LLAppearanceMgr::getCOF() const { return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -2458,8 +2474,7 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool << " )" << LL_ENDL; // If we are copying from library, attempt to use AIS to copy the category. - bool ais_ran=false; - if (copy && AISCommand::isAPIAvailable()) + if (copy && AISAPI::isAvailable()) { LLUUID parent_id; parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); @@ -2471,11 +2486,11 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append); LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper( std::string("wear_inventory_category_callback"), copy_cb); - LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb, false); - ais_ran=cmd_ptr->run_command(); - } - if (!ais_ran) + AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1); + AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, false, cr); + } + else { selfStartPhase("wear_inventory_category_fetch"); callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, @@ -3267,276 +3282,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, } -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(RequestAgentUpdateAppearanceResponder); - - friend class LLAppearanceMgr; - -public: - RequestAgentUpdateAppearanceResponder(); - - virtual ~RequestAgentUpdateAppearanceResponder(); - -private: - // Called when sendServerAppearanceUpdate called. May or may not - // trigger a request depending on various bits of state. - void onRequestRequested(); - - // Post the actual appearance request to cap. - void sendRequest(); - - void debugCOF(const LLSD& content); - -protected: - // Successful completion. - /* virtual */ void httpSuccess(); - - // Error - /*virtual*/ void httpFailure(); - - void onFailure(); - void onSuccess(); - - S32 mInFlightCounter; - LLTimer mInFlightTimer; - LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() -{ - bool retry_on_4xx = true; - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); - mInFlightCounter = 0; -} - -RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() -{ -} - -void RequestAgentUpdateAppearanceResponder::onRequestRequested() -{ - // If we have already received an update for this or higher cof version, ignore. - S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); - S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; - S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; - LL_DEBUGS("Avatar") << "cof_version " << cof_version - << " last_rcv " << last_rcv - << " last_req " << last_req - << " in flight " << mInFlightCounter << LL_ENDL; - if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) - { - LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; - mInFlightCounter = 0; - } - if (cof_version < last_rcv) - { - LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv - << " will not request for " << cof_version << LL_ENDL; - return; - } - if (mInFlightCounter>0 && last_req >= cof_version) - { - LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req - << " will not request for " << cof_version << LL_ENDL; - return; - } - - // Actually send the request. - LL_DEBUGS("Avatar") << "ATT sending bake request for cof_version " << cof_version << LL_ENDL; - mRetryPolicy->reset(); - sendRequest(); -} - -void RequestAgentUpdateAppearanceResponder::sendRequest() -{ - if (gAgentAvatarp->isEditingAppearance()) - { - // don't send out appearance updates if in appearance editing mode - return; - } - - if (!gAgent.getRegion()) - { - LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; - return; - } - if (gAgent.getRegion()->getCentralBakeVersion()==0) - { - LL_WARNS() << "Region does not support baking" << LL_ENDL; - } - std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance"); - if (url.empty()) - { - LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; - return; - } - - LLSD body; - S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); - if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) - { - body = LLAppearanceMgr::instance().dumpCOF(); - } - else - { - body["cof_version"] = cof_version; - if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) - { - body["cof_version"] = cof_version+999; - } - } - LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - - mInFlightCounter++; - mInFlightTimer.setTimerExpirySec(60.0); - LLHTTPClient::post(url, body, this); - llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); - gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; -} - -void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) -{ - LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() - << " ================================= " << LL_ENDL; - std::set<LLUUID> ais_items, local_items; - const LLSD& cof_raw = content["cof_raw"]; - for (LLSD::array_const_iterator it = cof_raw.beginArray(); - it != cof_raw.endArray(); ++it) - { - const LLSD& item = *it; - if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) - { - ais_items.insert(item["item_id"].asUUID()); - if (item["type"].asInteger() == 24) // link - { - LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << LL_ENDL; - } - else if (item["type"].asInteger() == 25) // folder link - { - LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << LL_ENDL; - } - else - { - LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() - << " linked_item_id: " << item["asset_id"].asUUID() - << " name: " << item["name"].asString() - << " type: " << item["type"].asInteger() - << LL_ENDL; - } - } - } - LL_INFOS("Avatar") << LL_ENDL; - LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() - << " ================================= " << LL_ENDL; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), - cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; i<item_array.size(); i++) - { - const LLViewerInventoryItem* inv_item = item_array.at(i).get(); - local_items.insert(inv_item->getUUID()); - LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() - << " linked_item_id: " << inv_item->getLinkedUUID() - << " name: " << inv_item->getName() - << " parent: " << inv_item->getParentUUID() - << LL_ENDL; - } - LL_INFOS("Avatar") << " ================================= " << LL_ENDL; - S32 local_only = 0, ais_only = 0; - for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) - { - if (ais_items.find(*it) == ais_items.end()) - { - LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; - local_only++; - } - } - for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) - { - if (local_items.find(*it) == local_items.end()) - { - LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; - ais_only++; - } - } - if (local_only==0 && ais_only==0) - { - LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " - << content["observed"].asInteger() - << " rcv " << content["expected"].asInteger() - << ")" << LL_ENDL; - } -} - -/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - if (content["success"].asBoolean()) - { - LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); - } - - onSuccess(); - } - else - { - failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); - } -} - -void RequestAgentUpdateAppearanceResponder::onSuccess() -{ - mInFlightCounter = llmax(mInFlightCounter-1,0); -} - -/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() -{ - LL_WARNS("Avatar") << "appearance update request failed, status " - << getStatus() << " reason " << getReason() << LL_ENDL; - - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) - { - const LLSD& content = getContent(); - dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); - debugCOF(content); - } - onFailure(); -} - -void RequestAgentUpdateAppearanceResponder::onFailure() -{ - mInFlightCounter = llmax(mInFlightCounter-1,0); - - F32 seconds_to_wait; - mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); - if (mRetryPolicy->shouldRetry(seconds_to_wait)) - { - LL_INFOS() << "retrying" << LL_ENDL; - doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), - seconds_to_wait); - } - else - { - LL_WARNS() << "giving up after too many retries" << LL_ENDL; - } -} - LLSD LLAppearanceMgr::dumpCOF() const { @@ -3603,102 +3348,201 @@ LLSD LLAppearanceMgr::dumpCOF() const void LLAppearanceMgr::requestServerAppearanceUpdate() { - mAppearanceResponder->onRequestRequested(); -} -class LLIncrementCofVersionResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLIncrementCofVersionResponder); -public: - LLIncrementCofVersionResponder() : LLHTTPClient::Responder() + if (!testCOFRequestVersion()) { - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5); + // *TODO: LL_LOG message here + return; } - virtual ~LLIncrementCofVersionResponder() + if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired())) { + LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; + mInFlightCounter = 0; } -protected: - virtual void httpSuccess() + if (gAgentAvatarp->isEditingAppearance()) { - LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - S32 new_version = content["category"]["version"].asInteger(); - - // cof_version should have increased - llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); - - gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; + LL_WARNS("Avatar") << "Avatar editing appearance, not sending request." << LL_ENDL; + // don't send out appearance updates if in appearance editing mode + return; } - virtual void httpFailure() + if (!gAgent.getRegion()) { - LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " - << dumpResponse() << LL_ENDL; - F32 seconds_to_wait; - mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); - if (mRetryPolicy->shouldRetry(seconds_to_wait)) - { - LL_INFOS() << "retrying" << LL_ENDL; - doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, - LLAppearanceMgr::getInstance(), - LLHTTPClient::ResponderPtr(this)), - seconds_to_wait); - } - else - { - LL_WARNS() << "giving up after too many retries" << LL_ENDL; - } + LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL; + return; } - -private: - LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr) -{ - // If we don't have a region, report it as an error - if (gAgent.getRegion() == NULL) + if (gAgent.getRegion()->getCentralBakeVersion() == 0) { - LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL; - return; + LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL; } - std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion"); - if (url.empty()) + LLSD postData; + S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); + if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) { - LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL; - return; + postData = LLAppearanceMgr::instance().dumpCOF(); } - - LL_INFOS() << "Requesting cof_version be incremented via capability to: " - << url << LL_ENDL; - LLSD headers; - LLSD body = LLSD::emptyMap(); - - if (!responder_ptr.get()) + else { - responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder()); + postData["cof_version"] = cof_version; + if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) + { + postData["cof_version"] = cof_version + 999; + } } - LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f); + mInFlightCounter++; + mInFlightTimer.setTimerExpirySec(60.0); + + llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); + gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; + + if (!gAgent.requestPostCapability("UpdateAvatarAppearance", postData, + static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::serverAppearanceUpdateSuccess, this, _1)), + static_cast<LLAgent::httpCallback_t>(boost::bind(&LLAppearanceMgr::decrementInFlightCounter, this)))) + { + LL_WARNS("Avatar") << "Unable to access UpdateAvatarAppearance in this region." << LL_ENDL; + } } -U32 LLAppearanceMgr::getNumAttachmentsInCOF() +void LLAppearanceMgr::serverAppearanceUpdateSuccess(const LLSD &result) { - const LLUUID cof = getCOF(); - LLInventoryModel::item_array_t obj_items; - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); - return obj_items.size(); + decrementInFlightCounter(); + if (result["success"].asBoolean()) + { + LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", result); + } + } + else + { + LL_WARNS("Avatar") << "Non success response for change appearance" << LL_ENDL; + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + debugAppearanceUpdateCOF(result); + } + } +} + +/*static*/ +void LLAppearanceMgr::debugAppearanceUpdateCOF(const LLSD& content) +{ + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); + + LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() + << " ================================= " << LL_ENDL; + std::set<LLUUID> ais_items, local_items; + const LLSD& cof_raw = content["cof_raw"]; + for (LLSD::array_const_iterator it = cof_raw.beginArray(); + it != cof_raw.endArray(); ++it) + { + const LLSD& item = *it; + if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) + { + ais_items.insert(item["item_id"].asUUID()); + if (item["type"].asInteger() == 24) // link + { + LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else if (item["type"].asInteger() == 25) // folder link + { + LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else + { + LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << " type: " << item["type"].asInteger() + << LL_ENDL; + } + } + } + LL_INFOS("Avatar") << LL_ENDL; + LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() + << " ================================= " << LL_ENDL; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); + for (S32 i = 0; i < item_array.size(); i++) + { + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + local_items.insert(inv_item->getUUID()); + LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() + << " linked_item_id: " << inv_item->getLinkedUUID() + << " name: " << inv_item->getName() + << " parent: " << inv_item->getParentUUID() + << LL_ENDL; + } + LL_INFOS("Avatar") << " ================================= " << LL_ENDL; + S32 local_only = 0, ais_only = 0; + for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) + { + if (ais_items.find(*it) == ais_items.end()) + { + LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; + local_only++; + } + } + for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) + { + if (local_items.find(*it) == local_items.end()) + { + LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; + ais_only++; + } + } + if (local_only == 0 && ais_only == 0) + { + LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " + << content["observed"].asInteger() + << " rcv " << content["expected"].asInteger() + << ")" << LL_ENDL; + } } +bool LLAppearanceMgr::testCOFRequestVersion() const +{ + // If we have already received an update for this or higher cof version, ignore. + S32 cof_version = getCOFVersion(); + S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; + S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; + + LL_DEBUGS("Avatar") << "cof_version " << cof_version + << " last_rcv " << last_rcv + << " last_req " << last_req + << " in flight " << mInFlightCounter + << LL_ENDL; + if (cof_version < last_rcv) + { + LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv + << " will not request for " << cof_version << LL_ENDL; + return false; + } + if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version) + { + LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req + << " will not request for " << cof_version << LL_ENDL; + return false; + } + + // Actually send the request. + LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; + return true; +} + std::string LLAppearanceMgr::getAppearanceServiceURL() const { if (gSavedSettings.getString("DebugAvatarAppearanceServiceURLOverride").empty()) @@ -3774,7 +3618,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo // First, make a folder in the My Outfits directory. const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { // cap-based category creation was buggy until recently. use // existence of AIS as an indicator the fix is present. Does @@ -3967,15 +3811,17 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, } } +bool LLAppearanceMgr::mActive = true; + LLAppearanceMgr::LLAppearanceMgr(): mAttachmentInvLinkEnabled(false), mOutfitIsDirty(false), mOutfitLocked(false), - mIsInUpdateAppearanceFromCOF(false), - mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) + mInFlightCounter(0), + mInFlightTimer(), + mIsInUpdateAppearanceFromCOF(false) { LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - // unlock outfit on save operation completed outfit_observer.addCOFSavedCallback(boost::bind( &LLAppearanceMgr::setOutfitLocked, this, false)); @@ -3983,11 +3829,12 @@ LLAppearanceMgr::LLAppearanceMgr(): mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32( "OutfitOperationsTimeout"))); - gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL); + gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL); } LLAppearanceMgr::~LLAppearanceMgr() { + mActive = false; } void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 4ed8c1bfb9..9b6ceb7d3e 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -34,12 +34,10 @@ #include "llinventorymodel.h" #include "llinventoryobserver.h" #include "llviewerinventory.h" -#include "llhttpclient.h" class LLWearableHoldingPattern; class LLInventoryCallback; class LLOutfitUnLockTimer; -class RequestAgentUpdateAppearanceResponder; class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr> { @@ -54,7 +52,6 @@ public: void updateAppearanceFromCOF(bool enforce_item_restrictions = true, bool enforce_ordering = true, nullary_func_t post_update_func = no_op); - bool needToSaveCOF(); void updateCOF(const LLUUID& category, bool append = false); void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); @@ -224,20 +221,23 @@ public: void requestServerAppearanceUpdate(); - void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); + void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } + std::string getAppearanceServiceURL() const; - U32 getNumAttachmentsInCOF(); - // *HACK Remove this after server side texture baking is deployed on all sims. - void incrementCofVersionLegacy(); + bool testCOFRequestVersion() const; + void decrementInFlightCounter() + { + mInFlightCounter = llmax(mInFlightCounter - 1, 0); + } - void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } - std::string getAppearanceServiceURL() const; private: + void serverAppearanceUpdateSuccess(const LLSD &result); + static void debugAppearanceUpdateCOF(const LLSD& content); + std::string mAppearanceServiceURL; - protected: LLAppearanceMgr(); ~LLAppearanceMgr(); @@ -261,13 +261,14 @@ private: bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. - LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; - /** * Lock for blocking operations on outfit until server reply or timeout exceed * to avoid unsynchronized outfit state or performing duplicate operations. */ bool mOutfitLocked; + S32 mInFlightCounter; + LLTimer mInFlightTimer; + static bool mActive; std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9b9b591cd1..44c9f893b8 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -57,8 +57,6 @@ #include "llfocusmgr.h" #include "llviewerjoystick.h" #include "llallocator.h" -#include "llares.h" -#include "llcurl.h" #include "llcalc.h" #include "llconversationlog.h" #include "lldxhardware.h" @@ -228,7 +226,7 @@ #include "llmachineid.h" #include "llmainlooprepeater.h" - +#include "llcoproceduremanager.h" #include "llviewereventrecorder.h" @@ -755,8 +753,11 @@ void fast_exit(int rc) { _exit(rc); } + + } + bool LLAppViewer::init() { setupErrorHandling(mSecondInstance); @@ -825,12 +826,7 @@ bool LLAppViewer::init() // before consumers (LLTextureFetch). mAppCoreHttp.init(); - // *NOTE:Mani - LLCurl::initClass is not thread safe. - // Called before threads are created. - LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"), - gSavedSettings.getS32("CurlMaximumNumberOfHandles"), - gSavedSettings.getBOOL("CurlUseMultipleThreads")); - LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ; + LL_INFOS("InitInfo") << "LLCore::Http initialized." << LL_ENDL ; LLMachineID::init(); @@ -900,7 +896,7 @@ bool LLAppViewer::init() // the libs involved in getting to a full login screen. // LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; - LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL; + LL_INFOS("InitInfo") << "libcurl version is: " << LLCore::LLHttp::getCURLVersion() << LL_ENDL; ///////////////////////////////////////////////// // OS-specific login dialogs @@ -1157,8 +1153,6 @@ bool LLAppViewer::init() { LLNotificationsUtil::add("CorruptedProtectedDataStore"); } - LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback); - gGLActive = FALSE; @@ -1216,6 +1210,12 @@ bool LLAppViewer::init() LLAgentLanguage::init(); + /// Tell the Coprocedure manager how to discover and store the pool sizes + // what I wanted + LLCoprocedureManager::getInstance()->setPropertyMethods( + boost::bind(&LLControlGroup::getU32, boost::ref(gSavedSettings), _1), + boost::bind(&LLControlGroup::declareU32, boost::ref(gSavedSettings), _1, _2, _3, LLControlVariable::PERSIST_ALWAYS)); + return true; } @@ -1282,7 +1282,6 @@ static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread"); static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads"); static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle"); static LLTrace::BlockTimerStatHandle FTM_PUMP("Pump"); -static LLTrace::BlockTimerStatHandle FTM_PUMP_ARES("Ares"); static LLTrace::BlockTimerStatHandle FTM_PUMP_SERVICE("Service"); static LLTrace::BlockTimerStatHandle FTM_SERVICE_CALLBACK("Callback"); static LLTrace::BlockTimerStatHandle FTM_AGENT_AUTOPILOT("Autopilot"); @@ -1306,8 +1305,6 @@ bool LLAppViewer::mainLoop() // Create IO Pump to use for HTTP Requests. gServicePump = new LLPumpIO(gAPRPoolp); - LLHTTPClient::setPump(*gServicePump); - LLCurl::setCAFile(gDirUtilp->getCAFile()); // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. @@ -1426,26 +1423,6 @@ bool LLAppViewer::mainLoop() LL_RECORD_BLOCK_TIME(FTM_IDLE); idle(); - if (gAres != NULL && gAres->isInitialized()) - { - pingMainloopTimeout("Main:ServicePump"); - LL_RECORD_BLOCK_TIME(FTM_PUMP); - { - LL_RECORD_BLOCK_TIME(FTM_PUMP_ARES); - gAres->process(); - } - { - LL_RECORD_BLOCK_TIME(FTM_PUMP_SERVICE); - // this pump is necessary to make the login screen show up - gServicePump->pump(); - - { - LL_RECORD_BLOCK_TIME(FTM_SERVICE_CALLBACK); - gServicePump->callback(); - } - } - } - resumeMainloopTimeout(); } @@ -1550,11 +1527,6 @@ bool LLAppViewer::mainLoop() } gMeshRepo.update() ; - if(!LLCurl::getCurlThread()->update(1)) - { - LLCurl::getCurlThread()->pause() ; //nothing in the curl thread. - } - if(!total_work_pending) //pause texture fetching threads if nothing to process. { LLAppViewer::getTextureCache()->pause(); @@ -1992,7 +1964,6 @@ bool LLAppViewer::cleanup() pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread pending += LLVFSThread::updateClass(0); pending += LLLFSThread::updateClass(0); - pending += LLCurl::getCurlThread()->update(1) ; F64 idle_time = idleTimer.getElapsedTimeF64(); if(!pending) { @@ -2004,7 +1975,6 @@ bool LLAppViewer::cleanup() break; } } - LLCurl::getCurlThread()->pause() ; // Delete workers first // shotdown all worker threads before deleting them in case of co-dependencies @@ -2019,17 +1989,9 @@ bool LLAppViewer::cleanup() LL_INFOS() << "Shutting down message system" << LL_ENDL; end_messaging_system(); - // *NOTE:Mani - The following call is not thread safe. - LL_CHECK_MEMORY - LLCurl::cleanupClass(); - LL_CHECK_MEMORY - // Non-LLCurl libcurl library mAppCoreHttp.cleanup(); - // NOTE The following call is not thread safe. - ll_cleanup_ares(); - LLFilePickerThread::cleanupClass(); //MUST happen AFTER LLCurl::cleanupClass @@ -2115,6 +2077,7 @@ bool LLAppViewer::cleanup() } LL_INFOS() << "Cleaning up LLProxy." << LL_ENDL; LLProxy::cleanupClass(); + LLCore::LLHttp::cleanup(); LLWearableType::cleanupClass(); @@ -3354,7 +3317,7 @@ LLSD LLAppViewer::getViewerInfo() const #endif info["OPENGL_VERSION"] = (const char*)(glGetString(GL_VERSION)); - info["LIBCURL_VERSION"] = LLCurl::getVersionString(); + info["LIBCURL_VERSION"] = LLCore::LLHttp::getCURLVersion(); info["J2C_VERSION"] = LLImageJ2C::getEngineInfo(); bool want_fullname = true; info["AUDIO_DRIVER_VERSION"] = gAudiop ? LLSD(gAudiop->getDriverName(want_fullname)) : LLSD(); @@ -4700,31 +4663,6 @@ void LLAppViewer::saveNameCache() } -void LLAppViewer::saveExperienceCache() -{ - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml"); - LL_INFOS("ExperienceCache") << "Saving " << filename << LL_ENDL; - llofstream cache_stream(filename.c_str()); - if(cache_stream.is_open()) - { - LLExperienceCache::exportFile(cache_stream); - } -} - -void LLAppViewer::loadExperienceCache() -{ - std::string filename = - gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml"); - LL_INFOS("ExperienceCache") << "Loading " << filename << LL_ENDL; - llifstream cache_stream(filename.c_str()); - if(cache_stream.is_open()) - { - LLExperienceCache::importFile(cache_stream); - } -} - - /*! @brief This class is an LLFrameTimer that can be created with an elapsed time that starts counting up from the given value rather than 0.0. @@ -4920,7 +4858,6 @@ void LLAppViewer::idle() // floating throughout the various object lists. // idleNameCache(); - idleExperienceCache(); idleNetwork(); @@ -5350,22 +5287,6 @@ void LLAppViewer::idleNameCache() LLAvatarNameCache::idle(); } -void LLAppViewer::idleExperienceCache() -{ - LLViewerRegion* region = gAgent.getRegion(); - if (!region) return; - - std::string lookup_url=region->getCapability("GetExperienceInfo"); - if(!lookup_url.empty() && *lookup_url.rbegin() != '/') - { - lookup_url += '/'; - } - - LLExperienceCache::setLookupURL(lookup_url); - - LLExperienceCache::idle(); -} - // // Handle messages, and all message related stuff // @@ -5528,7 +5449,9 @@ void LLAppViewer::disconnectViewer() } saveNameCache(); - saveExperienceCache(); + LLExperienceCache *expCache = LLExperienceCache::getIfExists(); + if (expCache) + expCache->cleanup(); // close inventory interface, close all windows LLFloaterInventory::cleanup(); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 718871138e..e8a1ca036b 100755 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -122,9 +122,6 @@ public: void loadNameCache(); void saveNameCache(); - void loadExperienceCache(); - void saveExperienceCache(); - void removeMarkerFiles(); void removeDumpDir(); @@ -233,7 +230,6 @@ private: void idle(); void idleShutdown(); // update avatar SLID and display name caches - void idleExperienceCache(); void idleNameCache(); void idleNetwork(); diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp deleted file mode 100755 index 359ee1e221..0000000000 --- a/indra/newview/llassetuploadqueue.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file llassetupload.cpp - * @brief Serializes asset upload request - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llassetuploadqueue.h" -#include "llviewerregion.h" -#include "llviewerobjectlist.h" - -#include "llassetuploadresponders.h" -#include "llsd.h" -#include <iostream> - -class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder -{ - LOG_CLASS(LLAssetUploadChainResponder); -public: - - LLAssetUploadChainResponder(const LLSD& post_data, - const std::string& file_name, - const LLUUID& queue_id, - U8* data, - U32 data_size, - std::string script_name, - LLAssetUploadQueueSupplier *supplier) : - LLUpdateTaskInventoryResponder(post_data, file_name, queue_id, LLAssetType::AT_LSL_TEXT), - mSupplier(supplier), - mData(data), - mDataSize(data_size), - mScriptName(script_name) - { - } - - virtual ~LLAssetUploadChainResponder() - { - if(mSupplier) - { - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Give ownership of supplier back to queue. - queue->mSupplier = mSupplier; - mSupplier = NULL; - } - } - delete mSupplier; - delete mData; - } - -protected: - virtual void httpFailure() - { - // Parent class will spam the failure. - //LL_WARNS() << dumpResponse() << LL_ENDL; - LLUpdateTaskInventoryResponder::httpFailure(); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - queue->request(&mSupplier); - } - } - - virtual void httpSuccess() - { - LLUpdateTaskInventoryResponder::httpSuccess(); - LLAssetUploadQueue *queue = mSupplier->get(); - if (queue) - { - // Responder is reused across 2 phase upload, - // so only start next upload after 2nd phase complete. - const std::string& state = getContent()["state"].asStringRef(); - if(state == "complete") - { - queue->request(&mSupplier); - } - } - } - -public: - virtual void uploadUpload(const LLSD& content) - { - std::string uploader = content["uploader"]; - - mSupplier->log(std::string("Compiling " + mScriptName).c_str()); - LL_INFOS() << "Compiling " << LL_ENDL; - - // postRaw takes ownership of mData and will delete it. - LLHTTPClient::postRaw(uploader, mData, mDataSize, this); - mData = NULL; - mDataSize = 0; - } - - virtual void uploadComplete(const LLSD& content) - { - // Bytecode save completed - if (content["compiled"]) - { - mSupplier->log("Compilation succeeded"); - LL_INFOS() << "Compiled!" << LL_ENDL; - } - else - { - LLSD compile_errors = content["errors"]; - for(LLSD::array_const_iterator line = compile_errors.beginArray(); - line < compile_errors.endArray(); line++) - { - std::string str = line->asString(); - str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); - mSupplier->log(str); - LL_INFOS() << content["errors"] << LL_ENDL; - } - } - LLUpdateTaskInventoryResponder::uploadComplete(content); - } - - LLAssetUploadQueueSupplier *mSupplier; - U8* mData; - U32 mDataSize; - std::string mScriptName; -}; - - -LLAssetUploadQueue::LLAssetUploadQueue(LLAssetUploadQueueSupplier *supplier) : - mSupplier(supplier) -{ -} - -//virtual -LLAssetUploadQueue::~LLAssetUploadQueue() -{ - delete mSupplier; -} - -// Takes ownership of supplier. -void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) -{ - if (mQueue.empty()) - return; - - UploadData data = mQueue.front(); - mQueue.pop_front(); - - LLSD body; - body["task_id"] = data.mTaskId; - body["item_id"] = data.mItemId; - body["is_script_running"] = data.mIsRunning; - body["target"] = data.mIsTargetMono? "mono" : "lsl2"; - body["experience"] = data.mExperienceId; - - std::string url = ""; - LLViewerObject* object = gObjectList.findObject(data.mTaskId); - if (object) - { - url = object->getRegion()->getCapability("UpdateScriptTask"); - LLHTTPClient::post(url, body, - new LLAssetUploadChainResponder( - body, data.mFilename, data.mQueueId, - data.mData, data.mDataSize, data.mScriptName, *supplier)); - } - - *supplier = NULL; -} - -void LLAssetUploadQueue::queue(const std::string& filename, - const LLUUID& task_id, - const LLUUID& item_id, - BOOL is_running, - BOOL is_target_mono, - const LLUUID& queue_id, - U8* script_data, - U32 data_size, - std::string script_name, - const LLUUID& experience_id) -{ - UploadData data; - data.mTaskId = task_id; - data.mItemId = item_id; - data.mIsRunning = is_running; - data.mIsTargetMono = is_target_mono; - data.mQueueId = queue_id; - data.mFilename = filename; - data.mData = script_data; - data.mDataSize = data_size; - data.mScriptName = script_name; - data.mExperienceId = experience_id; - - mQueue.push_back(data); - - if(mSupplier) - { - request(&mSupplier); - } -} - -LLAssetUploadQueueSupplier::~LLAssetUploadQueueSupplier() -{ -} diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h deleted file mode 100755 index 2ceee8f700..0000000000 --- a/indra/newview/llassetuploadqueue.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file llassetuploadqueue.h - * @brief Serializes asset upload request - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLASSETUPLOADQUEUE_H -#define LL_LLASSETUPLOADQUEUE_H - -#include "lluuid.h" - -#include <string> -#include <deque> - -class LLAssetUploadQueueSupplier; - -class LLAssetUploadQueue -{ -public: - - // Takes ownership of supplier. - LLAssetUploadQueue(LLAssetUploadQueueSupplier* supplier); - virtual ~LLAssetUploadQueue(); - - void queue(const std::string& filename, - const LLUUID& task_id, - const LLUUID& item_id, - BOOL is_running, - BOOL is_target_mono, - const LLUUID& queue_id, - U8* data, - U32 data_size, - std::string script_name, - const LLUUID& experience_id); - - bool isEmpty() const {return mQueue.empty();} - -private: - - friend class LLAssetUploadChainResponder; - - struct UploadData - { - std::string mFilename; - LLUUID mTaskId; - LLUUID mItemId; - BOOL mIsRunning; - BOOL mIsTargetMono; - LLUUID mQueueId; - U8* mData; - U32 mDataSize; - std::string mScriptName; - LLUUID mExperienceId; - }; - - // Ownership of mSupplier passed to currently waiting responder - // and returned to queue when no requests in progress. - LLAssetUploadQueueSupplier* mSupplier; - std::deque<UploadData> mQueue; - - // Passes on ownership of mSupplier if request is made. - void request(LLAssetUploadQueueSupplier** supplier); -}; - -class LLAssetUploadQueueSupplier -{ -public: - virtual ~LLAssetUploadQueueSupplier(); - virtual LLAssetUploadQueue* get() const = 0; - virtual void log(std::string message) const = 0; -}; - -#endif // LL_LLASSETUPLOADQUEUE_H diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp deleted file mode 100755 index d2b1dcbf35..0000000000 --- a/indra/newview/llassetuploadresponders.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -/** - * @file llassetuploadresponders.cpp - * @brief Processes responses received for asset upload requests. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llassetuploadresponders.h" - -// viewer includes -#include "llagent.h" -#include "llcompilequeue.h" -#include "llbuycurrencyhtml.h" -#include "llfilepicker.h" -#include "llinventorydefines.h" -#include "llinventoryobserver.h" -#include "llinventorypanel.h" -#include "llpermissionsflags.h" -#include "llpreviewnotecard.h" -#include "llpreviewscript.h" -#include "llpreviewgesture.h" -#include "llgesturemgr.h" -#include "llstatusbar.h" // sendMoneyBalanceRequest() -#include "llsdserialize.h" -#include "lluploaddialog.h" -#include "llviewerobject.h" -#include "llviewercontrol.h" -#include "llviewerobjectlist.h" -#include "llviewermenufile.h" -#include "llviewertexlayer.h" -#include "llviewerwindow.h" -#include "lltrans.h" - -// library includes -#include "lldir.h" -#include "lleconomy.h" -#include "llfloaterreg.h" -#include "llfocusmgr.h" -#include "llnotificationsutil.h" -#include "llscrolllistctrl.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "llvfs.h" - -void dialog_refresh_all(); - -void on_new_single_inventory_upload_complete( - LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - const std::string inventory_type_string, - const LLUUID& item_folder_id, - const std::string& item_name, - const std::string& item_description, - const LLSD& server_response, - S32 upload_price) -{ - bool success = false; - - if ( upload_price > 0 ) - { - // this upload costed us L$, update our balance - // and display something saying that it cost L$ - LLStatusBar::sendMoneyBalanceRequest(); - - LLSD args; - args["AMOUNT"] = llformat("%d", upload_price); - LLNotificationsUtil::add("UploadPayment", args); - } - - if( item_folder_id.notNull() ) - { - U32 everyone_perms = PERM_NONE; - U32 group_perms = PERM_NONE; - U32 next_owner_perms = PERM_ALL; - if( server_response.has("new_next_owner_mask") ) - { - // The server provided creation perms so use them. - // Do not assume we got the perms we asked for in - // since the server may not have granted them all. - everyone_perms = server_response["new_everyone_mask"].asInteger(); - group_perms = server_response["new_group_mask"].asInteger(); - next_owner_perms = server_response["new_next_owner_mask"].asInteger(); - } - else - { - // The server doesn't provide creation perms - // so use old assumption-based perms. - if( inventory_type_string != "snapshot") - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - } - - LLPermissions new_perms; - new_perms.init( - gAgent.getID(), - gAgent.getID(), - LLUUID::null, - LLUUID::null); - - new_perms.initMasks( - PERM_ALL, - PERM_ALL, - everyone_perms, - group_perms, - next_owner_perms); - - U32 inventory_item_flags = 0; - if (server_response.has("inventory_flags")) - { - inventory_item_flags = (U32) server_response["inventory_flags"].asInteger(); - if (inventory_item_flags != 0) - { - LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL; - } - } - S32 creation_date_now = time_corrected(); - LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( - server_response["new_inventory_item"].asUUID(), - item_folder_id, - new_perms, - server_response["new_asset"].asUUID(), - asset_type, - inventory_type, - item_name, - item_description, - LLSaleInfo::DEFAULT, - inventory_item_flags, - creation_date_now); - - gInventory.updateItem(item); - gInventory.notifyObservers(); - success = true; - - // Show the preview panel for textures and sounds to let - // user know that the image (or snapshot) arrived intact. - LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); - if ( panel ) - { - LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); - - panel->setSelection( - server_response["new_inventory_item"].asUUID(), - TAKE_FOCUS_NO); - - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus); - } - } - else - { - LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; - } - - // remove the "Uploading..." message - LLUploadDialog::modalUploadFinished(); - - // Let the Snapshot floater know we have finished uploading a snapshot to inventory. - LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); - if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot) - { - floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory"))); - } -} - -LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) - : LLHTTPClient::Responder(), - mPostData(post_data), - mVFileID(vfile_id), - mAssetType(asset_type) -{ - if (!gVFS->getExists(vfile_id, asset_type)) - { - LL_WARNS() << "LLAssetUploadResponder called with nonexistant vfile_id" << LL_ENDL; - mVFileID.setNull(); - mAssetType = LLAssetType::AT_NONE; - return; - } -} - -LLAssetUploadResponder::LLAssetUploadResponder( - const LLSD &post_data, - const std::string& file_name, - LLAssetType::EType asset_type) - : LLHTTPClient::Responder(), - mPostData(post_data), - mFileName(file_name), - mAssetType(asset_type) -{ -} - -LLAssetUploadResponder::~LLAssetUploadResponder() -{ - if (!mFileName.empty()) - { - // Delete temp file - LLFile::remove(mFileName); - } -} - -// virtual -void LLAssetUploadResponder::httpFailure() -{ - // *TODO: Add adaptive retry policy? - LL_WARNS() << dumpResponse() << LL_ENDL; - std::string reason; - if (isHttpClientErrorStatus(getStatus())) - { - reason = "Error in upload request. Please visit " - "http://secondlife.com/support for help fixing this problem."; - } - else - { - reason = "The server is experiencing unexpected " - "difficulties."; - } - LLSD args; - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = reason; - LLNotificationsUtil::add("CannotUploadReason", args); - - // unfreeze script preview - if(mAssetType == LLAssetType::AT_LSL_TEXT) - { - LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", mPostData["item_id"]); - if (preview) - { - LLSD errors; - errors.append(LLTrans::getString("UploadFailed") + reason); - preview->callbackLSLCompileFailed(errors); - } - } - - LLUploadDialog::modalUploadFinished(); - LLFilePicker::instance().reset(); // unlock file picker when bulk upload fails -} - -//virtual -void LLAssetUploadResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL; - - const std::string& state = content["state"].asStringRef(); - - if (state == "upload") - { - uploadUpload(content); - } - else if (state == "complete") - { - // rename file in VFS with new asset id - if (mFileName.empty()) - { - // rename the file in the VFS to the actual asset id - // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL; - gVFS->renameFile(mVFileID, mAssetType, content["new_asset"].asUUID(), mAssetType); - } - uploadComplete(content); - } - else - { - uploadFailure(content); - } -} - -void LLAssetUploadResponder::uploadUpload(const LLSD& content) -{ - const std::string& uploader = content["uploader"].asStringRef(); - if (mFileName.empty()) - { - LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); - } - else - { - LLHTTPClient::postFile(uploader, mFileName, this); - } -} - -void LLAssetUploadResponder::uploadFailure(const LLSD& content) -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - - // unfreeze script preview - if(mAssetType == LLAssetType::AT_LSL_TEXT) - { - LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", mPostData["item_id"]); - if (preview) - { - LLSD errors; - errors.append(LLTrans::getString("UploadFailed") + content["message"].asString()); - preview->callbackLSLCompileFailed(errors); - } - } - - // remove the "Uploading..." message - LLUploadDialog::modalUploadFinished(); - - LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); - if (floater_snapshot) - { - floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", false).with("msg", "inventory"))); - } - - const std::string& reason = content["state"].asStringRef(); - // deal with L$ errors - if (reason == "insufficient funds") - { - S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("uploading_costs", args), price ); - } - else - { - LLSD args; - args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); - args["REASON"] = content["message"].asString(); - LLNotificationsUtil::add("CannotUploadReason", args); - } -} - -void LLAssetUploadResponder::uploadComplete(const LLSD& content) -{ -} - -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( - const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) - : LLAssetUploadResponder(post_data, vfile_id, asset_type) -{ -} - -LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( - const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) - : LLAssetUploadResponder(post_data, file_name, asset_type) -{ -} - -// virtual -void LLNewAgentInventoryResponder::httpFailure() -{ - LLAssetUploadResponder::httpFailure(); - //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); -} - - -//virtual -void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) -{ - LLAssetUploadResponder::uploadFailure(content); - - //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE); -} - -//virtual -void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) -{ - LL_DEBUGS() << "LLNewAgentInventoryResponder::result from capabilities" << LL_ENDL; - - //std::ostringstream llsdxml; - //LLSDSerialize::toXML(content, llsdxml); - //LL_INFOS() << "upload complete content:\n " << llsdxml.str() << LL_ENDL; - - LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString()); - LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); - S32 expected_upload_cost = 0; - - // Update L$ and ownership credit information - // since it probably changed on the server - if (asset_type == LLAssetType::AT_TEXTURE || - asset_type == LLAssetType::AT_SOUND || - asset_type == LLAssetType::AT_ANIMATION || - asset_type == LLAssetType::AT_MESH) - { - expected_upload_cost = - LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - } - - on_new_single_inventory_upload_complete( - asset_type, - inventory_type, - mPostData["asset_type"].asString(), - mPostData["folder_id"].asUUID(), - mPostData["name"], - mPostData["description"], - content, - expected_upload_cost); - - // continue uploading for bulk uploads - - // *FIX: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - std::string next_file = LLFilePicker::instance().getNextFile(); - if(!next_file.empty()) - { - std::string name = gDirUtilp->getBaseFileName(next_file, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - // Continuing the horrible hack above, we need to extract the originally requested permissions data, if any, - // and use them for each next file to be uploaded. Note the requested perms are not the same as the - U32 everyone_perms = - content.has("new_everyone_mask") ? - content["new_everyone_mask"].asInteger() : - PERM_NONE; - - U32 group_perms = - content.has("new_group_mask") ? - content["new_group_mask"].asInteger() : - PERM_NONE; - - U32 next_owner_perms = - content.has("new_next_owner_mask") ? - content["new_next_owner_mask"].asInteger() : - PERM_NONE; - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - void *userdata = NULL; - - upload_new_resource( - next_file, - asset_name, - asset_name, - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - next_owner_perms, - group_perms, - everyone_perms, - display_name, - callback, - LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), - userdata); - } - - //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); -} - -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( - const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) - : LLAssetUploadResponder(post_data, vfile_id, asset_type) -{ -} - -LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( - const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) - : LLAssetUploadResponder(post_data, file_name, asset_type) -{ -} - -//virtual -void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) -{ - LL_INFOS() << "LLUpdateAgentInventoryResponder::result from capabilities" << LL_ENDL; - LLUUID item_id = mPostData["item_id"]; - - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(item_id); - if(!item) - { - LL_WARNS() << "Inventory item for " << mVFileID - << " is no longer in agent inventory." << LL_ENDL; - return; - } - - // Update viewer inventory item - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item); - new_item->setAssetUUID(content["new_asset"].asUUID()); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - - LL_INFOS() << "Inventory item " << item->getName() << " saved into " - << content["new_asset"].asString() << LL_ENDL; - - LLInventoryType::EType inventory_type = new_item->getInventoryType(); - switch(inventory_type) - { - case LLInventoryType::IT_NOTECARD: - { - // Update the UI with the new asset. - LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id)); - if(nc) - { - // *HACK: we have to delete the asset in the VFS so - // that the viewer will redownload it. This is only - // really necessary if the asset had to be modified by - // the uploader, so this can be optimized away in some - // cases. A better design is to have a new uuid if the - // script actually changed the asset. - if(nc->hasEmbeddedInventory()) - { - gVFS->removeFile(content["new_asset"].asUUID(), LLAssetType::AT_NOTECARD); - } - nc->refreshFromInventory(new_item->getUUID()); - } - break; - } - case LLInventoryType::IT_LSL: - { - // Find our window and close it if requested. - LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", LLSD(item_id)); - if (preview) - { - // Bytecode save completed - if (content["compiled"]) - { - preview->callbackLSLCompileSucceeded(); - } - else - { - preview->callbackLSLCompileFailed(content["errors"]); - } - } - break; - } - - case LLInventoryType::IT_GESTURE: - { - // If this gesture is active, then we need to update the in-memory - // active map with the new pointer. - if (LLGestureMgr::instance().isGestureActive(item_id)) - { - LLUUID asset_id = new_item->getAssetUUID(); - LLGestureMgr::instance().replaceGesture(item_id, asset_id); - gInventory.notifyObservers(); - } - - //gesture will have a new asset_id - LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(item_id)); - if(previewp) - { - previewp->onUpdateSucceeded(); - } - - break; - } - case LLInventoryType::IT_WEARABLE: - default: - break; - } -} - - -LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, vfile_id, asset_type) -{ -} - -LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type) -{ -} - -LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name, - const LLUUID& queue_id, - LLAssetType::EType asset_type) -: LLAssetUploadResponder(post_data, file_name, asset_type), mQueueId(queue_id) -{ -} - -//virtual -void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) -{ - LL_INFOS() << "LLUpdateTaskInventoryResponder::result from capabilities" << LL_ENDL; - LLUUID item_id = mPostData["item_id"]; - LLUUID task_id = mPostData["task_id"]; - - dialog_refresh_all(); - - switch(mAssetType) - { - case LLAssetType::AT_NOTECARD: - { - // Update the UI with the new asset. - LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(item_id)); - if(nc) - { - // *HACK: we have to delete the asset in the VFS so - // that the viewer will redownload it. This is only - // really necessary if the asset had to be modified by - // the uploader, so this can be optimized away in some - // cases. A better design is to have a new uuid if the - // script actually changed the asset. - if(nc->hasEmbeddedInventory()) - { - gVFS->removeFile(content["new_asset"].asUUID(), - LLAssetType::AT_NOTECARD); - } - nc->setAssetId(content["new_asset"].asUUID()); - nc->refreshFromInventory(); - } - break; - } - case LLAssetType::AT_LSL_TEXT: - { - if(mQueueId.notNull()) - { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mQueueId); - if(NULL != queue) - { - queue->removeItemByItemID(item_id); - } - } - else - { - LLSD floater_key; - floater_key["taskid"] = task_id; - floater_key["itemid"] = item_id; - LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", floater_key); - if (preview) - { - // Bytecode save completed - if (content["compiled"]) - { - preview->callbackLSLCompileSucceeded(task_id, item_id, mPostData["is_script_running"]); - } - else - { - preview->callbackLSLCompileFailed(content["errors"]); - } - } - } - break; - } - default: - break; - } -} - - -///////////////////////////////////////////////////// -// LLNewAgentInventoryVariablePriceResponder::Impl // -///////////////////////////////////////////////////// -class LLNewAgentInventoryVariablePriceResponder::Impl -{ -public: - Impl( - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_data) : - mVFileID(vfile_id), - mAssetType(asset_type), - mInventoryData(inventory_data), - mFileName("") - { - if (!gVFS->getExists(vfile_id, asset_type)) - { - LL_WARNS() - << "LLAssetUploadResponder called with nonexistant " - << "vfile_id " << vfile_id << LL_ENDL; - mVFileID.setNull(); - mAssetType = LLAssetType::AT_NONE; - } - } - - Impl( - const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_data) : - mFileName(file_name), - mAssetType(asset_type), - mInventoryData(inventory_data) - { - mVFileID.setNull(); - } - - std::string getFilenameOrIDString() const - { - return (mFileName.empty() ? mVFileID.asString() : mFileName); - } - - LLUUID getVFileID() const - { - return mVFileID; - } - - std::string getFilename() const - { - return mFileName; - } - - LLAssetType::EType getAssetType() const - { - return mAssetType; - } - - LLInventoryType::EType getInventoryType() const - { - return LLInventoryType::lookup( - mInventoryData["inventory_type"].asString()); - } - - std::string getInventoryTypeString() const - { - return mInventoryData["inventory_type"].asString(); - } - - LLUUID getFolderID() const - { - return mInventoryData["folder_id"].asUUID(); - } - - std::string getItemName() const - { - return mInventoryData["name"].asString(); - } - - std::string getItemDescription() const - { - return mInventoryData["description"].asString(); - } - - void displayCannotUploadReason(const std::string& reason) - { - LLSD args; - args["FILE"] = getFilenameOrIDString(); - args["REASON"] = reason; - - - LLNotificationsUtil::add("CannotUploadReason", args); - LLUploadDialog::modalUploadFinished(); - } - - void onApplicationLevelError(const LLSD& error) - { - static const std::string _IDENTIFIER = "identifier"; - - static const std::string _INSUFFICIENT_FUNDS = - "NewAgentInventory_InsufficientLindenDollarBalance"; - static const std::string _MISSING_REQUIRED_PARAMETER = - "NewAgentInventory_MissingRequiredParamater"; - static const std::string _INVALID_REQUEST_BODY = - "NewAgentInventory_InvalidRequestBody"; - static const std::string _RESOURCE_COST_DIFFERS = - "NewAgentInventory_ResourceCostDiffers"; - - static const std::string _MISSING_PARAMETER = "missing_parameter"; - static const std::string _INVALID_PARAMETER = "invalid_parameter"; - static const std::string _MISSING_RESOURCE = "missing_resource"; - static const std::string _INVALID_RESOURCE = "invalid_resource"; - - // TODO* Add the other error_identifiers - - std::string error_identifier = error[_IDENTIFIER].asString(); - - // TODO*: Pull these user visible strings from an xml file - // to be localized - if ( _INSUFFICIENT_FUNDS == error_identifier ) - { - displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload."); - } - else if ( _MISSING_REQUIRED_PARAMETER == error_identifier ) - { - // Missing parameters - if (error.has(_MISSING_PARAMETER) ) - { - std::string message = - "Upload request was missing required parameter '[P]'"; - LLStringUtil::replaceString( - message, - "[P]", - error[_MISSING_PARAMETER].asString()); - - displayCannotUploadReason(message); - } - else - { - std::string message = - "Upload request was missing a required parameter"; - displayCannotUploadReason(message); - } - } - else if ( _INVALID_REQUEST_BODY == error_identifier ) - { - // Invalid request body, check to see if - // a particular parameter was invalid - if ( error.has(_INVALID_PARAMETER) ) - { - std::string message = "Upload parameter '[P]' is invalid."; - LLStringUtil::replaceString( - message, - "[P]", - error[_INVALID_PARAMETER].asString()); - - // See if the server also responds with what resource - // is missing. - if ( error.has(_MISSING_RESOURCE) ) - { - message += "\nMissing resource '[R]'."; - - LLStringUtil::replaceString( - message, - "[R]", - error[_MISSING_RESOURCE].asString()); - } - else if ( error.has(_INVALID_RESOURCE) ) - { - message += "\nInvalid resource '[R]'."; - - LLStringUtil::replaceString( - message, - "[R]", - error[_INVALID_RESOURCE].asString()); - } - - displayCannotUploadReason(message); - } - else - { - std::string message = "Upload request was malformed"; - displayCannotUploadReason(message); - } - } - else if ( _RESOURCE_COST_DIFFERS == error_identifier ) - { - displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server."); - } - else - { - displayCannotUploadReason("Unknown Error"); - } - } - - void onTransportError() - { - displayCannotUploadReason( - "The server is experiencing unexpected difficulties."); - } - - void onTransportError(const LLSD& error) - { - static const std::string _IDENTIFIER = "identifier"; - - static const std::string _SERVER_ERROR_AFTER_CHARGE = - "NewAgentInventory_ServerErrorAfterCharge"; - - std::string error_identifier = error[_IDENTIFIER].asString(); - - // TODO*: Pull the user visible strings from an xml file - // to be localized - - if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier ) - { - displayCannotUploadReason( - "The server is experiencing unexpected difficulties. You may have been charged for the upload."); - } - else - { - displayCannotUploadReason( - "The server is experiencing unexpected difficulties."); - } - } - - bool uploadConfirmationCallback( - const LLSD& notification, - const LLSD& response, - LLPointer<LLNewAgentInventoryVariablePriceResponder> responder) - { - S32 option; - std::string confirmation_url; - - option = LLNotificationsUtil::getSelectedOption( - notification, - response); - - confirmation_url = - notification["payload"]["confirmation_url"].asString(); - - // Yay! We are confirming or cancelling our upload - switch(option) - { - case 0: - { - confirmUpload(confirmation_url, responder); - } - break; - case 1: - default: - break; - } - - return false; - } - - void confirmUpload( - const std::string& confirmation_url, - LLPointer<LLNewAgentInventoryVariablePriceResponder> responder) - { - if ( getFilename().empty() ) - { - // we have no filename, use virtual file ID instead - LLHTTPClient::postFile( - confirmation_url, - getVFileID(), - getAssetType(), - responder); - } - else - { - LLHTTPClient::postFile( - confirmation_url, - getFilename(), - responder); - } - } - - -private: - std::string mFileName; - - LLSD mInventoryData; - LLAssetType::EType mAssetType; - LLUUID mVFileID; -}; - -/////////////////////////////////////////////// -// LLNewAgentInventoryVariablePriceResponder // -/////////////////////////////////////////////// -LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_info) -{ - mImpl = new Impl( - vfile_id, - asset_type, - inventory_info); -} - -LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder( - const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_info) -{ - mImpl = new Impl( - file_name, - asset_type, - inventory_info); -} - -LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder() -{ - delete mImpl; -} - -void LLNewAgentInventoryVariablePriceResponder::httpFailure() -{ - const LLSD& content = getContent(); - LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - - static const std::string _ERROR = "error"; - if ( content.has(_ERROR) ) - { - mImpl->onTransportError(content[_ERROR]); - } - else - { - mImpl->onTransportError(); - } -} - -void LLNewAgentInventoryVariablePriceResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - // Parse out application level errors and the appropriate - // responses for them - static const std::string _ERROR = "error"; - static const std::string _STATE = "state"; - - static const std::string _COMPLETE = "complete"; - static const std::string _CONFIRM_UPLOAD = "confirm_upload"; - - static const std::string _UPLOAD_PRICE = "upload_price"; - static const std::string _RESOURCE_COST = "resource_cost"; - static const std::string _RSVP = "rsvp"; - - // Check for application level errors - if ( content.has(_ERROR) ) - { - LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - onApplicationLevelError(content[_ERROR]); - return; - } - - std::string state = content[_STATE]; - LLAssetType::EType asset_type = mImpl->getAssetType(); - - if ( _COMPLETE == state ) - { - // rename file in VFS with new asset id - if (mImpl->getFilename().empty()) - { - // rename the file in the VFS to the actual asset id - // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL; - gVFS->renameFile( - mImpl->getVFileID(), - asset_type, - content["new_asset"].asUUID(), - asset_type); - } - - on_new_single_inventory_upload_complete( - asset_type, - mImpl->getInventoryType(), - mImpl->getInventoryTypeString(), - mImpl->getFolderID(), - mImpl->getItemName(), - mImpl->getItemDescription(), - content, - content[_UPLOAD_PRICE].asInteger()); - - // TODO* Add bulk (serial) uploading or add - // a super class of this that does so - } - else if ( _CONFIRM_UPLOAD == state ) - { - showConfirmationDialog( - content[_UPLOAD_PRICE].asInteger(), - content[_RESOURCE_COST].asInteger(), - content[_RSVP].asString()); - } - else - { - LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - onApplicationLevelError(""); - } -} - -void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError( - const LLSD& error) -{ - mImpl->onApplicationLevelError(error); -} - -void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( - S32 upload_price, - S32 resource_cost, - const std::string& confirmation_url) -{ - if ( 0 == upload_price ) - { - // don't show confirmation dialog for free uploads, I mean, - // they're free! - - // The creating of a new instrusive_ptr(this) - // creates a new boost::intrusive_ptr - // which is a copy of this. This code is required because - // 'this' is always of type Class* and not the intrusive_ptr, - // and thus, a reference to 'this' is not registered - // by using just plain 'this'. - - // Since LLNewAgentInventoryVariablePriceResponder is a - // reference counted class, it is possible (since the - // reference to a plain 'this' would be missed here) that, - // when using plain ol' 'this', that this object - // would be deleted before the callback is triggered - // and cause sadness. - mImpl->confirmUpload( - confirmation_url, - LLPointer<LLNewAgentInventoryVariablePriceResponder>(this)); - } - else - { - LLSD substitutions; - LLSD payload; - - substitutions["PRICE"] = upload_price; - - payload["confirmation_url"] = confirmation_url; - - // The creating of a new instrusive_ptr(this) - // creates a new boost::intrusive_ptr - // which is a copy of this. This code is required because - // 'this' is always of type Class* and not the intrusive_ptr, - // and thus, a reference to 'this' is not registered - // by using just plain 'this'. - - // Since LLNewAgentInventoryVariablePriceResponder is a - // reference counted class, it is possible (since the - // reference to a plain 'this' would be missed here) that, - // when using plain ol' 'this', that this object - // would be deleted before the callback is triggered - // and cause sadness. - LLNotificationsUtil::add( - "UploadCostConfirmation", - substitutions, - payload, - boost::bind( - &LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback, - mImpl, - _1, - _2, - LLPointer<LLNewAgentInventoryVariablePriceResponder>(this))); - } -} - - diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h deleted file mode 100755 index 7fbebc7481..0000000000 --- a/indra/newview/llassetuploadresponders.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @file llassetuploadresponders.h - * @brief Processes responses received for asset upload requests. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_LLASSETUPLOADRESPONDER_H -#define LL_LLASSETUPLOADRESPONDER_H - -#include "llhttpclient.h" - -// Abstract class for supporting asset upload -// via capabilities -class LLAssetUploadResponder : public LLHTTPClient::Responder -{ -protected: - LOG_CLASS(LLAssetUploadResponder); -public: - LLAssetUploadResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLAssetUploadResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type); - ~LLAssetUploadResponder(); - -protected: - virtual void httpFailure(); - virtual void httpSuccess(); - -public: - virtual void uploadUpload(const LLSD& content); - virtual void uploadComplete(const LLSD& content); - virtual void uploadFailure(const LLSD& content); - -protected: - LLSD mPostData; - LLAssetType::EType mAssetType; - LLUUID mVFileID; - std::string mFileName; -}; - -// TODO*: Remove this once deprecated -class LLNewAgentInventoryResponder : public LLAssetUploadResponder -{ - LOG_CLASS(LLNewAgentInventoryResponder); -public: - LLNewAgentInventoryResponder( - const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLNewAgentInventoryResponder( - const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type); - virtual void uploadComplete(const LLSD& content); - virtual void uploadFailure(const LLSD& content); -protected: - virtual void httpFailure(); -}; - -// A base class which goes through and performs some default -// actions for variable price uploads. If more specific actions -// are needed (such as different confirmation messages, etc.) -// the functions onApplicationLevelError and showConfirmationDialog. -class LLNewAgentInventoryVariablePriceResponder : - public LLHTTPClient::Responder -{ - LOG_CLASS(LLNewAgentInventoryVariablePriceResponder); -public: - LLNewAgentInventoryVariablePriceResponder( - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - const LLSD& inventory_info); - - LLNewAgentInventoryVariablePriceResponder( - const std::string& file_name, - LLAssetType::EType asset_type, - const LLSD& inventory_info); - virtual ~LLNewAgentInventoryVariablePriceResponder(); - -private: - /* virtual */ void httpFailure(); - /* virtual */ void httpSuccess(); - -public: - virtual void onApplicationLevelError( - const LLSD& error); - virtual void showConfirmationDialog( - S32 upload_price, - S32 resource_cost, - const std::string& confirmation_url); - -private: - class Impl; - Impl* mImpl; -}; - -class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder -{ -public: - LLUpdateAgentInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLUpdateAgentInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type); - virtual void uploadComplete(const LLSD& content); -}; - -class LLUpdateTaskInventoryResponder : public LLAssetUploadResponder -{ -public: - LLUpdateTaskInventoryResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type); - LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name, - LLAssetType::EType asset_type); - LLUpdateTaskInventoryResponder(const LLSD& post_data, - const std::string& file_name, - const LLUUID& queue_id, - LLAssetType::EType asset_type); - - virtual void uploadComplete(const LLSD& content); - -private: - LLUUID mQueueId; -}; - -#endif // LL_LLASSETUPLOADRESPONDER_H diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 38e153137c..470f516db2 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -35,7 +35,6 @@ // external library headers // other Linden headers #include "llcharacter.h" -#include "llhttpclient.h" #include "lltimer.h" #include "llviewercontrol.h" #include "llviewermenu.h" @@ -43,7 +42,10 @@ #include "llviewerregion.h" #include "llvoavatar.h" #include "llworld.h" - +#include "llhttpsdhandler.h" +#include "httpheaders.h" +#include "httpoptions.h" +#include "llcorehttputil.h" static const std::string KEY_AGENTS = "agents"; // map static const std::string KEY_WEIGHT = "weight"; // integer @@ -55,166 +57,178 @@ static const std::string KEY_ERROR = "error"; // Send data updates about once per minute, only need per-frame resolution LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; +//LLCore::HttpRequest::ptr_t LLAvatarRenderInfoAccountant::sHttpRequest; - -// HTTP responder class for GET request for avatar render weight information -class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder +//========================================================================= +void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64 regionHandle) { -public: - LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle) - { - } - - virtual void error(U32 statusNum, const std::string& reason) - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight GET error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } - - } - - virtual void result(const LLSD& content) - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; - } - - if (content.isMap()) - { - if (content.has(KEY_AGENTS)) - { - const LLSD & agents = content[KEY_AGENTS]; - if (agents.isMap()) - { - LLSD::map_const_iterator report_iter = agents.beginMap(); - while (report_iter != agents.endMap()) - { - LLUUID target_agent_id = LLUUID(report_iter->first); - const LLSD & agent_info_map = report_iter->second; - LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); - if (avatarp && - avatarp->isAvatar() && - agent_info_map.isMap()) - { // Extract the data for this avatar - - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Agent " << target_agent_id - << ": " << agent_info_map << LL_ENDL; - } - - if (agent_info_map.has(KEY_WEIGHT)) - { - ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); - } - } - report_iter++; - } - } - } // has "agents" - else if (content.has(KEY_ERROR)) - { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info GET error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; - } - } - } - else - { - LL_INFOS() << "Avatar render weight info recieved but region not found for " - << mRegionHandle << LL_ENDL; - } - } - -private: - U64 mRegionHandle; -}; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for " + << regionHandle << LL_ENDL; + return; + } + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL; + return; + } + + if (result.has(KEY_AGENTS)) + { + const LLSD & agents = result[KEY_AGENTS]; + if (agents.isMap()) + { + LLSD::map_const_iterator report_iter = agents.beginMap(); + while (report_iter != agents.endMap()) + { + LLUUID target_agent_id = LLUUID(report_iter->first); + const LLSD & agent_info_map = report_iter->second; + LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); + if (avatarp && + avatarp->isAvatar() && + agent_info_map.isMap()) + { // Extract the data for this avatar + + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS() << "LRI: Agent " << target_agent_id + << ": " << agent_info_map << LL_ENDL; + } + + if (agent_info_map.has(KEY_WEIGHT)) + { + ((LLVOAvatar *) avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); + } + } + report_iter++; + } + } + } // has "agents" + else if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS() << "Avatar render info GET error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } +} -// HTTP responder class for POST request for avatar render weight information -class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder +//------------------------------------------------------------------------- +void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U64 regionHandle) { -public: - LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle) - { - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but region not found for " + << regionHandle << LL_ENDL; + return; + } + + if (logRenderInfo()) + { + LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info to region " << regionp->getName() + << " from " << url << LL_ENDL; + } + + // Build the render info to POST to the region + LLSD report = LLSD::emptyMap(); + LLSD agents = LLSD::emptyMap(); + + std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); + while( iter != LLCharacter::sInstances.end() ) + { + LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); + if (avatar && + avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) + !avatar->isDead() && // Not dead yet + avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region + { + avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date + + LLSD info = LLSD::emptyMap(); + if (avatar->getVisualComplexity() > 0) + { + info[KEY_WEIGHT] = avatar->getVisualComplexity(); + agents[avatar->getID().asString()] = info; + + if (logRenderInfo()) + { + LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Sending avatar render info for " << avatar->getID() + << ": " << info << LL_ENDL; + LL_INFOS("AvatarRenderInfoAccountant") << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() + << ", area " << avatar->getAttachmentSurfaceArea() + << LL_ENDL; + } + } + } + iter++; + } + + if (agents.size() == 0) + return; + + report[KEY_AGENTS] = agents; + regionp = NULL; + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, report); + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) + { + LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for " + << regionHandle << LL_ENDL; + return; + } + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AvatarRenderInfoAccountant") << "HTTP status, " << status.toTerseString() << LL_ENDL; + return; + } + + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS("AvatarRenderInfoAccountant") << "LRI: Result for avatar weights POST for region " << regionp->getName() + << ": " << result << LL_ENDL; + } + + if (result.isMap()) + { + if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render info POST error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } + } - virtual void error(U32 statusNum, const std::string& reason) - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum - << ", " << reason - << " returned by region " << regionp->getName() - << LL_ENDL; - } - else - { - LL_WARNS() << "Avatar render weight POST error recieved but region not found for " - << mRegionHandle - << ", error " << statusNum - << ", " << reason - << LL_ENDL; - } - } - - virtual void result(const LLSD& content) - { - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - if (LLAvatarRenderInfoAccountant::logRenderInfo()) - { - LL_INFOS() << "LRI: Result for avatar weights POST for region " << regionp->getName() - << ": " << content << LL_ENDL; - } - - if (content.isMap()) - { - if (content.has(KEY_ERROR)) - { - const LLSD & error = content[KEY_ERROR]; - LL_WARNS() << "Avatar render info POST error: " - << error[KEY_IDENTIFIER] - << ": " << error[KEY_MESSAGE] - << " from region " << regionp->getName() - << LL_ENDL; - } - } - } - else - { - LL_INFOS() << "Avatar render weight POST result recieved but region not found for " - << mRegionHandle << LL_ENDL; - } - } - -private: - U64 mRegionHandle; -}; +} // static // Send request for one region, no timer checks @@ -223,53 +237,9 @@ void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regio std::string url = regionp->getCapability("AvatarRenderInfo"); if (!url.empty()) { - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Sending avatar render info to region " - << regionp->getName() - << " from " << url - << LL_ENDL; - } - - // Build the render info to POST to the region - LLSD report = LLSD::emptyMap(); - LLSD agents = LLSD::emptyMap(); - - std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); - while( iter != LLCharacter::sInstances.end() ) - { - LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*iter); - if (avatar && - avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) - !avatar->isDead() && // Not dead yet - avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region - { - avatar->calculateUpdateRenderCost(); // Make sure the numbers are up-to-date - - LLSD info = LLSD::emptyMap(); - if (avatar->getVisualComplexity() > 0) - { - info[KEY_WEIGHT] = avatar->getVisualComplexity(); - agents[avatar->getID().asString()] = info; - - if (logRenderInfo()) - { - LL_INFOS() << "LRI: Sending avatar render info for " << avatar->getID() - << ": " << info << LL_ENDL; - LL_INFOS() << "LRI: other info geometry " << avatar->getAttachmentGeometryBytes() - << ", area " << avatar->getAttachmentSurfaceArea() - << LL_ENDL; - } - } - } - iter++; - } - - report[KEY_AGENTS] = agents; - if (agents.size() > 0) - { - LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle())); - } + std::string coroname = + LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro", + boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro, url, regionp->getHandle())); } } @@ -292,7 +262,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi } // First send a request to get the latest data - LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); + std::string coroname = + LLCoros::instance().launch("LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro", + boost::bind(&LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro, url, regionp->getHandle())); } } @@ -301,6 +273,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi // Called every frame - send render weight requests to every region void LLAvatarRenderInfoAccountant::idle() { +// if (!LLAvatarRenderInfoAccountant::sHttpRequest) +// sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); + if (sRenderInfoReportTimer.hasExpired()) { const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds @@ -393,6 +368,7 @@ void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer(const LLUUID& reg // static bool LLAvatarRenderInfoAccountant::logRenderInfo() { - static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); - return render_mute_logging_enabled; + return true; +// static LLCachedControl<bool> render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); +// return render_mute_logging_enabled; } diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h index d68f2dccfb..f7a04cca2c 100644 --- a/indra/newview/llavatarrenderinfoaccountant.h +++ b/indra/newview/llavatarrenderinfoaccountant.h @@ -29,6 +29,9 @@ #if ! defined(LL_llavatarrenderinfoaccountant_H) #define LL_llavatarrenderinfoaccountant_H +#include "httpcommon.h" +#include "llcoros.h" + class LLViewerRegion; // Class to gather avatar rendering information @@ -36,8 +39,6 @@ class LLViewerRegion; class LLAvatarRenderInfoAccountant { public: - LLAvatarRenderInfoAccountant() {}; - ~LLAvatarRenderInfoAccountant() {}; static void sendRenderInfoToRegion(LLViewerRegion * regionp); static void getRenderInfoFromRegion(LLViewerRegion * regionp); @@ -49,8 +50,16 @@ public: static bool logRenderInfo(); private: + LLAvatarRenderInfoAccountant() {}; + ~LLAvatarRenderInfoAccountant() {}; + // Send data updates about once per minute, only need per-frame resolution static LLFrameTimer sRenderInfoReportTimer; + + static void avatarRenderInfoGetCoro(std::string url, U64 regionHandle); + static void avatarRenderInfoReportCoro(std::string url, U64 regionHandle); + + }; #endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */ diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index 59ecbdd0ea..59ecbdd0ea 100755..100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h deleted file mode 100755 index 0516c9cdb4..0000000000 --- a/indra/newview/llcallbacklist.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llcallbacklist.h - * @brief A simple list of callback functions to call. - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#ifndef LL_LLCALLBACKLIST_H -#define LL_LLCALLBACKLIST_H - -#include "llstl.h" - -class LLCallbackList -{ -public: - typedef void (*callback_t)(void*); - - LLCallbackList(); - ~LLCallbackList(); - - void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) - BOOL containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair - BOOL deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void callFunctions(); // calls all functions - void deleteAllFunctions(); - - static void test(); - -protected: - // Use a list so that the callbacks are ordered in case that matters - typedef std::pair<callback_t,void*> callback_pair_t; - typedef std::list<callback_pair_t > callback_list_t; - callback_list_t mCallbackList; -}; - -typedef boost::function<void ()> nullary_func_t; -typedef boost::function<bool ()> bool_func_t; - -// Call a given callable once in idle loop. -void doOnIdleOneTime(nullary_func_t callable); - -// Repeatedly call a callable in idle loop until it returns true. -void doOnIdleRepeating(bool_func_t callable); - -// Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds); - -// Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds); - -extern LLCallbackList gIdleCallbacks; - -#endif diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp deleted file mode 100755 index ef9b910ae5..0000000000 --- a/indra/newview/llcapabilitylistener.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @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; -} diff --git a/indra/newview/llcapabilitylistener.h b/indra/newview/llcapabilitylistener.h deleted file mode 100755 index e7535013e7..0000000000 --- a/indra/newview/llcapabilitylistener.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file llcapabilitylistener.h - * @author Nat Goodspeed - * @date 2009-01-07 - * @brief Provide an event-based API for capability requests - * - * $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$ - */ - -#if ! defined(LL_LLCAPABILITYLISTENER_H) -#define LL_LLCAPABILITYLISTENER_H - -#include "llevents.h" // LLEventPump -#include "llsdmessage.h" // LLSDMessage::ArgError -#include "llerror.h" // LOG_CLASS() - -class LLCapabilityProvider; -class LLMessageSystem; -class LLSD; - -class LLCapabilityListener -{ - LOG_CLASS(LLCapabilityListener); -public: - LLCapabilityListener(const std::string& name, LLMessageSystem* messageSystem, - const LLCapabilityProvider& provider, - const LLUUID& agentID, const LLUUID& sessionID); - - /// Capability-request exception - typedef LLSDMessage::ArgError ArgError; - /// Get LLEventPump on which we listen for capability requests - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLEventPump& getCapAPI() { return mEventPump; } - - /** - * Base class for mapping an as-yet-undeployed capability name to a (pair - * of) LLMessageSystem message(s). To map a capability name to such - * messages, derive a subclass of CapabilityMapper and declare a static - * instance in a translation unit known to be loaded. The mapping is not - * region-specific. If an LLViewerRegion's capListener() receives a - * request for a supported capability, it will use the capability's URL. - * If not, it will look for an applicable CapabilityMapper subclass - * instance. - */ - class CapabilityMapper - { - public: - /** - * Base-class constructor. Typically your subclass constructor will - * pass these parameters as literals. - * @param cap the capability name handled by this (subclass) instance - * @param reply the name of the response LLMessageSystem message. Omit - * if the LLMessageSystem message you intend to send doesn't prompt a - * reply message, or if you already handle that message in some other - * way. - */ - CapabilityMapper(const std::string& cap, const std::string& reply = ""); - virtual ~CapabilityMapper(); - /// query the capability name - std::string getCapName() const { return mCapName; } - /// query the reply message name - std::string getReplyName() const { return mReplyName; } - /** - * Override this method to build the LLMessageSystem message we should - * send instead of the requested capability message. DO NOT send that - * message: that will be handled by the caller. - */ - virtual void buildMessage(LLMessageSystem* messageSystem, - const LLUUID& agentID, - const LLUUID& sessionID, - const std::string& capabilityName, - const LLSD& payload) const = 0; - /** - * Override this method if you pass a non-empty @a reply - * LLMessageSystem message name to the constructor: that is, if you - * expect to receive an LLMessageSystem message in response to the - * message you constructed in buildMessage(). If you don't pass a @a - * reply message name, you need not override this method as it won't - * be called. - * - * Using LLMessageSystem message-reading operations, your - * readResponse() override should construct and return an LLSD object - * of the form you expect to receive from the real implementation of - * the capability you intend to invoke, when it finally goes live. - */ - virtual LLSD readResponse(LLMessageSystem* messageSystem) const; - - private: - const std::string mCapName; - const std::string mReplyName; - }; - -private: - /// Bind the LLCapabilityProvider passed to our ctor - const LLCapabilityProvider& mProvider; - - /// Post an event to this LLEventPump to invoke a capability message on - /// the bound LLCapabilityProvider's server - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLEventStream mEventPump; - - LLMessageSystem* mMessageSystem; - LLUUID mAgentID, mSessionID; - - /// listener to process capability requests - bool capListener(const LLSD&); - - /// helper class for capListener() - class CapabilityMappers; -}; - -#endif /* ! defined(LL_LLCAPABILITYLISTENER_H) */ diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp deleted file mode 100755 index b2524d14f8..0000000000 --- a/indra/newview/llcaphttpsender.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file llcaphttpsender.cpp - * @brief Abstracts details of sending messages via UntrustedMessage cap. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llcaphttpsender.h" - -#include "llhost.h" - -LLCapHTTPSender::LLCapHTTPSender(const std::string& cap) : - mCap(cap) -{ -} - -//virtual -void LLCapHTTPSender::send(const LLHost& host, const std::string& message, - const LLSD& body, - LLHTTPClient::ResponderPtr response) const -{ - LL_INFOS() << "LLCapHTTPSender::send: message " << message - << " to host " << host << LL_ENDL; - LLSD llsd; - llsd["message"] = message; - llsd["body"] = body; - LLHTTPClient::post(mCap, llsd, response); -} diff --git a/indra/newview/llcaphttpsender.h b/indra/newview/llcaphttpsender.h deleted file mode 100755 index e1f4c813f6..0000000000 --- a/indra/newview/llcaphttpsender.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file llcaphttpsender.h - * @brief Abstracts details of sending messages via the - * UntrustedMessage capability. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_CAP_HTTP_SENDER_H -#define LL_CAP_HTTP_SENDER_H - -#include "llhttpsender.h" - -class LLCapHTTPSender : public LLHTTPSender -{ -public: - LLCapHTTPSender(const std::string& cap); - - /** @brief Send message via UntrustedMessage capability with body, - call response when done */ - virtual void send(const LLHost& host, - const std::string& message, const LLSD& body, - LLHTTPClient::ResponderPtr response) const; - -private: - std::string mCap; -}; - -#endif // LL_CAP_HTTP_SENDER_H diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp deleted file mode 100755 index f1ef8e9a03..0000000000 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llclassifiedstatsresponder.cpp - * @brief Receives information about classified ad click-through - * counts for display in the classified information UI. - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llclassifiedstatsresponder.h" - -#include "llpanelclassified.h" -#include "llpanel.h" -#include "llhttpclient.h" -#include "llsdserialize.h" -#include "llviewerregion.h" -#include "llview.h" -#include "message.h" - -LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID classified_id) -: mClassifiedID(classified_id) -{} - -/*virtual*/ -void LLClassifiedStatsResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - S32 teleport = content["teleport_clicks"].asInteger(); - S32 map = content["map_clicks"].asInteger(); - S32 profile = content["profile_clicks"].asInteger(); - S32 search_teleport = content["search_teleport_clicks"].asInteger(); - S32 search_map = content["search_map_clicks"].asInteger(); - S32 search_profile = content["search_profile_clicks"].asInteger(); - - LLPanelClassifiedInfo::setClickThrough( mClassifiedID, - teleport + search_teleport, - map + search_map, - profile + search_profile, - true); -} - -/*virtual*/ -void LLClassifiedStatsResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} - diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h deleted file mode 100755 index efa4d82411..0000000000 --- a/indra/newview/llclassifiedstatsresponder.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file llclassifiedstatsresponder.h - * @brief Receives information about classified ad click-through - * counts for display in the classified information UI. - * - * $LicenseInfo:firstyear=2007&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$ - */ -#ifndef LL_LLCLASSIFIEDSTATSRESPONDER_H -#define LL_LLCLASSIFIEDSTATSRESPONDER_H - -#include "llhttpclient.h" -#include "llview.h" -#include "lluuid.h" - -class LLClassifiedStatsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLClassifiedStatsResponder); -public: - LLClassifiedStatsResponder(LLUUID classified_id); - -protected: - //If we get back a normal response, handle it here - virtual void httpSuccess(); - //If we get back an error (not found, etc...), handle it here - virtual void httpFailure(); - -protected: - LLUUID mClassifiedID; -}; - -#endif // LL_LLCLASSIFIEDSTATSRESPONDER_H diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 19dba3f917..5ea7efc045 100755 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -30,6 +30,7 @@ #include "llcommandhandler.h" #include "llnotificationsutil.h" #include "llcommanddispatcherlistener.h" +#include "llstartup.h" #include "stringize.h" // system includes @@ -116,7 +117,11 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL; if (! slurl_blocked) { - LLNotificationsUtil::add("BlockedSLURL"); + if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) + { + // Note: commands can arrive before we initialize everything we need for Notification. + LLNotificationsUtil::add("BlockedSLURL"); + } slurl_blocked = true; } return true; @@ -138,7 +143,10 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL; if (! slurl_throttled) { - LLNotificationsUtil::add("ThrottledSLURL"); + if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) + { + LLNotificationsUtil::add("ThrottledSLURL"); + } slurl_throttled = true; } return true; diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index d9fd4509a5..219bcf0eb0 100755 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -37,8 +37,6 @@ #include "llcompilequeue.h" #include "llagent.h" -#include "llassetuploadqueue.h" -#include "llassetuploadresponders.h" #include "llchat.h" #include "llfloaterreg.h" #include "llviewerwindow.h" @@ -59,11 +57,54 @@ #include "lltrans.h" #include "llselectmgr.h" -#include "llexperienceassociationresponder.h" #include "llexperiencecache.h" -// *TODO: This should be separated into the script queue, and the floater views of that queue. -// There should only be one floater class that can view any queue type +#include "llviewerassetupload.h" +#include "llcorehttputil.h" + +// *NOTE$: A minor specialization of LLScriptAssetUpload, it does not require a buffer +// (and does not save a buffer to the vFS) and it finds the compile queue window and +// displays a compiling message. +class LLQueuedScriptAssetUpload : public LLScriptAssetUpload +{ +public: + LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, TargetType_t targetType, + bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, taskUploadFinish_f finish) : + LLScriptAssetUpload(taskId, itemId, targetType, isRunning, + exerienceId, std::string(), finish), + mScriptName(scriptName), + mQueueId(queueId) + { + setAssetId(assetId); + } + + virtual LLSD prepareUpload() + { + /* *NOTE$: The parent class (LLScriptAssetUpload will attempt to save + * the script buffer into to the VFS. Since the resource is already in + * the VFS we don't want to do that. Just put a compiling message in + * the window and move on + */ + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId)); + if (queue) + { + std::string message = std::string("Compiling \"") + getScriptName() + std::string("\"..."); + + queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM); + } + + return LLSD().with("success", LLSD::Boolean(true)); + } + + + std::string getScriptName() const { return mScriptName; } + +private: + void setScriptName(const std::string &scriptName) { mScriptName = scriptName; } + + LLUUID mQueueId; + std::string mScriptName; +}; ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -127,7 +168,7 @@ void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object, //which it internally stores. //If we call this further down in the function, calls to handleInventory - //and nextObject may update the interally stored viewer object causing + //and nextObject may update the internally stored viewer object causing //the removal of the incorrect listener from an incorrect object. //Fixes SL-6119:Recompile scripts fails to complete @@ -242,81 +283,17 @@ BOOL LLFloaterScriptQueue::startQueue() return nextObject(); } -class CompileQueueExperienceResponder : public LLHTTPClient::Responder -{ -public: - CompileQueueExperienceResponder(const LLUUID& parent):mParent(parent) - { - } - - LLUUID mParent; - - /*virtual*/ void httpSuccess() - { - sendResult(getContent()); - } - /*virtual*/ void httpFailure() - { - sendResult(LLSD()); - } - void sendResult(const LLSD& content) - { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mParent); - if(!queue) - return; - - queue->experienceIdsReceived(content["experience_ids"]); - } -}; - - - ///---------------------------------------------------------------------------- /// Class LLFloaterCompileQueue ///---------------------------------------------------------------------------- - -class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier -{ -public: - - LLCompileFloaterUploadQueueSupplier(const LLUUID& queue_id) : - mQueueId(queue_id) - { - } - - virtual LLAssetUploadQueue* get() const - { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId)); - if(NULL == queue) - { - return NULL; - } - return queue->getUploadQueue(); - } - - virtual void log(std::string message) const - { - LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(mQueueId)); - if(NULL == queue) - { - return; - } - - queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM); - } - -private: - LLUUID mQueueId; -}; - LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key) : LLFloaterScriptQueue(key) { setTitle(LLTrans::getString("CompileQueueTitle")); setStartString(LLTrans::getString("CompileQueueStart")); - mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID())); +// mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID())); } LLFloaterCompileQueue::~LLFloaterCompileQueue() @@ -380,8 +357,8 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(), viewer_object->getID(), itemp); - ExperienceAssociationResponder::fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(), - boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1)); + LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(), + boost::bind(&LLFloaterCompileQueue::requestAsset, datap, _1)); } } } @@ -423,6 +400,37 @@ void LLFloaterCompileQueue::requestAsset( LLScriptQueueData* datap, const LLSD& (void*)datap); } +/*static*/ +void LLFloaterCompileQueue::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId) +{ + + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", LLSD(queueId)); + if (queue) + { + // Bytecode save completed + if (response["compiled"]) + { + std::string message = std::string("Compilation of \"") + scriptName + std::string("\" succeeded"); + + queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM); + LL_INFOS() << message << LL_ENDL; + } + else + { + LLSD compile_errors = response["errors"]; + for (LLSD::array_const_iterator line = compile_errors.beginArray(); + line < compile_errors.endArray(); line++) + { + std::string str = line->asString(); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + + queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(str, ADD_BOTTOM); + } + LL_INFOS() << response["errors"] << LL_ENDL; + } + + } +} // This is the callback for when each script arrives // static @@ -441,36 +449,21 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, std::string buffer; if(queue && (0 == status)) { - //LL_INFOS() << "ITEM NAME 3: " << data->mScriptName << LL_ENDL; - - // Dump this into a file on the local disk so we can compile it. - std::string filename; - LLVFile file(vfs, asset_id, type); - std::string uuid_str; - asset_id.toString(uuid_str); - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + llformat(".%s",LLAssetType::lookup(type)); - - const bool is_running = true; - LLViewerObject* object = gObjectList.findObject(data->mTaskId); - if (object) - { - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - if(!url.empty()) - { - // Read script source in to buffer. - U32 script_size = file.getSize(); - U8* script_data = new U8[script_size]; - file.read(script_data, script_size); - - queue->mUploadQueue->queue(filename, data->mTaskId, - data->mItem->getUUID(), is_running, queue->mMono, queue->getKey().asUUID(), - script_data, script_size, data->mItem->getName(), data->mExperienceId); - } - else - { - buffer = LLTrans::getString("CompileQueueServiceUnavailable") + (": ") + data->mItem->getName(); - } - } + LLViewerObject* object = gObjectList.findObject(data->mTaskId); + if (object) + { + std::string url = object->getRegion()->getCapability("UpdateScriptTask"); + std::string scriptName = data->mItem->getName(); + + LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLFloaterCompileQueue::finishLSLUpload, _1, _2, _3, _4, + scriptName, data->mQueueID); + + LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(data->mTaskId, data->mItem->getUUID(), asset_id, + (queue->mMono) ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, + true, scriptName, data->mQueueID, data->mExperienceId, proc)); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } } else { @@ -653,14 +646,29 @@ BOOL LLFloaterCompileQueue::startQueue() std::string lookup_url=region->getCapability("GetCreatorExperiences"); if(!lookup_url.empty()) { - LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(getKey().asUUID())); - return TRUE; + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success = + boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, _1, getKey().asUUID()); + + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t failure = + boost::bind(&LLFloaterCompileQueue::processExperienceIdResults, LLSD(), getKey().asUUID()); + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, + success, failure); + return TRUE; } } return nextObject(); } +/*static*/ +void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID parent) +{ + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", parent); + if (!queue) + return; + queue->experienceIdsReceived(result["experience_ids"]); +} void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t* inv) diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 54842bb302..cee8efe9b0 100755 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -118,8 +118,6 @@ struct LLCompileQueueData mQueueID(q_id), mItemId(item_id) {} }; -class LLAssetUploadQueue; - class LLFloaterCompileQueue : public LLFloaterScriptQueue { friend class LLFloaterReg; @@ -131,8 +129,6 @@ public: // remove any object in mScriptScripts with the matching uuid. void removeItemByItemID(const LLUUID& item_id); - LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; } - void experienceIdsReceived( const LLSD& content ); BOOL hasExperience(const LLUUID& id)const; @@ -147,6 +143,8 @@ protected: static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience); + static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, std::string scriptName, LLUUID queueId); + // This is the callback for when each script arrives static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id, LLAssetType::EType type, @@ -157,7 +155,8 @@ protected: LLViewerInventoryItem::item_array_t mCurrentScripts; private: - LLAssetUploadQueue* mUploadQueue; + static void processExperienceIdResults(LLSD result, LLUUID parent); + uuid_list_t mExperienceIds; }; diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 821d58a9b2..f828b56f7f 100755 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1600,6 +1600,14 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* for (U32 j = 0; j < count; ++j) { LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); + if (!joint) + { + joint = avatar->getJoint("mPelvis"); + } + if (!joint) + { + LL_DEBUGS("Avatar") << "Failed to find " << skin->mJointNames[j] << LL_ENDL; + } if (joint) { mat[j] = skin->mInvBindMatrix[j]; diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 78d619a315..8f2eb41307 100755 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -29,7 +29,6 @@ #include "llestateinfomodel.h" // libs -#include "llhttpclient.h" #include "llregionflags.h" #include "message.h" @@ -38,6 +37,8 @@ #include "llfloaterregioninfo.h" // for invoice id #include "llviewerregion.h" +#include "llcorehttputil.h" + LLEstateInfoModel::LLEstateInfoModel() : mID(0) , mFlags(0) @@ -110,24 +111,6 @@ void LLEstateInfoModel::notifyCommit() //== PRIVATE STUFF ============================================================ -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLEstateChangeInfoResponder); -protected: - // if we get a normal response, handle it here - virtual void httpSuccesss() - { - LL_INFOS() << "Committed estate info" << LL_ENDL; - LLEstateInfoModel::instance().notifyCommit(); - } - - // if we get an error response - virtual void httpFailure() - { - LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL; - } -}; - // tries to send estate info using a cap; returns true if it succeeded bool LLEstateInfoModel::commitEstateInfoCaps() { @@ -139,29 +122,53 @@ bool LLEstateInfoModel::commitEstateInfoCaps() return false; } - LLSD body; - body["estate_name" ] = getName(); - body["sun_hour" ] = getSunHour(); + LLCoros::instance().launch("LLEstateInfoModel::commitEstateInfoCapsCoro", + boost::bind(&LLEstateInfoModel::commitEstateInfoCapsCoro, this, url)); - body["is_sun_fixed" ] = getUseFixedSun(); - body["is_externally_visible"] = getIsExternallyVisible(); - body["allow_direct_teleport"] = getAllowDirectTeleport(); - body["deny_anonymous" ] = getDenyAnonymous(); - body["deny_age_unverified" ] = getDenyAgeUnverified(); - body["allow_voice_chat" ] = getAllowVoiceChat(); - - body["invoice" ] = LLFloaterRegionInfo::getLastInvoice(); - - LL_DEBUGS("Windlight Sync") << "Sending estate caps: " - << "is_sun_fixed = " << getUseFixedSun() - << ", sun_hour = " << getSunHour() << LL_ENDL; - LL_DEBUGS() << body << LL_ENDL; - - // we use a responder so that we can re-get the data after committing to the database - LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder); return true; } +void LLEstateInfoModel::commitEstateInfoCapsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EstateChangeInfo", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD body; + body["estate_name"] = getName(); + body["sun_hour"] = getSunHour(); + + body["is_sun_fixed"] = getUseFixedSun(); + body["is_externally_visible"] = getIsExternallyVisible(); + body["allow_direct_teleport"] = getAllowDirectTeleport(); + body["deny_anonymous"] = getDenyAnonymous(); + body["deny_age_unverified"] = getDenyAgeUnverified(); + body["allow_voice_chat"] = getAllowVoiceChat(); + + body["invoice"] = LLFloaterRegionInfo::getLastInvoice(); + + LL_DEBUGS("Windlight Sync") << "Sending estate caps: " + << "is_sun_fixed = " << getUseFixedSun() + << ", sun_hour = " << getSunHour() << LL_ENDL; + LL_DEBUGS() << body << LL_ENDL; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, body); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status) + { + LL_INFOS() << "Committed estate info" << LL_ENDL; + LLEstateInfoModel::instance().notifyCommit(); + } + else + { + LL_WARNS() << "Failed to commit estate info " << LL_ENDL; + } +} + /* This is the old way of doing things, is deprecated, and should be deleted when the dataserver model can be removed */ // key = "estatechangeinfo" diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h index 538f2f7c75..fcfbd1ce7d 100755 --- a/indra/newview/llestateinfomodel.h +++ b/indra/newview/llestateinfomodel.h @@ -30,6 +30,8 @@ class LLMessageSystem; #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h" /** * Contains estate info, notifies interested parties of its changes. @@ -73,7 +75,6 @@ protected: friend class LLSingleton<LLEstateInfoModel>; friend class LLDispatchEstateUpdateInfo; - friend class LLEstateChangeInfoResponder; LLEstateInfoModel(); @@ -99,6 +100,8 @@ private: update_signal_t mUpdateSignal; /// emitted when we receive update from sim update_signal_t mCommitSignal; /// emitted when our update gets applied to sim + + void commitEstateInfoCapsCoro(std::string url); }; inline bool LLEstateInfoModel::getFlag(U64 flag) const diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 4de6ad4d2f..021d17251d 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -30,261 +30,248 @@ #include "llappviewer.h" #include "llagent.h" -#include "llhttpclient.h" -#include "llhttpconstants.h" #include "llsdserialize.h" #include "lleventtimer.h" #include "llviewerregion.h" #include "message.h" #include "lltrans.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +#include "lleventfilter.h" -namespace +namespace LLEventPolling { - // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. - // This means we attempt to recover relatively quickly but back off giving more time to recover - // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts. - const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout. - const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout. - const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules. - - class LLEventPollResponder : public LLHTTPClient::Responder - { - LOG_CLASS(LLEventPollResponder); - public: - - static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); - void stop(); - - void makeRequest(); - - /* virtual */ void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); - - private: - LLEventPollResponder(const std::string& pollURL, const LLHost& sender); - ~LLEventPollResponder(); - - - void handleMessage(const LLSD& content); - - /* virtual */ void httpFailure(); - /* virtual */ void httpSuccess(); - - private: - - bool mDone; - - std::string mPollURL; - std::string mSender; - - LLSD mAcknowledge; - - // these are only here for debugging so we can see which poller is which - static int sCount; - int mCount; - S32 mErrorCount; - }; - - class LLEventPollEventTimer : public LLEventTimer - { - typedef LLPointer<LLEventPollResponder> EventPollResponderPtr; - - public: - LLEventPollEventTimer(F32 period, EventPollResponderPtr responder) - : LLEventTimer(period), mResponder(responder) - { } - - virtual BOOL tick() - { - mResponder->makeRequest(); - return TRUE; // Causes this instance to be deleted. - } - - private: - - EventPollResponderPtr mResponder; - }; - - //static - LLHTTPClient::ResponderPtr LLEventPollResponder::start( - const std::string& pollURL, const LLHost& sender) - { - LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender); - LL_INFOS() << "LLEventPollResponder::start <" << sCount << "> " - << pollURL << LL_ENDL; - return result; - } - - void LLEventPollResponder::stop() - { - LL_INFOS() << "LLEventPollResponder::stop <" << mCount << "> " - << mPollURL << LL_ENDL; - // there should be a way to stop a LLHTTPClient request in progress - mDone = true; - } - - int LLEventPollResponder::sCount = 0; - - LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender) - : mDone(false), - mPollURL(pollURL), - mCount(++sCount), - mErrorCount(0) - { - //extract host and port of simulator to set as sender - LLViewerRegion *regionp = gAgent.getRegion(); - if (!regionp) - { - LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL; - } - mSender = sender.getIPandPort(); - LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL; - makeRequest(); - } - - LLEventPollResponder::~LLEventPollResponder() - { - stop(); - LL_DEBUGS() << "LLEventPollResponder::~Impl <" << mCount << "> " - << mPollURL << LL_ENDL; - } - - // virtual - void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - if (getStatus() == HTTP_BAD_GATEWAY) - { - // These errors are not parsable as LLSD, - // which LLHTTPClient::Responder::completedRaw will try to do. - httpCompleted(); - } - else - { - LLHTTPClient::Responder::completedRaw(channels,buffer); - } - } - - void LLEventPollResponder::makeRequest() - { - LLSD request; - request["ack"] = mAcknowledge; - request["done"] = mDone; - - LL_DEBUGS() << "LLEventPollResponder::makeRequest <" << mCount << "> ack = " - << LLSDXMLStreamer(mAcknowledge) << LL_ENDL; - LLHTTPClient::post(mPollURL, request, this); - } - - void LLEventPollResponder::handleMessage(const LLSD& content) - { - std::string msg_name = content["message"]; - LLSD message; - message["sender"] = mSender; - message["body"] = content["body"]; - LLMessageSystem::dispatch(msg_name, message); - } - - //virtual - void LLEventPollResponder::httpFailure() - { - if (mDone) return; - - // A HTTP_BAD_GATEWAY (502) error is our standard timeout response - // we get this when there are no events. - if ( getStatus() == HTTP_BAD_GATEWAY ) - { - mErrorCount = 0; - makeRequest(); - } - else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS) - { - ++mErrorCount; - - // The 'tick' will return TRUE causing the timer to delete this. - new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS - + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC - , this); - - LL_WARNS() << dumpResponse() << LL_ENDL; - } - else - { - LL_WARNS() << dumpResponse() - << " [count:" << mCount << "] " - << (mDone ? " -- done" : "") << LL_ENDL; - stop(); - - // At this point we have given up and the viewer will not receive HTTP messages from the simulator. - // IMs, teleports, about land, selecing land, region crossing and more will all fail. - // They are essentially disconnected from the region even though some things may still work. - // Since things won't get better until they relog we force a disconnect now. - - // *NOTE:Mani - The following condition check to see if this failing event poll - // is attached to the Agent's main region. If so we disconnect the viewer. - // Else... its a child region and we just leave the dead event poll stopped and - // continue running. - if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender) - { - LL_WARNS() << "Forcing disconnect due to stalled main region event poll." << LL_ENDL; - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection")); - } - } - } - - //virtual - void LLEventPollResponder::httpSuccess() - { - LL_DEBUGS() << "LLEventPollResponder::result <" << mCount << ">" - << (mDone ? " -- done" : "") << LL_ENDL; - - if (mDone) return; - - mErrorCount = 0; - - const LLSD& content = getContent(); - if (!content.isMap() || - !content.get("events") || - !content.get("id")) - { - LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL; - makeRequest(); - return; - } - - mAcknowledge = content["id"]; - LLSD events = content["events"]; - - if(mAcknowledge.isUndefined()) - { - LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL; - } - - // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG - LL_DEBUGS() << "LLEventPollResponder::httpSuccess <" << mCount << "> " << events.size() << "events (id " - << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; - - LLSD::array_const_iterator i = events.beginArray(); - LLSD::array_const_iterator end = events.endArray(); - for (; i != end; ++i) - { - if (i->has("message")) - { - handleMessage(*i); - } - } - - makeRequest(); - } +namespace Details +{ + + class LLEventPollImpl + { + public: + LLEventPollImpl(const LLHost &sender); + + void start(const std::string &url); + void stop(); + + private: + // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error. + // This means we attempt to recover relatively quickly but back off giving more time to recover + // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts. + static const F32 EVENT_POLL_ERROR_RETRY_SECONDS; + static const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC; + static const S32 MAX_EVENT_POLL_HTTP_ERRORS; + + void eventPollCoro(std::string url); + + void handleMessage(const LLSD &content); + + bool mDone; + LLCore::HttpRequest::ptr_t mHttpRequest; + LLCore::HttpRequest::policy_t mHttpPolicy; + std::string mSenderIp; + int mCounter; + LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mAdapter; + + static int sNextCounter; + }; + + + const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout. + const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout. + const S32 LLEventPollImpl::MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules. + + int LLEventPollImpl::sNextCounter = 1; + + + LLEventPollImpl::LLEventPollImpl(const LLHost &sender) : + mDone(false), + mHttpRequest(), + mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mSenderIp(), + mCounter(sNextCounter++) + + { + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest); + mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL); + mSenderIp = sender.getIPandPort(); + } + + void LLEventPollImpl::handleMessage(const LLSD& content) + { + std::string msg_name = content["message"]; + LLSD message; + message["sender"] = mSenderIp; + message["body"] = content["body"]; + LLMessageSystem::dispatch(msg_name, message); + } + + void LLEventPollImpl::start(const std::string &url) + { + if (!url.empty()) + { + std::string coroname = + LLCoros::instance().launch("LLEventPollImpl::eventPollCoro", + boost::bind(&LLEventPollImpl::eventPollCoro, this, url)); + LL_INFOS("LLEventPollImpl") << coroname << " with url '" << url << LL_ENDL; + } + } + + void LLEventPollImpl::stop() + { + LL_INFOS() << "requesting stop for event poll coroutine <" << mCounter << ">" << LL_ENDL; + mDone = true; + + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter = mAdapter.lock(); + if (adapter) + { + // cancel the yielding operation if any. + adapter->cancelSuspendedOperation(); + } + } + + void LLEventPollImpl::eventPollCoro(std::string url) + { + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EventPoller", mHttpPolicy)); + LLSD acknowledge; + int errorCount = 0; + int counter = mCounter; // saved on the stack for logging. + + LL_INFOS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL; + + mAdapter = httpAdapter; + + // continually poll for a server update until we've been flagged as + // finished + while (!mDone) + { + LLSD request; + request["ack"] = acknowledge; + request["done"] = mDone; + +// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = " +// << LLSDXMLStreamer(request) << LL_ENDL; + + LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL; + LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request); + +// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = " +// << LLSDXMLStreamer(result) << LL_ENDL; + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if (status == LLCore::HttpStatus(HTTP_BAD_GATEWAY)) + { // A HTTP_BAD_GATEWAY (502) error is our standard timeout response + // we get this when there are no events. + errorCount = 0; + continue; + } + else if ((status == LLCore::HttpStatus(LLCore::HttpStatus::LLCORE, LLCore::HE_OP_CANCELED)) || + (status == LLCore::HttpStatus(HTTP_NOT_FOUND))) + { // Event polling for this server has been canceled. In + // some cases the server gets ahead of the viewer and will + // return a 404 error (Not Found) before the cancel event + // comes back in the queue + LL_WARNS() << "Canceling coroutine" << LL_ENDL; + break; + } + LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code " + << status.toTerseString() << ": '" << httpResults["message"] << "'" << LL_ENDL; + + if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS) + { // An unanticipated error has been received from our poll + // request. Calculate a timeout and wait for it to expire(sleep) + // before trying again. The sleep time is increased by 5 seconds + // for each consecutive error. + LLEventTimeout timeout; + ++errorCount; + + F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS + + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC; + + LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry << + " seconds, error count is now " << errorCount << LL_ENDL; + + timeout.eventAfter(waitToRetry, LLSD()); + llcoro::suspendUntilEventOn(timeout); + + if (mDone) + break; + LL_INFOS("LLEventPollImpl") << "<" << counter << "> About to retry request." << LL_ENDL; + continue; + } + else + { + // At this point we have given up and the viewer will not receive HTTP messages from the simulator. + // IMs, teleports, about land, selecting land, region crossing and more will all fail. + // They are essentially disconnected from the region even though some things may still work. + // Since things won't get better until they relog we force a disconnect now. + mDone = true; + + // *NOTE:Mani - The following condition check to see if this failing event poll + // is attached to the Agent's main region. If so we disconnect the viewer. + // Else... its a child region and we just leave the dead event poll stopped and + // continue running. + if (gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSenderIp) + { + LL_WARNS("LLEventPollImpl") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL; + LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection")); + } + break; + } + } + + errorCount = 0; + + if (!result.isMap() || + !result.get("events") || + !result.get("id")) + { + LL_WARNS("LLEventPollImpl") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL; + continue; + } + + acknowledge = result["id"]; + LLSD events = result["events"]; + + if (acknowledge.isUndefined()) + { + LL_WARNS("LLEventPollImpl") << " id undefined" << LL_ENDL; + } + + // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG + LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL; + + LLSD::array_const_iterator i = events.beginArray(); + LLSD::array_const_iterator end = events.endArray(); + for (; i != end; ++i) + { + if (i->has("message")) + { + handleMessage(*i); + } + } + } + LL_INFOS("LLEventPollImpl") << " <" << counter << "> Leaving coroutine." << LL_ENDL; + } + +} } -LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender) - : mImpl(LLEventPollResponder::start(poll_url, sender)) - { } +LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender): + mImpl() +{ + mImpl = boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl> + (new LLEventPolling::Details::LLEventPollImpl(sender)); + mImpl->start(poll_url); +} LLEventPoll::~LLEventPoll() { - LLHTTPClient::Responder* responderp = mImpl.get(); - LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp); - if (event_poll_responder) event_poll_responder->stop(); + mImpl->stop(); + } diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h index e8d98062aa..e2afd9226b 100755 --- a/indra/newview/lleventpoll.h +++ b/indra/newview/lleventpoll.h @@ -27,10 +27,23 @@ #ifndef LL_LLEVENTPOLL_H #define LL_LLEVENTPOLL_H -#include "llhttpclient.h" +#include "boost/move/unique_ptr.hpp" + +namespace boost +{ + using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace. +} class LLHost; +namespace LLEventPolling +{ +namespace Details +{ + class LLEventPollImpl; +} +} + class LLEventPoll ///< implements the viewer side of server-to-viewer pushed events. @@ -40,11 +53,11 @@ public: ///< Start polling the URL. virtual ~LLEventPoll(); - ///< will stop polling, cancelling any poll in progress. + ///< will stop polling, canceling any poll in progress. private: - LLHTTPClient::ResponderPtr mImpl; + boost::unique_ptr<LLEventPolling::Details::LLEventPollImpl> mImpl; }; diff --git a/indra/newview/llexperienceassociationresponder.cpp b/indra/newview/llexperienceassociationresponder.cpp deleted file mode 100644 index b50c81eedc..0000000000 --- a/indra/newview/llexperienceassociationresponder.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file llexperienceassociationresponder.cpp - * @brief llexperienceassociationresponder implementation. This class combines - * a lookup for a script association and an experience details request. The first - * is always async, but the second may be cached locally. - * - * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2013, 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 "llexperienceassociationresponder.h" -#include "llexperiencecache.h" -#include "llviewerregion.h" -#include "llagent.h" - -ExperienceAssociationResponder::ExperienceAssociationResponder(ExperienceAssociationResponder::callback_t callback):mCallback(callback) -{ - ref(); -} - -void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& object_id, const LLUUID& item_id, callback_t callback ) -{ - LLSD request; - request["object-id"]=object_id; - request["item-id"]=item_id; - fetchAssociatedExperience(request, callback); -} - -void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback) -{ - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string lookup_url=region->getCapability("GetMetadata"); - if(!lookup_url.empty()) - { - LLSD fields; - fields.append("experience"); - request["fields"] = fields; - LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(callback)); - } - } -} - -void ExperienceAssociationResponder::httpFailure() -{ - LLSD msg; - msg["error"]=(LLSD::Integer)getStatus(); - msg["message"]=getReason(); - LL_INFOS("ExperienceAssociation") << "Failed to look up associated experience: " << getStatus() << ": " << getReason() << LL_ENDL; - - sendResult(msg); - -} -void ExperienceAssociationResponder::httpSuccess() -{ - if(!getContent().has("experience")) - { - - LLSD msg; - msg["message"]="no experience"; - msg["error"]=-1; - sendResult(msg); - return; - } - - LLExperienceCache::get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1)); - -} - -void ExperienceAssociationResponder::sendResult( const LLSD& experience ) -{ - mCallback(experience); - unref(); -} - - - diff --git a/indra/newview/llexperienceassociationresponder.h b/indra/newview/llexperienceassociationresponder.h deleted file mode 100644 index 2bdc3d251b..0000000000 --- a/indra/newview/llexperienceassociationresponder.h +++ /dev/null @@ -1,58 +0,0 @@ -#include "llhttpclient.h" -#include "llsd.h" -/** - * @file llexperienceassociationresponder.h - * @brief llexperienceassociationresponder and related class definitions - * - * $LicenseInfo:firstyear=2013&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2013, 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$ - */ - - - -#ifndef LL_LLEXPERIENCEASSOCIATIONRESPONDER_H -#define LL_LLEXPERIENCEASSOCIATIONRESPONDER_H - -#include "llhttpclient.h" -#include "llsd.h" - -class ExperienceAssociationResponder : public LLHTTPClient::Responder -{ -public: - typedef boost::function<void(const LLSD& experience)> callback_t; - - ExperienceAssociationResponder(callback_t callback); - - /*virtual*/ void httpSuccess(); - /*virtual*/ void httpFailure(); - - static void fetchAssociatedExperience(const LLUUID& object_it, const LLUUID& item_id, callback_t callback); - -private: - static void fetchAssociatedExperience(LLSD& request, callback_t callback); - - void sendResult(const LLSD& experience); - - callback_t mCallback; - -}; - -#endif // LL_LLEXPERIENCEASSOCIATIONRESPONDER_H diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index 28319564e4..1de4102dba 100755 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -34,7 +34,6 @@ #include "llagent.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llcommandhandler.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llurlaction.h" #include "llimagepng.h" @@ -42,9 +41,11 @@ #include "lltrans.h" #include "llevents.h" #include "llviewerregion.h" +#include "llviewercontrol.h" #include "llfloaterwebcontent.h" #include "llfloaterreg.h" +#include "llcorehttputil.h" boost::scoped_ptr<LLEventPump> LLFacebookConnect::sStateWatcher(new LLEventStream("FacebookConnectState")); boost::scoped_ptr<LLEventPump> LLFacebookConnect::sInfoWatcher(new LLEventStream("FacebookConnectInfo")); @@ -67,6 +68,24 @@ void toast_user_for_facebook_success() LLNotificationsUtil::add("FacebookConnect", args); } +LLCore::HttpHeaders::ptr_t get_headers() +{ + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + // The DebugSlshareLogTag mechanism is intended to trigger slshare-service + // debug logging. slshare-service is coded to respond to an X-debug-tag + // header by engaging debug logging for that request only. This way a + // developer need not muck with the slshare-service image to engage debug + // logging. Moreover, the value of X-debug-tag is embedded in each such + // log line so the developer can quickly find the log lines pertinent to + // THIS session. + std::string logtag(gSavedSettings.getString("DebugSlshareLogTag")); + if (! logtag.empty()) + { + httpHeaders->append("X-debug-tag", logtag); + } + return httpHeaders; +} + /////////////////////////////////////////////////////////////////////////////// // class LLFacebookConnectHandler : public LLCommandHandler @@ -125,266 +144,349 @@ LLFacebookConnectHandler gFacebookConnectHandler; /////////////////////////////////////////////////////////////////////////////// // -class LLFacebookConnectResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectCoro(std::string authCode, std::string authState) { - LOG_CLASS(LLFacebookConnectResponder); -public: - - LLFacebookConnectResponder() + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + LLSD putData; + if (!authCode.empty()) { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + putData["code"] = authCode; + } + if (!authState.empty()) + { + putData["state"] = authState; } - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); - } - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFacebookConnect::instance().openFacebookWeb(location); - } - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); - const LLSD& content = getContent(); - log_facebook_connect_error("Connect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->putAndSuspend(httpRequest, getFacebookConnectURL("/connection"), putData, httpOpts, get_headers()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFacebookWeb(location); + } + } + } + else + { + LL_INFOS("FacebookConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_CONNECTED); + } + +} /////////////////////////////////////////////////////////////////////////////// // -class LLFacebookShareResponder : public LLHTTPClient::Responder +bool LLFacebookConnect::testShareStatus(LLSD &result) { - LOG_CLASS(LLFacebookShareResponder); -public: - - LLFacebookShareResponder() - { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING); - } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - /* virtual */ void httpSuccess() - { - toast_user_for_facebook_success(); - LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); - } + if (status) + return true; - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFacebookConnect::instance().openFacebookWeb(location); - } - } - else if ( HTTP_NOT_FOUND == getStatus() ) - { - LLFacebookConnect::instance().connectToFacebook(); - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); - const LLSD& content = getContent(); - log_facebook_connect_error("Share", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFacebookWeb(location); + } + } + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL; + connectToFacebook(); + } + else + { + LL_WARNS("FacebookConnect") << "HTTP Status error " << status.toString() << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_POST_FAILED); + log_facebook_connect_error("Share", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + return false; +} -/////////////////////////////////////////////////////////////////////////////// -// -class LLFacebookDisconnectResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookShareCoro(std::string route, LLSD share) { - LOG_CLASS(LLFacebookDisconnectResponder); -public: - - LLFacebookDisconnectResponder() - { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECTING); - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - void setUserDisconnected() - { - // Clear data - LLFacebookConnect::instance().clearInfo(); - LLFacebookConnect::instance().clearContent(); - //Notify state change - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); - } + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } + LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), share, httpOpts, get_headers()); - /* virtual */ void httpFailure() - { - //User not found so already disconnected - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); - const LLSD& content = getContent(); - log_facebook_connect_error("Disconnect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + if (testShareStatus(result)) + { + toast_user_for_facebook_success(); + LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_POSTED); + } +} + +void LLFacebookConnect::facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(get_headers()); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + std::string imageFormat; + if (dynamic_cast<LLImagePNG*>(image.get())) + { + imageFormat = "png"; + } + else if (dynamic_cast<LLImageJPEG*>(image.get())) + { + imageFormat = "jpg"; + } + else + { + LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; + return; + } + + // All this code is mostly copied from LLWebProfile::post() + static const std::string boundary = "----------------------------0123abcdefab"; + + std::string contentType = "multipart/form-data; boundary=" + boundary; + httpHeaders->append("Content-Type", contentType.c_str()); + + LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); // + LLCore::BufferArrayStream body(raw.get()); + + // *NOTE: The order seems to matter. + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"caption\"\r\n\r\n" + << caption << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" + << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + + // Insert the image data. + // *FIX: Treating this as a string will probably screw it up ... + U8* image_data = image->getData(); + for (S32 i = 0; i < image->getDataSize(); ++i) + { + body << image_data[i]; + } + + body << "\r\n--" << boundary << "--\r\n"; + + setConnectionState(LLFacebookConnect::FB_POSTING); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, getFacebookConnectURL(route, true), raw, httpOpts, httpHeaders); + + if (testShareStatus(result)) + { + toast_user_for_facebook_success(); + LL_DEBUGS("FacebookConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_POSTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLFacebookConnectedResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookDisconnectCoro() { - LOG_CLASS(LLFacebookConnectedResponder); -public: - - LLFacebookConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFacebookConnectURL("/connection"), httpOpts, get_headers()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status && (status != LLCore::HttpStatus(HTTP_FOUND))) + { + LL_WARNS("FacebookConnect") << "Failed to disconnect:" << status.toTerseString() << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); + log_facebook_connect_error("Disconnect", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + LL_DEBUGS("FacebookConnect") << "Facebook Disconnect successful. " << LL_ENDL; + clearInfo(); + clearContent(); + //Notify state change + setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); } - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); - } +} - /* virtual */ void httpFailure() - { - // show the facebook login page if not connected yet - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL; - if (mAutoConnect) - { - LLFacebookConnect::instance().connectToFacebook(); - } - else - { - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); - } - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); - const LLSD& content = getContent(); - log_facebook_connect_error("Connected", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } - -private: - bool mAutoConnect; -}; +/////////////////////////////////////////////////////////////////////////////// +// +void LLFacebookConnect::facebookConnectedCheckCoro(bool autoConnect) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/connection", true), httpOpts, get_headers()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if ( status == LLCore::HttpStatus(HTTP_NOT_FOUND) ) + { + LL_DEBUGS("FacebookConnect") << "Not connected. " << LL_ENDL; + if (autoConnect) + { + connectToFacebook(); + } + else + { + setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); + } + } + else + { + LL_WARNS("FacebookConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + + setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); + log_facebook_connect_error("Connected", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + } + else + { + LL_DEBUGS("FacebookConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLFacebookConnect::FB_CONNECTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLFacebookInfoResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectInfoCoro() { - LOG_CLASS(LLFacebookInfoResponder); -public: + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - /* virtual */ void httpSuccess() - { - LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; - LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().storeInfo(getContent()); - } + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFacebookConnect::instance().openFacebookWeb(location); - } - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - const LLSD& content = getContent(); - log_facebook_connect_error("Info", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/info", true), httpOpts, get_headers()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFacebookWeb(location); + } + } + else if (!status) + { + LL_WARNS("FacebookConnect") << "Facebook Info failed: " << status.toString() << LL_ENDL; + log_facebook_connect_error("Info", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + storeInfo(result); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLFacebookFriendsResponder : public LLHTTPClient::Responder +void LLFacebookConnect::facebookConnectFriendsCoro() { - LOG_CLASS(LLFacebookFriendsResponder); -public: - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL; - LLFacebookConnect::instance().storeContent(getContent()); - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FacebookConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFacebookConnect::instance().openFacebookWeb(location); - } - } - else - { - LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; - const LLSD& content = getContent(); - log_facebook_connect_error("Friends", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getFacebookConnectURL("/friends", true), httpOpts, get_headers()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FacebookConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFacebookWeb(location); + } + } + else if (!status) + { + LL_WARNS("FacebookConnect") << "Facebook Friends failed: " << status.toString() << LL_ENDL; + log_facebook_connect_error("Info", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_INFOS("FacebookConnect") << "Facebook: Friends received" << LL_ENDL; + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + LLSD content = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; + storeContent(content); + } +} /////////////////////////////////////////////////////////////////////////////// // @@ -439,40 +541,32 @@ std::string LLFacebookConnect::getFacebookConnectURL(const std::string& route, b void LLFacebookConnect::connectToFacebook(const std::string& auth_code, const std::string& auth_state) { - LLSD body; - if (!auth_code.empty()) - { - body["code"] = auth_code; - } - if (!auth_state.empty()) - { - body["state"] = auth_state; - } - - LLHTTPClient::put(getFacebookConnectURL("/connection"), body, new LLFacebookConnectResponder()); + setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS); + + LLCoros::instance().launch("LLFacebookConnect::facebookConnectCoro", + boost::bind(&LLFacebookConnect::facebookConnectCoro, this, auth_code, auth_state)); } void LLFacebookConnect::disconnectFromFacebook() { - LLHTTPClient::del(getFacebookConnectURL("/connection"), new LLFacebookDisconnectResponder()); + LLCoros::instance().launch("LLFacebookConnect::facebookDisconnectCoro", + boost::bind(&LLFacebookConnect::facebookDisconnectCoro, this)); } void LLFacebookConnect::checkConnectionToFacebook(bool auto_connect) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getFacebookConnectURL("/connection", true), new LLFacebookConnectedResponder(auto_connect), - LLSD(), timeout, follow_redirects); + setConnectionState(LLFacebookConnect::FB_DISCONNECTING); + + LLCoros::instance().launch("LLFacebookConnect::facebookConnectedCheckCoro", + boost::bind(&LLFacebookConnect::facebookConnectedCheckCoro, this, auto_connect)); } void LLFacebookConnect::loadFacebookInfo() { if(mRefreshInfo) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getFacebookConnectURL("/info", true), new LLFacebookInfoResponder(), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLFacebookConnect::facebookConnectInfoCoro", + boost::bind(&LLFacebookConnect::facebookConnectInfoCoro, this)); } } @@ -480,15 +574,16 @@ void LLFacebookConnect::loadFacebookFriends() { if(mRefreshContent) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getFacebookConnectURL("/friends", true), new LLFacebookFriendsResponder(), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLFacebookConnect::facebookConnectFriendsCoro", + boost::bind(&LLFacebookConnect::facebookConnectFriendsCoro, this)); } } -void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, const std::string& description, const std::string& image, const std::string& message) +void LLFacebookConnect::postCheckin(const std::string& location, const std::string& name, + const std::string& description, const std::string& image, const std::string& message) { + setConnectionState(LLFacebookConnect::FB_POSTING); + LLSD body; if (!location.empty()) { @@ -511,80 +606,39 @@ void LLFacebookConnect::postCheckin(const std::string& location, const std::stri body["message"] = message; } - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getFacebookConnectURL("/share/checkin", true), body, new LLFacebookShareResponder()); + LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", + boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/checkin", body)); } void LLFacebookConnect::sharePhoto(const std::string& image_url, const std::string& caption) { + setConnectionState(LLFacebookConnect::FB_POSTING); + LLSD body; body["image"] = image_url; body["caption"] = caption; - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getFacebookConnectURL("/share/photo", true), body, new LLFacebookShareResponder()); + LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", + boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/photo", body)); } void LLFacebookConnect::sharePhoto(LLPointer<LLImageFormatted> image, const std::string& caption) { - std::string imageFormat; - if (dynamic_cast<LLImagePNG*>(image.get())) - { - imageFormat = "png"; - } - else if (dynamic_cast<LLImageJPEG*>(image.get())) - { - imageFormat = "jpg"; - } - else - { - LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; - return; - } - - // All this code is mostly copied from LLWebProfile::post() - const std::string boundary = "----------------------------0123abcdefab"; - - LLSD headers; - headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; - - std::ostringstream body; - - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"caption\"\r\n\r\n" - << caption << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" - << "Content-Type: image/" << imageFormat << "\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } + setConnectionState(LLFacebookConnect::FB_POSTING); - body << "\r\n--" << boundary << "--\r\n"; - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::postRaw(getFacebookConnectURL("/share/photo", true), data, size, new LLFacebookShareResponder(), headers); + LLCoros::instance().launch("LLFacebookConnect::facebookShareImageCoro", + boost::bind(&LLFacebookConnect::facebookShareImageCoro, this, "/share/photo", image, caption)); } void LLFacebookConnect::updateStatus(const std::string& message) { LLSD body; body["message"] = message; - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getFacebookConnectURL("/share/wall", true), body, new LLFacebookShareResponder()); + + setConnectionState(LLFacebookConnect::FB_POSTING); + + LLCoros::instance().launch("LLFacebookConnect::facebookShareCoro", + boost::bind(&LLFacebookConnect::facebookShareCoro, this, "/share/wall", body)); } void LLFacebookConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/llfacebookconnect.h b/indra/newview/llfacebookconnect.h index c157db2178..2a2cdb5499 100644 --- a/indra/newview/llfacebookconnect.h +++ b/indra/newview/llfacebookconnect.h @@ -30,6 +30,8 @@ #include "llsingleton.h" #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLEventPump; @@ -101,6 +103,15 @@ private: static boost::scoped_ptr<LLEventPump> sStateWatcher; static boost::scoped_ptr<LLEventPump> sInfoWatcher; static boost::scoped_ptr<LLEventPump> sContentWatcher; + + bool testShareStatus(LLSD &results); + void facebookConnectCoro(std::string authCode, std::string authState); + void facebookConnectedCheckCoro(bool autoConnect); + void facebookDisconnectCoro(); + void facebookShareCoro(std::string route, LLSD share); + void facebookShareImageCoro(std::string route, LLPointer<LLImageFormatted> image, std::string caption); + void facebookConnectInfoCoro(); + void facebookConnectFriendsCoro(); }; #endif // LL_LLFACEBOOKCONNECT_H diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index ea39f812fd..f08064d9b5 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,7 +40,6 @@ #include "llappviewer.h" #include "llbufferstream.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llviewercontrol.h" #include "llworld.h" @@ -55,6 +54,7 @@ #include "llviewershadermgr.h" #include "llstring.h" #include "stringize.h" +#include "llcorehttputil.h" #if LL_WINDOWS #include "lldxhardware.h" @@ -492,95 +492,70 @@ bool LLFeatureManager::loadGPUClass() return true; // indicates that a gpu value was established } - -// responder saves table into file -class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder +void LLFeatureManager::fetchFeatureTableCoro(std::string tableName) { - LOG_CLASS(LLHTTPFeatureTableResponder); -public: + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FeatureManagerHTTPTable", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLHTTPFeatureTableResponder(std::string filename) : - mFilename(filename) - { - } + const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - if (isGoodStatus()) - { - // write to file - - LL_INFOS() << "writing feature table to " << mFilename << LL_ENDL; - - S32 file_size = buffer->countAfter(channels.in(), NULL); - if (file_size > 0) - { - // read from buffer - U8* copy_buffer = new U8[file_size]; - buffer->readAfter(channels.in(), NULL, copy_buffer, file_size); - - // write to file - LLAPRFile out(mFilename, LL_APR_WB); - out.write(copy_buffer, file_size); - out.close(); - } - } - else - { - char body[1025]; - body[1024] = '\0'; - LLBufferStream istr(channels, buffer.get()); - istr.get(body,1024); - if (strlen(body) > 0) - { - mContent["body"] = body; - } - LL_WARNS() << dumpResponse() << LL_ENDL; - } - } - -private: - std::string mFilename; -}; - -void fetch_feature_table(std::string table) -{ - const std::string base = gSavedSettings.getString("FeatureManagerHTTPTable"); #if LL_WINDOWS - std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); - std::string filename; - if (os_string.find("Microsoft Windows XP") == 0) - { - filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); - } - else - { - filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str()); - } + std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + std::string filename; + + if (os_string.find("Microsoft Windows XP") == 0) + { + filename = llformat(tableName.c_str(), "_xp", LLVersionInfo::getVersion().c_str()); + } + else + { + filename = llformat(tableName.c_str(), "", LLVersionInfo::getVersion().c_str()); + } #else - const std::string filename = llformat(table.c_str(), LLVersionInfo::getVersion().c_str()); + const std::string filename = llformat(tableName.c_str(), LLVersionInfo::getVersion().c_str()); #endif - const std::string url = base + "/" + filename; + std::string url = base + "/" + filename; + // testing url below + //url = "http://viewer-settings.secondlife.com/featuretable.2.1.1.208406.txt"; + const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - const std::string path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); - LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL; - - LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path)); -} + LL_INFOS() << "LLFeatureManager fetching " << url << " into " << path << LL_ENDL; + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status) + { // There was a newer feature table on the server. We've grabbed it and now should write it. + // write to file + const LLSD::Binary &raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); + LL_INFOS() << "writing feature table to " << path << LL_ENDL; + + S32 size = raw.size(); + if (size > 0) + { + // write to file + LLAPRFile out(path, LL_APR_WB); + out.write(raw.data(), size); + out.close(); + } + } +} // fetch table(s) from a website (S3) void LLFeatureManager::fetchHTTPTables() { - fetch_feature_table(FEATURE_TABLE_VER_FILENAME); + LLCoros::instance().launch("LLFeatureManager::fetchFeatureTableCoro", + boost::bind(&LLFeatureManager::fetchFeatureTableCoro, this, FEATURE_TABLE_VER_FILENAME)); } - void LLFeatureManager::cleanupFeatureTables() { std::for_each(mMaskList.begin(), mMaskList.end(), DeletePairedPointer()); diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 69078ccc21..12ea691b49 100755 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -32,6 +32,8 @@ #include "llsingleton.h" #include "llstring.h" #include <map> +#include "llcoros.h" +#include "lleventcoro.h" typedef enum EGPUClass { @@ -164,6 +166,7 @@ protected: void initBaseMask(); + void fetchFeatureTableCoro(std::string name); std::map<std::string, LLFeatureList *> mMaskList; std::set<std::string> mSkippedFeatures; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index ef50594feb..a7236d1778 100755 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -40,6 +40,10 @@ #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers #endif // LL_SDL +#if LL_LINUX || LL_SOLARIS +#include "llhttpconstants.h" // file picker uses some of thes constants on Linux +#endif + // // Globals // diff --git a/indra/newview/llflickrconnect.cpp b/indra/newview/llflickrconnect.cpp index b75660ea00..c0ca5b8cf8 100644 --- a/indra/newview/llflickrconnect.cpp +++ b/indra/newview/llflickrconnect.cpp @@ -32,7 +32,6 @@ #include "llagent.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llcommandhandler.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llurlaction.h" #include "llimagepng.h" @@ -43,6 +42,7 @@ #include "llfloaterwebcontent.h" #include "llfloaterreg.h" +#include "llcorehttputil.h" boost::scoped_ptr<LLEventPump> LLFlickrConnect::sStateWatcher(new LLEventStream("FlickrConnectState")); boost::scoped_ptr<LLEventPump> LLFlickrConnect::sInfoWatcher(new LLEventStream("FlickrConnectInfo")); @@ -67,228 +67,322 @@ void toast_user_for_flickr_success() /////////////////////////////////////////////////////////////////////////////// // -class LLFlickrConnectResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrConnectCoro(std::string requestToken, std::string oauthVerifier) { - LOG_CLASS(LLFlickrConnectResponder); -public: - - LLFlickrConnectResponder() + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD body; + if (!requestToken.empty()) + body["request_token"] = requestToken; + if (!oauthVerifier.empty()) + body["oauth_verifier"] = oauthVerifier; + + setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + + LLSD result = httpAdapter->putAndSuspend(httpRequest, getFlickrConnectURL("/connection"), body, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if ( status == LLCore::HttpStatus(HTTP_FOUND) ) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFlickrWeb(location); + } + } + else + { + LL_WARNS("FlickrConnect") << "Connection failed " << status.toString() << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); + log_flickr_connect_error("Connect", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + } + else { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); } - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFlickrConnect::instance().openFlickrWeb(location); - } - } - else - { - LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); - const LLSD& content = getContent(); - log_flickr_connect_error("Connect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; +} /////////////////////////////////////////////////////////////////////////////// // -class LLFlickrShareResponder : public LLHTTPClient::Responder +bool LLFlickrConnect::testShareStatus(LLSD &result) { - LOG_CLASS(LLFlickrShareResponder); -public: - - LLFlickrShareResponder() - { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTING); - } - - /* virtual */ void httpSuccess() - { + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status) + return true; + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFlickrWeb(location); + } + } + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; + connectToFlickr(); + } + else + { + LL_WARNS("FlickrConnect") << "HTTP Status error " << status.toString() << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); + log_flickr_connect_error("Share", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + return false; +} + +void LLFlickrConnect::flickrShareCoro(LLSD share) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), share, httpOpts); + + if (testShareStatus(result)) + { toast_user_for_flickr_success(); - LL_DEBUGS("FlickrConnect") << "Post successful. " << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POSTED); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFlickrConnect::instance().openFlickrWeb(location); - } - } - else if ( HTTP_NOT_FOUND == getStatus() ) - { - LLFlickrConnect::instance().connectToFlickr(); - } - else - { - LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_POST_FAILED); - const LLSD& content = getContent(); - log_flickr_connect_error("Share", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_POSTED); + } + +} + +void LLFlickrConnect::flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + std::string imageFormat; + if (dynamic_cast<LLImagePNG*>(image.get())) + { + imageFormat = "png"; + } + else if (dynamic_cast<LLImageJPEG*>(image.get())) + { + imageFormat = "jpg"; + } + else + { + LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; + return; + } + + // All this code is mostly copied from LLWebProfile::post() + const std::string boundary = "----------------------------0123abcdefab"; + + std::string contentType = "multipart/form-data; boundary=" + boundary; + httpHeaders->append("Content-Type", contentType.c_str()); + + LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); // + LLCore::BufferArrayStream body(raw.get()); + + // *NOTE: The order seems to matter. + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"title\"\r\n\r\n" + << title << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"description\"\r\n\r\n" + << description << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" + << tags << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" + << safetyLevel << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" + << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + + // Insert the image data. + // *FIX: Treating this as a string will probably screw it up ... + U8* image_data = image->getData(); + for (S32 i = 0; i < image->getDataSize(); ++i) + { + body << image_data[i]; + } + + body << "\r\n--" << boundary << "--\r\n"; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, getFlickrConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); + + if (testShareStatus(result)) + { + toast_user_for_flickr_success(); + LL_DEBUGS("FlickrConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_POSTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLFlickrDisconnectResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrDisconnectCoro() { - LOG_CLASS(LLFlickrDisconnectResponder); -public: - - LLFlickrDisconnectResponder() - { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - void setUserDisconnected() - { - // Clear data - LLFlickrConnect::instance().clearInfo(); + setConnectionState(LLFlickrConnect::FLICKR_DISCONNECTING); + httpOpts->setFollowRedirects(false); - //Notify state change - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); - } + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getFlickrConnectURL("/connection"), httpOpts); - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } - - /* virtual */ void httpFailure() - { - //User not found so already disconnected - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("FlickrConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } - else - { - LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); - const LLSD& content = getContent(); - log_flickr_connect_error("Disconnect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) + { + LL_WARNS("FlickrConnect") << "Disconnect failed!" << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_DISCONNECT_FAILED); + + log_flickr_connect_error("Disconnect", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_DEBUGS("FlickrConnect") << "Disconnect successful. " << LL_ENDL; + clearInfo(); + setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLFlickrConnectedResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrConnectedCoro(bool autoConnect) { - LOG_CLASS(LLFlickrConnectedResponder); -public: - - LLFlickrConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/connection", true), httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_IN_PROGRESS); + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + LL_DEBUGS("FlickrConnect") << "Not connected. " << LL_ENDL; + if (autoConnect) + { + connectToFlickr(); + } + else + { + setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); + } + } + else + { + LL_WARNS("FlickrConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + + setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); + log_flickr_connect_error("Connected", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + } + else + { + LL_DEBUGS("FlickrConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); } - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("FlickrConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTED); - } - - /* virtual */ void httpFailure() - { - // show the facebook login page if not connected yet - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("FlickrConnect") << "Not connected. " << dumpResponse() << LL_ENDL; - if (mAutoConnect) - { - LLFlickrConnect::instance().connectToFlickr(); - } - else - { - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_NOT_CONNECTED); - } - } - else - { - LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().setConnectionState(LLFlickrConnect::FLICKR_CONNECTION_FAILED); - const LLSD& content = getContent(); - log_flickr_connect_error("Connected", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } - -private: - bool mAutoConnect; -}; + +} /////////////////////////////////////////////////////////////////////////////// // -class LLFlickrInfoResponder : public LLHTTPClient::Responder +void LLFlickrConnect::flickrInfoCoro() { - LOG_CLASS(LLFlickrInfoResponder); -public: + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - /* virtual */ void httpSuccess() - { - LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL; - LL_DEBUGS("FlickrConnect") << "Getting Flickr info successful. " << dumpResponse() << LL_ENDL; - LLFlickrConnect::instance().storeInfo(getContent()); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("FlickrConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLFlickrConnect::instance().openFlickrWeb(location); - } - } - else - { - LL_WARNS("FlickrConnect") << dumpResponse() << LL_ENDL; - const LLSD& content = getContent(); - log_flickr_connect_error("Info", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getFlickrConnectURL("/info", true), httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openFlickrWeb(location); + } + } + else if (!status) + { + LL_WARNS("FlickrConnect") << "Flickr Info failed: " << status.toString() << LL_ENDL; + log_flickr_connect_error("Info", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_INFOS("FlickrConnect") << "Flickr: Info received" << LL_ENDL; + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + storeInfo(result); + } +} /////////////////////////////////////////////////////////////////////////////// // @@ -341,36 +435,28 @@ std::string LLFlickrConnect::getFlickrConnectURL(const std::string& route, bool void LLFlickrConnect::connectToFlickr(const std::string& request_token, const std::string& oauth_verifier) { - LLSD body; - if (!request_token.empty()) - body["request_token"] = request_token; - if (!oauth_verifier.empty()) - body["oauth_verifier"] = oauth_verifier; - - LLHTTPClient::put(getFlickrConnectURL("/connection"), body, new LLFlickrConnectResponder()); + LLCoros::instance().launch("LLFlickrConnect::flickrConnectCoro", + boost::bind(&LLFlickrConnect::flickrConnectCoro, this, request_token, oauth_verifier)); } void LLFlickrConnect::disconnectFromFlickr() { - LLHTTPClient::del(getFlickrConnectURL("/connection"), new LLFlickrDisconnectResponder()); + LLCoros::instance().launch("LLFlickrConnect::flickrDisconnectCoro", + boost::bind(&LLFlickrConnect::flickrDisconnectCoro, this)); } void LLFlickrConnect::checkConnectionToFlickr(bool auto_connect) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getFlickrConnectURL("/connection", true), new LLFlickrConnectedResponder(auto_connect), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLFlickrConnect::flickrConnectedCoro", + boost::bind(&LLFlickrConnect::flickrConnectedCoro, this, auto_connect)); } void LLFlickrConnect::loadFlickrInfo() { if(mRefreshInfo) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getFlickrConnectURL("/info", true), new LLFlickrInfoResponder(), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLFlickrConnect::flickrInfoCoro", + boost::bind(&LLFlickrConnect::flickrInfoCoro, this)); } } @@ -382,74 +468,20 @@ void LLFlickrConnect::uploadPhoto(const std::string& image_url, const std::strin body["description"] = description; body["tags"] = tags; body["safety_level"] = safety_level; - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getFlickrConnectURL("/share/photo", true), body, new LLFlickrShareResponder()); + + setConnectionState(LLFlickrConnect::FLICKR_POSTING); + + LLCoros::instance().launch("LLFlickrConnect::flickrShareCoro", + boost::bind(&LLFlickrConnect::flickrShareCoro, this, body)); } void LLFlickrConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& title, const std::string& description, const std::string& tags, int safety_level) { - std::string imageFormat; - if (dynamic_cast<LLImagePNG*>(image.get())) - { - imageFormat = "png"; - } - else if (dynamic_cast<LLImageJPEG*>(image.get())) - { - imageFormat = "jpg"; - } - else - { - LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; - return; - } - - // All this code is mostly copied from LLWebProfile::post() - const std::string boundary = "----------------------------0123abcdefab"; - - LLSD headers; - headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; - - std::ostringstream body; - - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"title\"\r\n\r\n" - << title << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"description\"\r\n\r\n" - << description << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"tags\"\r\n\r\n" - << tags << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"safety_level\"\r\n\r\n" - << safety_level << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" - << "Content-Type: image/" << imageFormat << "\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << boundary << "--\r\n"; + setConnectionState(LLFlickrConnect::FLICKR_POSTING); - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::postRaw(getFlickrConnectURL("/share/photo", true), data, size, new LLFlickrShareResponder(), headers); + LLCoros::instance().launch("LLFlickrConnect::flickrShareImageCoro", + boost::bind(&LLFlickrConnect::flickrShareImageCoro, this, image, + title, description, tags, safety_level)); } void LLFlickrConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/llflickrconnect.h b/indra/newview/llflickrconnect.h index b127e6e104..0155804da0 100644 --- a/indra/newview/llflickrconnect.h +++ b/indra/newview/llflickrconnect.h @@ -30,6 +30,8 @@ #include "llsingleton.h" #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLEventPump; @@ -93,6 +95,15 @@ private: static boost::scoped_ptr<LLEventPump> sStateWatcher; static boost::scoped_ptr<LLEventPump> sInfoWatcher; static boost::scoped_ptr<LLEventPump> sContentWatcher; + + bool testShareStatus(LLSD &result); + void flickrConnectCoro(std::string requestToken, std::string oauthVerifier); + void flickrShareCoro(LLSD share); + void flickrShareImageCoro(LLPointer<LLImageFormatted> image, std::string title, std::string description, std::string tags, int safetyLevel); + void flickrDisconnectCoro(); + void flickrConnectedCoro(bool autoConnect); + void flickrInfoCoro(); + }; #endif // LL_LLFLICKRCONNECT_H diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index e71daa6067..7bd01f6beb 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -48,7 +48,6 @@ // Linden library includes #include "llaudioengine.h" #include "llbutton.h" -#include "llcurl.h" #include "llglheaders.h" #include "llfloater.h" #include "llfloaterreg.h" @@ -61,6 +60,7 @@ #include "stringize.h" #include "llsdutil_math.h" #include "lleventapi.h" +#include "llcorehttputil.h" #if LL_WINDOWS #include "lldxhardware.h" @@ -70,18 +70,6 @@ extern LLMemoryInfo gSysMemory; extern U32 gPacketsIn; ///---------------------------------------------------------------------------- -/// Class LLServerReleaseNotesURLFetcher -///---------------------------------------------------------------------------- -class LLServerReleaseNotesURLFetcher : public LLHTTPClient::Responder -{ - LOG_CLASS(LLServerReleaseNotesURLFetcher); -public: - static void startFetch(); -private: - /* virtual */ void httpCompleted(); -}; - -///---------------------------------------------------------------------------- /// Class LLFloaterAbout ///---------------------------------------------------------------------------- class LLFloaterAbout @@ -102,6 +90,9 @@ public: private: void setSupportText(const std::string& server_release_notes_url); + + static void startFetchServerReleaseNotes(); + static void handleServerReleaseNotes(LLSD results); }; @@ -138,7 +129,7 @@ BOOL LLFloaterAbout::postBuild() { // start fetching server release notes URL setSupportText(LLTrans::getString("RetrievingData")); - LLServerReleaseNotesURLFetcher::startFetch(); + startFetchServerReleaseNotes(); } else // not logged in { @@ -201,6 +192,50 @@ LLSD LLFloaterAbout::getInfo() return LLAppViewer::instance()->getViewerInfo(); } +/*static*/ +void LLFloaterAbout::startFetchServerReleaseNotes() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; + + // We cannot display the URL returned by the ServerReleaseNotes capability + // because opening it in an external browser will trigger a warning about untrusted + // SSL certificate. + // So we query the URL ourselves, expecting to find + // an URL suitable for external browsers in the "Location:" HTTP header. + std::string cap_url = region->getCapability("ServerReleaseNotes"); + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(cap_url, + &LLFloaterAbout::handleServerReleaseNotes, &LLFloaterAbout::handleServerReleaseNotes); + +} + +/*static*/ +void LLFloaterAbout::handleServerReleaseNotes(LLSD results) +{ +// LLFloaterAbout* floater_about = LLFloaterReg::getTypedInstance<LLFloaterAbout>("sl_about"); +// if (floater_about) +// { + LLSD http_headers; + if (results.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS)) + { + LLSD http_results = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + http_headers = http_results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + } + else + { + http_headers = results[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + } + + std::string location = http_headers[HTTP_IN_HEADER_LOCATION].asString(); + if (location.empty()) + { + location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); + } + LLAppViewer::instance()->setServerReleaseNotesURL(location); +// } +} + class LLFloaterAboutListener: public LLEventAPI { public: @@ -265,35 +300,3 @@ void LLFloaterAboutUtil::registerFloater() } -///---------------------------------------------------------------------------- -/// Class LLServerReleaseNotesURLFetcher implementation -///---------------------------------------------------------------------------- -// static -void LLServerReleaseNotesURLFetcher::startFetch() -{ - LLViewerRegion* region = gAgent.getRegion(); - if (!region) return; - - // We cannot display the URL returned by the ServerReleaseNotes capability - // because opening it in an external browser will trigger a warning about untrusted - // SSL certificate. - // So we query the URL ourselves, expecting to find - // an URL suitable for external browsers in the "Location:" HTTP header. - std::string cap_url = region->getCapability("ServerReleaseNotes"); - LLHTTPClient::get(cap_url, new LLServerReleaseNotesURLFetcher); -} - -// virtual -void LLServerReleaseNotesURLFetcher::httpCompleted() -{ - LL_DEBUGS("ServerReleaseNotes") << dumpResponse() - << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - - std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); - } - LLAppViewer::instance()->setServerReleaseNotesURL(location); -} - diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index b661fed276..56619e818a 100755 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -57,6 +57,7 @@ #include "llsdutil.h" #include "llsdutil_math.h" #include "lltrans.h" +#include "llcorehttputil.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -361,7 +362,10 @@ void LLFloaterAuction::doResetParcel() LL_INFOS() << "Sending parcel update to reset for auction via capability to: " << mParcelUpdateCapUrl << LL_ENDL; - LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder()); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body, + "Parcel reset for auction", + "Parcel not set for auction."); // Send a message to clear the object return time LLMessageSystem *msg = gMessageSystem; @@ -490,7 +494,10 @@ void LLFloaterAuction::doSellToAnyone() LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: " << mParcelUpdateCapUrl << LL_ENDL; - LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::Responder()); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(mParcelUpdateCapUrl, body, + "Parcel set as sell to everyone.", + "Parcel sell to everyone failed."); // clean up floater, and get out cleanupAndClose(); diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp index 6e56e929df..5830f2f711 100755 --- a/indra/newview/llfloaterautoreplacesettings.cpp +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -36,7 +36,6 @@ #include "llcolorswatch.h" #include "llcombobox.h" #include "llview.h" -#include "llhttpclient.h" #include "llbufferstream.h" #include "llcheckboxctrl.h" #include "llviewercontrol.h" diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 566a3c9cd3..72892b47a4 100755 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -42,7 +42,6 @@ #include "llavatarnamecache.h" // IDEVO #include "llbutton.h" #include "llcachename.h" -#include "llhttpclient.h" // IDEVO #include "lllineeditor.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" @@ -52,6 +51,7 @@ #include "llfocusmgr.h" #include "lldraghandle.h" #include "message.h" +#include "llcorehttputil.h" //#include "llsdserialize.h" @@ -456,39 +456,33 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const return FALSE; } -class LLAvatarPickerResponder : public LLHTTPClient::Responder +/*static*/ +void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::string name) { - LOG_CLASS(LLAvatarPickerResponder); -public: - LLUUID mQueryID; - std::string mName; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLAvatarPickerResponder(const LLUUID& id, const std::string& name) : mQueryID(id), mName(name) { } + LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; -protected: - /*virtual*/ void httpCompleted() - { - //std::ostringstream ss; - //LLSDSerialize::toPrettyXML(content, ss); - //LL_INFOS() << ss.str() << LL_ENDL; + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST))) + { + LLFloaterAvatarPicker* floater = + LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name); + if (floater) + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + floater->processResponse(queryID, result); + } + } +} - // in case of invalid characters, the avatar picker returns a 400 - // just set it to process so it displays 'not found' - if (isGoodStatus() || getStatus() == HTTP_BAD_REQUEST) - { - LLFloaterAvatarPicker* floater = - LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", mName); - if (floater) - { - floater->processResponse(mQueryID, getContent()); - } - } - else - { - LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL; - } - } -}; void LLFloaterAvatarPicker::find() { @@ -517,7 +511,9 @@ void LLFloaterAvatarPicker::find() std::replace(text.begin(), text.end(), '.', ' '); url += LLURI::escape(text); LL_INFOS() << "avatar picker " << url << LL_ENDL; - LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID, getKey().asString())); + + LLCoros::instance().launch("LLFloaterAvatarPicker::findCoro", + boost::bind(&LLFloaterAvatarPicker::findCoro, url, mQueryID, getKey().asString())); } else { diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index ed3e51c56f..fbee61b054 100755 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -28,6 +28,8 @@ #define LLFLOATERAVATARPICKER_H #include "llfloater.h" +#include "lleventcoro.h" +#include "llcoros.h" #include <vector> @@ -84,6 +86,7 @@ private: void populateFriend(); BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected. + static void findCoro(std::string url, LLUUID mQueryID, std::string mName); void find(); void setAllowMultiple(BOOL allow_multiple); LLScrollListCtrl* getActiveList(); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 669ffa7c59..e5df417ca9 100755 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -992,20 +992,16 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) { std::string name = floaterp->getChild<LLUICtrl>("name_form")->getValue().asString(); std::string desc = floaterp->getChild<LLUICtrl>("description_form")->getValue().asString(); - LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - upload_new_resource(floaterp->mTransactionID, // tid - LLAssetType::AT_ANIMATION, - name, - desc, - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_ANIMATION, - LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), - name, - callback, expected_upload_cost, userdata); + LLResourceUploadInfo::ptr_t assetUpdloadInfo(new LLResourceUploadInfo( + floaterp->mTransactionID, LLAssetType::AT_ANIMATION, + name, desc, 0, + LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, + LLFloaterPerms::getNextOwnerPerms("Uploads"), LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost)); + + upload_new_resource(assetUpdloadInfo); } else { diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp deleted file mode 100755 index 596e8c0dbe..0000000000 --- a/indra/newview/llfloaterdisplayname.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/** - * @file llfloaterdisplayname.cpp - * @author Leyla Farazha - * @brief Implementation of the LLFloaterDisplayName class. - * - * $LicenseInfo:firstyear=2002&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$ - */ - - -#include "llviewerprecompiledheaders.h" -#include "llfloaterreg.h" -#include "llfloater.h" - -#include "llnotificationsutil.h" -#include "llviewerdisplayname.h" - -#include "llnotifications.h" -#include "llfloaterdisplayname.h" -#include "llavatarnamecache.h" - -#include "llagent.h" - - -class LLFloaterDisplayName : public LLFloater -{ -public: - LLFloaterDisplayName(const LLSD& key); - virtual ~LLFloaterDisplayName() { } - /*virtual*/ BOOL postBuild(); - void onSave(); - void onReset(); - void onCancel(); - /*virtual*/ void onOpen(const LLSD& key); - -private: - - void onCacheSetName(bool success, - const std::string& reason, - const LLSD& content); -}; - -LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key) : - LLFloater(key) -{ -} - -void LLFloaterDisplayName::onOpen(const LLSD& key) -{ - getChild<LLUICtrl>("display_name_editor")->clear(); - getChild<LLUICtrl>("display_name_confirm")->clear(); - - LLAvatarName av_name; - LLAvatarNameCache::get(gAgent.getID(), &av_name); - - F64 now_secs = LLDate::now().secondsSinceEpoch(); - - if (now_secs < av_name.mNextUpdate) - { - // ...can't update until some time in the future - F64 next_update_local_secs = - av_name.mNextUpdate - LLStringOps::getLocalTimeOffset(); - LLDate next_update_local(next_update_local_secs); - // display as "July 18 12:17 PM" - std::string next_update_string = - next_update_local.toHTTPDateString("%B %d %I:%M %p"); - getChild<LLUICtrl>("lockout_text")->setTextArg("[TIME]", next_update_string); - getChild<LLUICtrl>("lockout_text")->setVisible(true); - getChild<LLUICtrl>("save_btn")->setEnabled(false); - getChild<LLUICtrl>("display_name_editor")->setEnabled(false); - getChild<LLUICtrl>("display_name_confirm")->setEnabled(false); - getChild<LLUICtrl>("cancel_btn")->setFocus(TRUE); - - } - else - { - getChild<LLUICtrl>("lockout_text")->setVisible(false); - getChild<LLUICtrl>("save_btn")->setEnabled(true); - getChild<LLUICtrl>("display_name_editor")->setEnabled(true); - getChild<LLUICtrl>("display_name_confirm")->setEnabled(true); - - } -} - -BOOL LLFloaterDisplayName::postBuild() -{ - getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this)); - getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this)); - getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this)); - - center(); - - return TRUE; -} - -void LLFloaterDisplayName::onCacheSetName(bool success, - const std::string& reason, - const LLSD& content) -{ - if (success) - { - // Inform the user that the change took place, but will take a while - // to percolate. - LLSD args; - args["DISPLAY_NAME"] = content["display_name"]; - LLNotificationsUtil::add("SetDisplayNameSuccess", args); - return; - } - - // Request failed, notify the user - std::string error_tag = content["error_tag"].asString(); - LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL; - - // We might have a localized string for this message - // error_args will usually be empty from the server. - if (!error_tag.empty() - && LLNotifications::getInstance()->templateExists(error_tag)) - { - LLNotificationsUtil::add(error_tag); - return; - } - - // The server error might have a localized message for us - std::string lang_code = LLUI::getLanguage(); - LLSD error_desc = content["error_description"]; - if (error_desc.has( lang_code )) - { - LLSD args; - args["MESSAGE"] = error_desc[lang_code].asString(); - LLNotificationsUtil::add("GenericAlert", args); - return; - } - - // No specific error, throw a generic one - LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); -} - -void LLFloaterDisplayName::onCancel() -{ - setVisible(false); -} - -void LLFloaterDisplayName::onReset() -{ - if (LLAvatarNameCache::hasNameLookupURL()) - { - LLViewerDisplayName::set("",boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); - } - else - { - LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); - } - - setVisible(false); -} - - -void LLFloaterDisplayName::onSave() -{ - std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString(); - std::string display_name_confirm = getChild<LLUICtrl>("display_name_confirm")->getValue().asString(); - - if (display_name_utf8.compare(display_name_confirm)) - { - LLNotificationsUtil::add("SetDisplayNameMismatch"); - return; - } - - const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes - LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8); - if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH) - { - LLSD args; - args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH); - LLNotificationsUtil::add("SetDisplayNameFailedLength", args); - return; - } - - if (LLAvatarNameCache::hasNameLookupURL()) - { - LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); - } - else - { - LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); - } - - setVisible(false); -} - - -////////////////////////////////////////////////////////////////////////////// -// LLInspectObjectUtil -////////////////////////////////////////////////////////////////////////////// -void LLFloaterDisplayNameUtil::registerFloater() -{ - LLFloaterReg::add("display_name", "floater_display_name.xml", - &LLFloaterReg::build<LLFloaterDisplayName>); -} diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h deleted file mode 100755 index a00bf56712..0000000000 --- a/indra/newview/llfloaterdisplayname.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file llfloaterdisplayname.h - * - * $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$ - */ - -#ifndef LLFLOATERDISPLAYNAME_H -#define LLFLOATERDISPLAYNAME_H - - -namespace LLFloaterDisplayNameUtil -{ - // Register with LLFloaterReg - void registerFloater(); -} - - - -#endif diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp index 197162487d..d44eb4310d 100644 --- a/indra/newview/llfloaterexperienceprofile.cpp +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -36,7 +36,6 @@ #include "llexpandabletextbox.h" #include "llexperiencecache.h" #include "llfloaterreg.h" -#include "llhttpclient.h" #include "lllayoutstack.h" #include "lllineeditor.h" #include "llnotificationsutil.h" @@ -99,7 +98,7 @@ public: if(params.size() != 2 || params[1].asString() != "profile") return false; - LLExperienceCache::get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1)); + LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1)); return true; } @@ -131,175 +130,20 @@ LLFloaterExperienceProfile::~LLFloaterExperienceProfile() } -template<class T> -class HandleResponder : public LLHTTPClient::Responder -{ -public: - HandleResponder(const LLHandle<T>& parent):mParent(parent){} - LLHandle<T> mParent; - - virtual void httpFailure() - { - LL_WARNS() << "HandleResponder failed with code: " << getStatus() << ", reason: " << getReason() << LL_ENDL; - } -}; - -class ExperienceUpdateResponder : public HandleResponder<LLFloaterExperienceProfile> -{ -public: - ExperienceUpdateResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent) - { - } - - virtual void httpSuccess() - { - LLFloaterExperienceProfile* parent=mParent.get(); - if(parent) - { - parent->onSaveComplete(getContent()); - } - } -}; - - - -class ExperiencePreferencesResponder : public LLHTTPClient::Responder -{ -public: - ExperiencePreferencesResponder(const LLUUID& single = LLUUID::null):mId(single) - { - } - - bool sendSingle(const LLSD& content, const LLSD& permission, const char* name) - { - if(!content.has(name)) - return false; - - LLEventPump& pump = LLEventPumps::instance().obtain("experience_permission"); - const LLSD& list = content[name]; - LLSD::array_const_iterator it = list.beginArray(); - while(it != list.endArray()) - { - if(it->asUUID() == mId) - { - LLSD message; - message[it->asString()] = permission; - message["experience"] = mId; - pump.post(message); - return true; - } - ++it; - } - return false; - } - - bool hasPermission(const LLSD& content, const char* name) - { - if(!content.has(name)) - return false; - - const LLSD& list = content[name]; - LLSD::array_const_iterator it = list.beginArray(); - while(it != list.endArray()) - { - if(it->asUUID() == mId) - { - return true; - } - ++it; - } - return false; - } - - const char* getPermission(const LLSD& content) - { - if(hasPermission(content, "experiences")) - { - return "Allow"; - } - else if(hasPermission(content, "blocked")) - { - return "Block"; - } - return "Forget"; - } - - - virtual void httpSuccess() - { - if(mId.notNull()) - { - post(getPermission(getContent())); - return; - } - LLEventPumps::instance().obtain("experience_permission").post(getContent()); - } - - void post( const char* perm ) - { - LLSD experience; - LLSD message; - experience["permission"]=perm; - message["experience"] = mId; - message[mId.asString()] = experience; - LLEventPumps::instance().obtain("experience_permission").post(message); - } - -private: - LLUUID mId; -}; - - -class IsAdminResponder : public HandleResponder<LLFloaterExperienceProfile> -{ -public: - IsAdminResponder(const LLHandle<LLFloaterExperienceProfile>& parent):HandleResponder<LLFloaterExperienceProfile>(parent) - { - } - - virtual void httpSuccess() - { - LLFloaterExperienceProfile* parent = mParent.get(); - if(!parent) - return; - - bool enabled = true; - LLViewerRegion* region = gAgent.getRegion(); - if (!region) - { - enabled = false; - } - else - { - std::string url=region->getCapability("UpdateExperience"); - if(url.empty()) - enabled = false; - } - if(enabled && getContent()["status"].asBoolean()) - { - parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE); - parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE); - } - } -}; - BOOL LLFloaterExperienceProfile::postBuild() { if (mExperienceId.notNull()) { - LLExperienceCache::fetch(mExperienceId, true); - LLExperienceCache::get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback, + LLExperienceCache::instance().fetch(mExperienceId, true); + LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback, getDerivedHandle<LLFloaterExperienceProfile>(), _1)); LLViewerRegion* region = gAgent.getRegion(); if (region) { - std::string lookup_url=region->getCapability("IsExperienceAdmin"); - if(!lookup_url.empty()) - { - LLHTTPClient::get(lookup_url+"?experience_id="+mExperienceId.asString(), new IsAdminResponder(getDerivedHandle<LLFloaterExperienceProfile>())); - } + LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle<LLFloaterExperienceProfile>(), _1)); } } @@ -372,23 +216,13 @@ void LLFloaterExperienceProfile::onClickSave() doSave(NOTHING); } - void LLFloaterExperienceProfile::onClickPermission(const char* perm) { LLViewerRegion* region = gAgent.getRegion(); if (!region) return; - - std::string lookup_url=region->getCapability("ExperiencePreferences"); - if(lookup_url.empty()) - return; - LLSD permission; - LLSD data; - permission["permission"]=perm; - - data[mExperienceId.asString()]=permission; - LLHTTPClient::put(lookup_url, data, new ExperiencePreferencesResponder(mExperienceId)); - + LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); } @@ -398,11 +232,8 @@ void LLFloaterExperienceProfile::onClickForget() if (!region) return; - std::string lookup_url=region->getCapability("ExperiencePreferences"); - if(lookup_url.empty()) - return; - - LLHTTPClient::del(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId)); + LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); } bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo ) @@ -549,11 +380,8 @@ void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience ) LLViewerRegion* region = gAgent.getRegion(); if (region) { - std::string lookup_url=region->getCapability("ExperiencePreferences"); - if(!lookup_url.empty()) - { - LLHTTPClient::get(lookup_url+"?"+mExperienceId.asString(), new ExperiencePreferencesResponder(mExperienceId)); - } + LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); } } @@ -733,15 +561,9 @@ void LLFloaterExperienceProfile::doSave( int success_action ) if (!region) return; - std::string url=region->getCapability("UpdateExperience"); - if(url.empty()) - return; - - mPackage.erase(LLExperienceCache::QUOTA); - mPackage.erase(LLExperienceCache::EXPIRES); - mPackage.erase(LLExperienceCache::AGENT_ID); - - LLHTTPClient::post(url, mPackage, new ExperienceUpdateResponder(getDerivedHandle<LLFloaterExperienceProfile>())); + LLExperienceCache::instance().updateExperience(mPackage, boost::bind( + &LLFloaterExperienceProfile::experienceUpdateResult, + getDerivedHandle<LLFloaterExperienceProfile>(), _1)); } void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content ) @@ -799,8 +621,8 @@ void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content ) } refreshExperience(*it); - LLExperienceCache::insert(*it); - LLExperienceCache::fetch(id, true); + LLExperienceCache::instance().insert(*it); + LLExperienceCache::instance().fetch(id, true); if(mSaveCompleteAction==VIEW) { @@ -1002,3 +824,76 @@ void LLFloaterExperienceProfile::onReportExperience() { LLFloaterReporter::showFromExperience(mExperienceId); } + +/*static*/ +bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test) +{ + if (!content.has(name)) + return false; + + const LLSD& list = content[name]; + LLSD::array_const_iterator it = list.beginArray(); + while (it != list.endArray()) + { + if (it->asUUID() == test) + { + return true; + } + ++it; + } + return false; +} + +/*static*/ +void LLFloaterExperienceProfile::experiencePermissionResults(LLUUID exprienceId, LLSD result) +{ + std::string permission("Forget"); + if (hasPermission(result, "experiences", exprienceId)) + permission = "Allow"; + else if (hasPermission(result, "blocked", exprienceId)) + permission = "Block"; + + LLSD experience; + LLSD message; + experience["permission"] = permission; + message["experience"] = exprienceId; + message[exprienceId.asString()] = experience; + + LLEventPumps::instance().obtain("experience_permission").post(message); +} + +/*static*/ +void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (!parent) + return; + + bool enabled = true; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + enabled = false; + } + else + { + std::string url = region->getCapability("UpdateExperience"); + if (url.empty()) + enabled = false; + } + if (enabled && result["status"].asBoolean()) + { + parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE); + parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE); + } +} + +/*static*/ +void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (parent) + { + parent->onSaveComplete(result); + } +} diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h index 78d54eb447..7a5ced546b 100644 --- a/indra/newview/llfloaterexperienceprofile.h +++ b/indra/newview/llfloaterexperienceprofile.h @@ -99,6 +99,12 @@ protected: int mSaveCompleteAction; bool mDirty; bool mForceClose; + +private: + static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test); + static void experiencePermissionResults(LLUUID exprienceId, LLSD result); + static void experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result); + static void experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result); }; #endif // LL_LLFLOATEREXPERIENCEPROFILE_H diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp index 777dc382cd..fbe00beddd 100644 --- a/indra/newview/llfloaterexperiences.cpp +++ b/indra/newview/llfloaterexperiences.cpp @@ -32,7 +32,6 @@ #include "llevents.h" #include "llexperiencecache.h" #include "llfloaterregioninfo.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llpanelexperiencelog.h" #include "llpanelexperiencepicker.h" @@ -43,59 +42,6 @@ #define SHOW_RECENT_TAB (0) - -class LLExperienceListResponder : public LLHTTPClient::Responder -{ -public: - typedef std::map<std::string, std::string> NameMap; - typedef boost::function<void(LLPanelExperiences*, const LLSD&)> Callback; - LLExperienceListResponder(const LLHandle<LLFloaterExperiences>& parent, NameMap& nameMap, const std::string& errorMessage="ErrorMessage"):mParent(parent),mErrorMessage(errorMessage) - { - mNameMap.swap(nameMap); - } - - Callback mCallback; - LLHandle<LLFloaterExperiences> mParent; - NameMap mNameMap; - const std::string mErrorMessage; - /*virtual*/ void httpSuccess() - { - if(mParent.isDead()) - return; - - LLFloaterExperiences* parent=mParent.get(); - LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs"); - - NameMap::iterator it = mNameMap.begin(); - while(it != mNameMap.end()) - { - if(getContent().has(it->first)) - { - LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it->second); - if(tab) - { - const LLSD& ids = getContent()[it->first]; - tab->setExperienceList(ids); - if(!mCallback.empty()) - { - mCallback(tab, getContent()); - } - } - } - ++it; - } - } - - /*virtual*/ void httpFailure() - { - LLSD subs; - subs["ERROR_MESSAGE"] = getReason(); - LLNotificationsUtil::add(mErrorMessage, subs); - } -}; - - - LLFloaterExperiences::LLFloaterExperiences(const LLSD& data) :LLFloater(data) { @@ -198,26 +144,20 @@ void LLFloaterExperiences::refreshContents() if (region) { - LLExperienceListResponder::NameMap nameMap; - std::string lookup_url=region->getCapability("GetExperiences"); - if(!lookup_url.empty()) - { - nameMap["experiences"]="Allowed_Experiences_Tab"; - nameMap["blocked"]="Blocked_Experiences_Tab"; - LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap)); - } + NameMap_t tabMap; + LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>(); + + tabMap["experiences"]="Allowed_Experiences_Tab"; + tabMap["blocked"]="Blocked_Experiences_Tab"; + tabMap["experience_ids"]="Owned_Experiences_Tab"; + + retrieveExperienceList(region->getCapability("GetExperiences"), handle, tabMap); updateInfo("GetAdminExperiences","Admin_Experiences_Tab"); updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); - lookup_url = region->getCapability("AgentExperiences"); - if(!lookup_url.empty()) - { - nameMap["experience_ids"]="Owned_Experiences_Tab"; - LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed"); - responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2); - LLHTTPClient::get(lookup_url, responder); - } + retrieveExperienceList(region->getCapability("AgentExperiences"), handle, tabMap, + "ExperienceAcquireFailed", boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2)); } } @@ -303,38 +243,139 @@ void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LL LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); } -void LLFloaterExperiences::updateInfo(std::string experiences, std::string tab) +void LLFloaterExperiences::updateInfo(std::string experienceCap, std::string tab) { LLViewerRegion* region = gAgent.getRegion(); if (region) { - LLExperienceListResponder::NameMap nameMap; - std::string lookup_url = region->getCapability(experiences); - if(!lookup_url.empty()) - { - nameMap["experience_ids"]=tab; - LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap)); - } - } + NameMap_t tabMap; + LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>(); + + tabMap["experience_ids"] = tab; + + retrieveExperienceList(region->getCapability(experienceCap), handle, tabMap); + } } -void LLFloaterExperiences::sendPurchaseRequest() const +void LLFloaterExperiences::sendPurchaseRequest() { - LLViewerRegion* region = gAgent.getRegion(); - std::string url = region->getCapability("AgentExperiences"); - if(!url.empty()) - { - LLSD content; - - LLExperienceListResponder::NameMap nameMap; - nameMap["experience_ids"]="Owned_Experiences_Tab"; - LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed"); - responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2); - LLHTTPClient::post(url, content, responder); - } + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + NameMap_t tabMap; + LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>(); + + tabMap["experience_ids"] = "Owned_Experiences_Tab"; + + requestNewExperience(region->getCapability("AgentExperiences"), handle, tabMap, "ExperienceAcquireFailed", + boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2)); + } } LLFloaterExperiences* LLFloaterExperiences::findInstance() { return LLFloaterReg::findTypedInstance<LLFloaterExperiences>("experiences"); } + + +void LLFloaterExperiences::retrieveExperienceList(const std::string &url, + const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback) + +{ + invokationFn_t getFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> httpOptions + // _5 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _4, _5); + + LLCoros::instance().launch("LLFloaterExperiences::retrieveExperienceList", + boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro, + url, hparent, tabMapping, errorNotify, cback, getFn)); + +} + +void LLFloaterExperiences::requestNewExperience(const std::string &url, + const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback) +{ + invokationFn_t postFn = boost::bind( + // Humans ignore next line. It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload. + static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)> + //---- + // _1 -> httpAdapter + // _2 -> httpRequest + // _3 -> url + // _4 -> httpOptions + // _5 -> httpHeaders + (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndSuspend), _1, _2, _3, LLSD(), _4, _5); + + LLCoros::instance().launch("LLFloaterExperiences::requestNewExperience", + boost::bind(&LLFloaterExperiences::retrieveExperienceListCoro, + url, hparent, tabMapping, errorNotify, cback, postFn)); + +} + + +void LLFloaterExperiences::retrieveExperienceListCoro(std::string url, + LLHandle<LLFloaterExperiences> hparent, NameMap_t tabMapping, + std::string errorNotify, Callback_t cback, invokationFn_t invoker) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("retrieveExperienceListCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + + if (url.empty()) + { + LL_WARNS() << "retrieveExperienceListCoro called with empty capability!" << LL_ENDL; + return; + } + + LLSD result = invoker(httpAdapter, httpRequest, url, httpOptions, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LLSD subs; + subs["ERROR_MESSAGE"] = status.getType(); + LLNotificationsUtil::add(errorNotify, subs); + + return; + } + + if (hparent.isDead()) + return; + + LLFloaterExperiences* parent = hparent.get(); + LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs"); + + for (NameMap_t::iterator it = tabMapping.begin(); it != tabMapping.end(); ++it) + { + if (result.has(it->first)) + { + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it->second); + if (tab) + { + const LLSD& ids = result[it->first]; + tab->setExperienceList(ids); + if (!cback.empty()) + { + cback(tab, result); + } + } + } + } + +} diff --git a/indra/newview/llfloaterexperiences.h b/indra/newview/llfloaterexperiences.h index 769283ff07..c038aa6375 100644 --- a/indra/newview/llfloaterexperiences.h +++ b/indra/newview/llfloaterexperiences.h @@ -28,6 +28,7 @@ #define LL_LLFLOATEREXPERIENCES_H #include "llfloater.h" +#include "llcorehttputil.h" class LLPanelExperiences; @@ -41,6 +42,9 @@ public: virtual void onOpen(const LLSD& key); static LLFloaterExperiences* findInstance(); protected: + typedef std::map<std::string, std::string> NameMap_t; + typedef boost::function<void(LLPanelExperiences*, const LLSD&)> Callback_t; + void clearFromRecent(const LLSD& ids); void resizeToTabs(); /*virtual*/ BOOL postBuild(); @@ -49,11 +53,22 @@ protected: LLPanelExperiences* addTab(const std::string& name, bool select); bool updatePermissions(const LLSD& permission); - void sendPurchaseRequest() const; + void sendPurchaseRequest(); void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const; void updateInfo(std::string experiences, std::string tab); + void retrieveExperienceList(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify = std::string("ErrorMessage"), Callback_t cback = Callback_t()); + + void requestNewExperience(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback); + private: + typedef boost::function < LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t, LLCore::HttpRequest::ptr_t, + const std::string, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t; + + static void retrieveExperienceListCoro(std::string url, LLHandle<LLFloaterExperiences> hparent, + NameMap_t tabMapping, std::string errorNotify, Callback_t cback, invokationFn_t invoker); }; diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 37774fbc5c..adc7f71586 100755 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -115,7 +115,7 @@ void LLFloaterGodTools::refreshAll() LLFloaterGodTools::LLFloaterGodTools(const LLSD& key) : LLFloater(key), - mCurrentHost(LLHost::invalid), + mCurrentHost(LLHost()), mUpdateTimer() { mFactoryMap["grid"] = LLCallbackMap(createPanelGrid, this); @@ -180,7 +180,7 @@ void LLFloaterGodTools::updatePopup(LLCoordGL center, MASK mask) // virtual void LLFloaterGodTools::draw() { - if (mCurrentHost == LLHost::invalid) + if (mCurrentHost == LLHost()) { if (mUpdateTimer.getElapsedTimeF32() > SECONDS_BETWEEN_UPDATE_REQUESTS) { @@ -325,7 +325,7 @@ void LLFloaterGodTools::sendRegionInfoRequest() { if (mPanelRegionTools) mPanelRegionTools->clearAllWidgets(); if (mPanelObjectTools) mPanelObjectTools->clearAllWidgets(); - mCurrentHost = LLHost::invalid; + mCurrentHost = LLHost(); mUpdateTimer.reset(); LLMessageSystem* msg = gMessageSystem; diff --git a/indra/newview/llfloaterhoverheight.cpp b/indra/newview/llfloaterhoverheight.cpp index 8908626de6..003a22fa04 100755 --- a/indra/newview/llfloaterhoverheight.cpp +++ b/indra/newview/llfloaterhoverheight.cpp @@ -31,7 +31,6 @@ #include "llsliderctrl.h" #include "llviewercontrol.h" #include "llsdserialize.h" -#include "llhttpclient.h" #include "llagent.h" #include "llviewerregion.h" #include "llvoavatarself.h" diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp index fc7fcf3ab9..6623ce0f80 100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -41,7 +41,6 @@ #include "llchicletbar.h" #include "lldonotdisturbnotificationstorage.h" #include "llfloaterreg.h" -#include "llhttpclient.h" #include "llfloateravatarpicker.h" #include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container #include "llinventoryfunctions.h" @@ -62,6 +61,7 @@ #include "llviewerchat.h" #include "llnotificationmanager.h" #include "llautoreplace.h" +#include "llcorehttputil.h" const F32 ME_TYPING_TIMEOUT = 4.0f; const F32 OTHER_TYPING_TIMEOUT = 9.0f; @@ -1178,26 +1178,6 @@ BOOL LLFloaterIMSession::isInviteAllowed() const || mIsP2PChat); } -class LLSessionInviteResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSessionInviteResponder); -public: - LLSessionInviteResponder(const LLUUID& session_id) - { - mSessionID = session_id; - } - -protected: - void httpFailure() - { - LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL; - //throw something back to the viewer here? - } - -private: - LLUUID mSessionID; -}; - BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids) { LLViewerRegion* region = gAgent.getRegion(); @@ -1221,7 +1201,9 @@ BOOL LLFloaterIMSession::inviteToSession(const uuid_vec_t& ids) } data["method"] = "invite"; data["session-id"] = mSessionID; - LLHTTPClient::post(url, data,new LLSessionInviteResponder(mSessionID)); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, + "Session invite sent", "Session invite failed"); } else { diff --git a/indra/newview/llfloatermarketplacelistings.cpp b/indra/newview/llfloatermarketplacelistings.cpp index b2d36479cd..18f0bc4498 100755 --- a/indra/newview/llfloatermarketplacelistings.cpp +++ b/indra/newview/llfloatermarketplacelistings.cpp @@ -572,7 +572,7 @@ void LLFloaterMarketplaceListings::updateView() std::string title; std::string tooltip; - const LLSD& subs = getMarketplaceStringSubstitutions(); + const LLSD& subs = LLMarketplaceData::getMarketplaceStringSubstitutions(); // Update the top message or flip to the tabs and folders view // *TODO : check those messages and create better appropriate ones in strings.xml diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6804b21b28..449d5e7d64 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -26,35 +26,8 @@ #include "llviewerprecompiledheaders.h" -#if LL_MSVC -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" -#if LL_MSVC -#pragma warning (default : 4263) -#pragma warning (default : 4264) -#endif +#include "llmodelloader.h" +#include "lldaeloader.h" #include "llfloatermodelpreview.h" @@ -112,14 +85,15 @@ #include "llanimationstates.h" #include "llviewernetwork.h" #include "llviewershadermgr.h" -#include "glod/glod.h" -const S32 SLM_SUPPORTED_VERSION = 3; +#include "glod/glod.h" +#include <boost/algorithm/string.hpp> //static S32 LLFloaterModelPreview::sUploadAmount = 10; LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; -std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList; + +bool LLModelPreview::sIgnoreLoadedCallback = false; // "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01 // But according to the UI spec for upload model floater, this parameter @@ -199,190 +173,46 @@ std::string lod_label_name[NUM_LOD+1] = "I went off the end of the lod_label_name array. Me so smart." }; -std::string colladaVersion[VERSIONTYPE_COUNT+1] = -{ - "1.4.0", - "1.4.1", - "Unsupported" -}; - - -#define LL_DEGENERACY_TOLERANCE 1e-7f - -inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b) -{ - volatile F32 p0 = a[0] * b[0]; - volatile F32 p1 = a[1] * b[1]; - volatile F32 p2 = a[2] * b[2]; - return p0 + p1 + p2; -} - -bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE) -{ - // small area check - { - LLVector4a edge1; edge1.setSub( a, b ); - LLVector4a edge2; edge2.setSub( a, c ); - ////////////////////////////////////////////////////////////////////////// - /// Linden Modified - ////////////////////////////////////////////////////////////////////////// - - // If no one edge is more than 10x longer than any other edge, we weaken - // the tolerance by a factor of 1e-4f. - - LLVector4a edge3; edge3.setSub( c, b ); - const F32 len1sq = edge1.dot3(edge1).getF32(); - const F32 len2sq = edge2.dot3(edge2).getF32(); - const F32 len3sq = edge3.dot3(edge3).getF32(); - bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); - bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); - bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); - if ( abOK && acOK && cbOK ) - { - tolerance *= 1e-4f; - } - - ////////////////////////////////////////////////////////////////////////// - /// End Modified - ////////////////////////////////////////////////////////////////////////// - - LLVector4a cross; cross.setCross3( edge1, edge2 ); - - LLVector4a edge1b; edge1b.setSub( b, a ); - LLVector4a edge2b; edge2b.setSub( b, c ); - LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); - - if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) - { - return true; - } - } - - // point triangle distance check - { - LLVector4a Q; Q.setSub(a, b); - LLVector4a R; R.setSub(c, b); - - const F32 QQ = dot3fpu(Q, Q); - const F32 RR = dot3fpu(R, R); - const F32 QR = dot3fpu(R, Q); - - volatile F32 QQRR = QQ * RR; - volatile F32 QRQR = QR * QR; - F32 Det = (QQRR - QRQR); - - if( Det == 0.0f ) - { - return true; - } - } - - return false; -} - -bool validate_face(const LLVolumeFace& face) +BOOL stop_gloderror() { + GLuint error = glodGetError(); - for (U32 v = 0; v < face.mNumVertices; v++) - { - if(face.mPositions && !face.mPositions[v].isFinite3()) - { - LL_WARNS() << "NaN position data in face found!" << LL_ENDL; - return false; - } - - if(face.mNormals && !face.mNormals[v].isFinite3()) - { - LL_WARNS() << "NaN normal data in face found!" << LL_ENDL; - return false; - } - } - - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - LL_WARNS() << "Face has invalid index." << LL_ENDL; - return false; - } - } - - if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) + if (error != GLOD_NO_ERROR) { - LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; - return false; + LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; + return TRUE; } - - /*const LLVector4a scale(0.5f); - - - for (U32 i = 0; i < face.mNumIndices; i+=3) - { - U16 idx1 = face.mIndices[i]; - U16 idx2 = face.mIndices[i+1]; - U16 idx3 = face.mIndices[i+2]; - - LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); - LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); - LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); - - if (ll_is_degenerate(v1,v2,v3)) - { - LL_WARNS() << "Degenerate face found!" << LL_ENDL; - return false; - } - }*/ - return true; + return FALSE; } -bool validate_model(const LLModel* mdl) +LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) { - if (mdl->getNumVolumeFaces() == 0) - { - LL_WARNS() << "Model has no faces!" << LL_ENDL; - return false; - } + LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + if (texture) { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - LL_WARNS() << "Face has no vertices." << LL_ENDL; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) + if (texture->getDiscardLevel() > -1) { - LL_WARNS() << "Face has no indices." << LL_ENDL; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) - { - return false; + gGL.getTexUnit(0)->bind(texture, true); + return texture; } } - return true; + return NULL; } -BOOL stop_gloderror() +std::string stripSuffix(std::string name) { - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) + if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1)) { - LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; - return TRUE; + return name.substr(0, name.rfind('_')); } - - return FALSE; + return name; } - LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) - : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) +: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { mMP = mp; mLOD = lod; @@ -393,6 +223,29 @@ void LLMeshFilePicker::notify(const std::string& filename) mMP->loadModel(mFile, mLOD); } +void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +{ + LLModelLoader::scene::iterator base_iter = scene.begin(); + bool found = false; + while (!found && (base_iter != scene.end())) + { + matOut = base_iter->first; + + LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); + while (!found && (base_instance_iter != base_iter->second.end())) + { + LLModelInstance& base_instance = *base_instance_iter++; + LLModel* base_model = base_instance.mModel; + + if (base_model && (base_model->mLabel == name_to_match)) + { + baseModelOut = base_model; + return; + } + } + base_iter++; + } +} //----------------------------------------------------------------------------- // LLFloaterModelPreview() @@ -613,6 +466,11 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option) void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; + if (lod == LLModel::LOD_PHYSICS) + { + // loading physics from file + mModelPreview->mPhysicsSearchLOD = lod; + } (new LLMeshFilePicker(mModelPreview, lod))->getFile(); } @@ -791,9 +649,9 @@ void LLFloaterModelPreview::draw() childSetTextArg("status", "[STATUS]", getString("status_material_mismatch")); } else - if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING ) - { - childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING))); + if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL ) + { + childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL))); } else if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING ) @@ -945,9 +803,16 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) /*virtual*/ void LLFloaterModelPreview::onOpen(const LLSD& key) { + LLModelPreview::sIgnoreLoadedCallback = false; requestAgentUploadPermissions(); } +/*virtual*/ +void LLFloaterModelPreview::onClose(bool app_quitting) +{ + LLModelPreview::sIgnoreLoadedCallback = true; +} + //static void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) { @@ -1308,1815 +1173,6 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl } //----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, - std::deque<std::string>& jointsFromNodes ) -: mJointList( jointMap ) -, mJointsFromNode( jointsFromNodes ) -, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; - - if (mPreview) - { - //only try to load from slm if viewer is configured to do so and this is the - //initial model load (not an LoD or physics shape) - mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty(); - mPreview->setLoadState(STARTING); - } - else - { - mTrySLM = false; - } - - assert_main_thread(); - sActiveLoaderList.push_back(this) ; -} - -LLModelLoader::~LLModelLoader() -{ - assert_main_thread(); - sActiveLoaderList.remove(this); -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; - - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) - { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } - } -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; - - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); - - stretch_extents(model, mata, mina, maxa, first_transform); - - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ - doLoadModel(); - doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); -} - -bool LLModelLoader::doLoadModel() -{ - //first, look for a .slm file of the same name that was modified later - //than the .dae - - if (mTrySLM) - { - std::string filename = mFilename; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size()-1, ".slm"); - llstat slm_status; - if (LLFile::stat(filename, &slm_status) == 0) - { //slm file exists - llstat dae_status; - if (LLFile::stat(mFilename, &dae_status) != 0 || - dae_status.st_mtime < slm_status.st_mtime) - { - if (loadFromSLM(filename)) - { //slm successfully loaded, if this fails, fall through and - //try loading from dae - - mLod = -1; //successfully loading from an slm implicitly sets all - //LoDs - return true; - } - } - } - } - } - - //no suitable slm exists, load from the .dae file - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (!dom) - { - LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL; - setLoadState( ERROR_PARSING ); - return false; - } - //Dom version - daeString domVersion = dae.getDomVersion(); - std::string sldom(domVersion); - LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL; - //Dae version - domVersionType docVersion = dom->getVersion(); - //0=1.4 - //1=1.4.1 - //2=Currently unsupported, however may work - if (docVersion > 1 ) - { - docVersion = VERSIONTYPE_COUNT; - } - LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL; - - - daeDatabase* db = dae.getDatabase(); - - daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); - - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - LL_WARNS() << "can't find internal doc" << LL_ENDL; - return false; - } - - daeElement* root = doc->getDomRoot(); - if (!root) - { - LL_WARNS() << "document has no root" << LL_ENDL; - return false; - } - - //Verify some basic properties of the dae - //1. Basic validity check on controller - U32 controllerCount = (int) db->getElementCount( NULL, "controller" ); - bool result = false; - for ( int i=0; i<controllerCount; ++i ) - { - domController* pController = NULL; - db->getElement( (daeElement**) &pController, i , NULL, "controller" ); - result = mPreview->verifyController( pController ); - if (!result) - { - setLoadState( ERROR_PARSING ); - return true; - } - } - - - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; - - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); - - if (up_axis) - { - up = up_axis->getValue(); - } - - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) - { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); - - if (mesh) - { - LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh); - - if(model->getStatus() != LLModel::NO_ERRORS) - { - setLoadState(ERROR_PARSING + model->getStatus()) ; - return false; //abort - } - - if (model.notNull() && validate_model(model)) - { - mModelList.push_back(model); - mModel[mesh] = model; - } - } - } - - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); - - if (skin) - { - domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - LLMeshSkinInfo& skin_info = model->mSkinInfo; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= skin_info.mBindShapeMatrix; - skin_info.mBindShapeMatrix = trans; - } - - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if ( pSkeleton ) - { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - rootNode = true; - } - - } - if ( !pSkeleton || !rootNode ) - { - daeElement* pScene = root->getDescendant("visual_scene"); - if ( !pScene ) - { - LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL; - missingSkeletonOrScene = true; - } - else - { - //Get the children at this level - daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast<domNode>(children[i]); - if ( isNodeAJoint( pNode ) ) - { - processJointNode( pNode, mJointList ); - } - } - } - } - else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if ( pSkeletonRootNode ) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for ( int i=0; i<jointCnt; ++i, ++jointIt ) - { - //Build a joint for the resolver to work with - char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str() ); - //LL_WARNS()<<"Joint "<< str <<LL_ENDL; - - //Setup the resolver - daeSIDResolver resolver( pSkeletonRootNode, str ); - - //Look for the joint - domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); - if ( pJoint ) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pJoint, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pJoint, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); - - LLMatrix4 workingTransform; - - //Translation via SID - if ( pTranslateA ) - { - extractTranslation( pTranslateA, workingTransform ); - } - else - if ( pTranslateB ) - { - extractTranslation( pTranslateB, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); - if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) - { - LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - missingSkeletonOrScene = true; - } - else - if ( pTranslateElement ) - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - else - { - extractTranslationViaSID( pJoint, workingTransform ); - } - - } - - //Store the joint transform w/respect to it's name. - mJointList[(*jointIt).second.c_str()] = workingTransform; - } - } - - //If anything failed in regards to extracting the skeleton, joints or translation id, - //mention it - if ( missingSkeletonOrScene ) - { - LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; - } - }//got skeleton? - } - - - domSkin::domJoints* joints = skin->getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast<domSource>(elem); - if (source) - { - - - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast<domSource>(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mSkinInfo.mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //Now that we've parsed the joint array, let's determine if we have a full rig - //(which means we have all the joint sthat are required for an avatar versus - //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - buildJointToNodeMappingFromScene( root ); - mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); - - if ( !missingSkeletonOrScene ) - { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if ( mPreview->getRigWithSceneParity() ) - { - std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin(); - std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end(); - for (;masterJointIt!=masterJointItEnd;++masterJointIt ) - { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if ( mJointList.find( lookingForJoint ) != mJointList.end() ) - { - //LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL; - LLMatrix4 jointTransform = mJointList[lookingForJoint]; - LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint ); - if ( pJoint ) - { - LLUUID fake_mesh_id; - fake_mesh_id.generate(); - pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString()); - } - else - { - //Most likely an error in the asset. - LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; - } - } - } - } - } //missingSkeletonOrScene - - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin(); - const int jointCnt = model->mSkinInfo.mJointNames.size(); - for ( int i=0; i<jointCnt; ++i, ++jointIt ) - { - std::string lookingForJoint = (*jointIt).c_str(); - //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key - //and store it in the alternate bind matrix - if ( mJointList.find( lookingForJoint ) != mJointList.end() ) - { - LLMatrix4 jointTransform = mJointList[lookingForJoint]; - LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; - newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); - model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); - } - else - { - LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL; - } - } - - //grab raw position array - - domVertices* verts = mesh->getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - LL_ERRS() << "Invalid position array size." << LL_ENDL; - } - - LLVector3 v(pos[j], pos[j+1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector<LLModel::JointWeight> wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back( weight_list[i] ); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::map<std::string, LLImportMaterial> materials; - for (U32 i = 0; i < model->mMaterialList.size(); ++i) - { - materials[model->mMaterialList[i]] = LLImportMaterial(); - } - mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - LL_WARNS() << "document has no visual_scene" << LL_ENDL; - setLoadState( ERROR_PARSING ); - return true; - } - - setLoadState( DONE ); - - bool badElement = false; - - processElement( scene, badElement ); - - if ( badElement ) - { - setLoadState( ERROR_PARSING ); - } - - return true; -} - -void LLModelLoader::setLoadState(U32 state) -{ - if (mPreview) - { - mPreview->setLoadState(state); - } -} - -bool LLModelLoader::loadFromSLM(const std::string& filename) -{ - //only need to populate mScene with data from slm - llstat stat; - - if (LLFile::stat(filename, &stat)) - { //file does not exist - return false; - } - - S32 file_size = (S32) stat.st_size; - - llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary); - LLSD data; - LLSDSerialize::fromBinary(data, ifstream, file_size); - ifstream.close(); - - //build model list for each LoD - model_list model[LLModel::NUM_LODS]; - - if (data["version"].asInteger() != SLM_SUPPORTED_VERSION) - { //unsupported version - return false; - } - - LLSD& mesh = data["mesh"]; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - for (U32 i = 0; i < mesh.size(); ++i) - { - std::stringstream str(mesh[i].asString()); - LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod); - if (loaded_model->loadModel(str)) - { - loaded_model->mLocalID = i; - model[lod].push_back(loaded_model); - - if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) - { - //check to see if rig is valid - mPreview->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames ); - } - } - } - } - - if (model[LLModel::LOD_HIGH].empty()) - { //failed to load high lod - return false; - } - - // Set name. - std::string name = data["name"]; - if (!name.empty()) - { - model[LLModel::LOD_HIGH][0]->mLabel = name; - } - - - //load instance list - model_instance_list instance_list; - - LLSD& instance = data["instance"]; - - for (U32 i = 0; i < instance.size(); ++i) - { - //deserialize instance list - instance_list.push_back(LLModelInstance(instance[i])); - - //match up model instance pointers - S32 idx = instance_list[i].mLocalMeshID; - - for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (!model[lod].empty()) - { - instance_list[i].mLOD[lod] = model[lod][idx]; - } - } - - instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; - } - - - //convert instance_list to mScene - mFirstTransform = TRUE; - for (U32 i = 0; i < instance_list.size(); ++i) - { - LLModelInstance& cur_instance = instance_list[i]; - mScene[cur_instance.mTransform].push_back(cur_instance); - stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); - } - - setLoadState( DONE ); - - return true; -} - -//static -bool LLModelLoader::isAlive(LLModelLoader* loader) -{ - if(!loader) - { - return false ; - } - - std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ; - for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ; - - return *iter == loader ; -} - -void LLModelLoader::loadModelCallback() -{ - assert_main_thread(); - - if (mPreview) - { - mPreview->loadModelCallback(mLod); - } - - while (!isStopped()) - { //wait until this thread is stopped before deleting self - apr_sleep(100); - } - - //doubel check if "this" is valid before deleting it, in case it is aborted during running. - if(!isAlive(this)) - { - return ; - } - - //cleanup model loader - if (mPreview) - { - mPreview->mModelLoader = NULL; - } - - delete this; -} -//----------------------------------------------------------------------------- -// buildJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot ) -{ - daeElement* pScene = pRoot->getDescendant("visual_scene"); - if ( pScene ) - { - daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); - S32 childCount = children.getCount(); - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast<domNode>(children[i]); - processJointToNodeMapping( pNode ); - } - } -} -//----------------------------------------------------------------------------- -// processJointToNodeMapping() -//----------------------------------------------------------------------------- -void LLModelLoader::processJointToNodeMapping( domNode* pNode ) -{ - if ( isNodeAJoint( pNode ) ) - { - //1.Store the parent - std::string nodeName = pNode->getName(); - if ( !nodeName.empty() ) - { - mJointsFromNode.push_front( pNode->getName() ); - } - //2. Handle the kiddo's - processChildJoints( pNode ); - } - else - { - //Determine if the're any children wrt to this failed node. - //This occurs when an armature is exported and ends up being what essentially amounts to - //as the root for the visual_scene - if ( pNode ) - { - processChildJoints( pNode ); - } - else - { - LL_INFOS()<<"Node is NULL"<<LL_ENDL; - } - - } -} -//----------------------------------------------------------------------------- -// processChildJoint() -//----------------------------------------------------------------------------- -void LLModelLoader::processChildJoints( domNode* pParentNode ) -{ - daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); - if ( pChildNode ) - { - processJointToNodeMapping( pChildNode ); - } - } -} - -//----------------------------------------------------------------------------- -// critiqueRigForUploadApplicability() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ) -{ - critiqueJointToNodeMappingFromScene(); - - //Determines the following use cases for a rig: - //1. It is suitable for upload with skin weights & joint positions, or - //2. It is suitable for upload as standard av with just skin weights - - bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); - bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); - - //It's OK that both could end up being true, both default to false - if ( isJointPositionUploadOK ) - { - setRigValidForJointPositionUpload( true ); - } - - if ( isRigLegacyOK) - { - setLegacyRigValid( true ); - } - -} -//----------------------------------------------------------------------------- -// critiqueJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueJointToNodeMappingFromScene( void ) -{ - //Do the actual nodes back the joint listing from the dae? - //if yes then this is a fully rigged asset, otherwise it's just a partial rig - - std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin(); - std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end(); - bool result = true; - - if ( !mJointsFromNode.empty() ) - { - for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt ) - { - std::string name = *jointsFromNodeIt; - if ( mJointTransformMap.find( name ) != mJointTransformMap.end() ) - { - continue; - } - else - { - LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL; - result = false; - } - } - } - else - { - result = false; - } - - //Determines the following use cases for a rig: - //1. Full av rig w/1-1 mapping from the scene and joint array - //2. Partial rig but w/o parity between the scene and joint array - if ( result ) - { - setRigWithSceneParity( true ); - } -} -//----------------------------------------------------------------------------- -// isRigLegacy() -//----------------------------------------------------------------------------- -bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) -{ - //No joints in asset - if ( jointListFromAsset.size() == 0 ) - { - return false; - } - - bool result = false; - - std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin(); - std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); - - std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) - { - result = false; - modelJointIt = jointListFromAsset.begin(); - - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) - { - if ( *masterJointIt == *modelJointIt ) - { - result = true; - break; - } - } - if ( !result ) - { - LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; - break; - } - } - return result; -} -//----------------------------------------------------------------------------- -// isRigSuitableForJointPositionUpload() -//----------------------------------------------------------------------------- -bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ) -{ - bool result = false; - - std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin(); - std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end(); - - std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) - { - result = false; - modelJointIt = jointListFromAsset.begin(); - - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) - { - if ( *masterJointIt == *modelJointIt ) - { - result = true; - break; - } - } - if ( !result ) - { - LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; - break; - } - } - return result; -} - - -//called in the main thread -void LLModelLoader::loadTextures() -{ - BOOL is_paused = isPaused() ; - pause() ; //pause the loader - - for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) - { - for(U32 i = 0 ; i < iter->second.size(); i++) - { - for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin(); - j != iter->second[i].mMaterial.end(); ++j) - { - LLImportMaterial& material = j->second; - - if(!material.mDiffuseMapFilename.empty()) - { - material.mDiffuseMap = - LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); - material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); - material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX); - mNumOfFetchingTextures++ ; - } - } - } - } - - if(!is_paused) - { - unpause() ; - } -} - -//----------------------------------------------------------------------------- -// isNodeAJoint() -//----------------------------------------------------------------------------- -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ - if ( !pNode ) - { - LL_INFOS()<<"Created node is NULL"<<LL_ENDL; - return false; - } - - if ( pNode->getName() == NULL ) - { - LL_INFOS()<<"Parsed node has no name "<<LL_ENDL; - //Attempt to write the node id, if possible (aids in debugging the visual scene) - if ( pNode->getId() ) - { - LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL; - } - return false; - } - - if ( mJointMap.find( pNode->getName() ) != mJointMap.end() ) - { - return true; - } - - return false; -} -//----------------------------------------------------------------------------- -// verifyCount -//----------------------------------------------------------------------------- -bool LLModelPreview::verifyCount( int expected, int result ) -{ - if ( expected != result ) - { - LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL; - return false; - } - return true; -} -//----------------------------------------------------------------------------- -// verifyController -//----------------------------------------------------------------------------- -bool LLModelPreview::verifyController( domController* pController ) -{ - - bool result = true; - - domSkin* pSkin = pController->getSkin(); - - if ( pSkin ) - { - xsAnyURI & uri = pSkin->getSource(); - domElement* pElement = uri.getElement(); - - if ( !pElement ) - { - LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL; - return false; - } - - daeString type_str = pElement->getTypeName(); - if ( stricmp(type_str, "geometry") == 0 ) - { - //Skin is reference directly by geometry and get the vertex count from skin - domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights(); - U32 vertexWeightsCount = pVertexWeights->getCount(); - domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement(); - domMesh* pMesh = pGeometry->getMesh(); - - if ( pMesh ) - { - //Get vertex count from geometry - domVertices* pVertices = pMesh->getVertices(); - if ( !pVertices ) - { - LL_INFOS()<<"No vertices!"<<LL_ENDL; - return false; - } - - if ( pVertices ) - { - xsAnyURI src = pVertices->getInput_array()[0]->getSource(); - domSource* pSource = (domSource*) (domElement*) src.getElement(); - U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount(); - result = verifyCount( verticesCount, vertexWeightsCount ); - if ( !result ) - { - return result; - } - } - } - - U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount(); - result = verifyCount( vcountCount, vertexWeightsCount ); - if ( !result ) - { - return result; - } - - domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array(); - U32 sum = 0; - for (size_t i=0; i<vcountCount; i++) - { - sum += pVertexWeights->getVcount()->getValue()[i]; - } - result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() ); - } - } - - return result; -} - -//----------------------------------------------------------------------------- -// extractTranslation() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); - transform.setTranslation( singleJointTranslation ); -} -//----------------------------------------------------------------------------- -// extractTranslationViaElement() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ - if ( pTranslateElement ) - { - domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement ); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); - transform.setTranslation( singleJointTranslation ); - } -} -//----------------------------------------------------------------------------- -// extractTranslationViaSID() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ) -{ - if ( pElement ) - { - daeSIDResolver resolver( pElement, "./transform" ); - domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() ); - //We are only extracting out the translational component atm - LLMatrix4 workingTransform; - if ( pMatrix ) - { - domFloat4x4 domArray = pMatrix->getValue(); - for ( int i = 0; i < 4; i++ ) - { - for( int j = 0; j < 4; j++ ) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - LLVector3 trans = workingTransform.getTranslation(); - transform.setTranslation( trans ); - } - } - else - { - LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL; - } -} -//----------------------------------------------------------------------------- -// processJointNode() -//----------------------------------------------------------------------------- -void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms ) -{ - if (pNode->getName() == NULL) - { - LL_WARNS() << "nameless node, can't process" << LL_ENDL; - return; - } - - //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL; - - //1. handle the incoming node - extract out translation via SID or element - - LLMatrix4 workingTransform; - - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pNode, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pNode, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); - - //Translation via SID was successful - if ( pTranslateA ) - { - extractTranslation( pTranslateA, workingTransform ); - } - else - if ( pTranslateB ) - { - extractTranslation( pTranslateB, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); - if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) - { - //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - daeSIDResolver jointResolver( pNode, "./matrix" ); - domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() ); - if ( pMatrix ) - { - //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; - domFloat4x4 domArray = pMatrix->getValue(); - for ( int i = 0; i < 4; i++ ) - { - for( int j = 0; j < 4; j++ ) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - } - else - { - LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL; - } - } - else - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - } - - //Store the working transform relative to the nodes name. - jointTransforms[ pNode->getName() ] = workingTransform; - - //2. handle the nodes children - - //Gather and handle the incoming nodes children - daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); - if ( pChildNode ) - { - processJointNode( pChildNode, jointTransforms ); - } - } -} -//----------------------------------------------------------------------------- -// getChildFromElement() -//----------------------------------------------------------------------------- -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ - daeElement* pChildOfElement = pElement->getChild( name.c_str() ); - if ( pChildOfElement ) - { - return pChildOfElement; - } - LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; - return NULL; -} - -void LLModelLoader::processElement( daeElement* element, bool& badElement ) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast<domTranslate>(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast<domRotate>(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast<domScale>(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - - LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]); - scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes - LLMatrix4 scaling; - scaling.initScale(scale_vector); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast<domMatrix>(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for(int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - if (mTransform.determinant() < 0) - { //negative scales are not supported - LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL; - badElement = true; - } - - std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::string label = getElementLabel(instance_geo); - mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - else - { - LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL; - badElement = true; - } - - } - - domInstance_node* instance_node = daeSafeCast<domInstance_node>(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance,badElement); - } - } - - //process children - daeTArray< daeSmartRef<daeElement> > children = element->getChildren(); - int childCount = children.getCount(); - for (S32 i = 0; i < childCount; i++) - { - processElement(children[i],badElement); - } - - domNode* node = daeSafeCast<domNode>(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::map<std::string, LLImportMaterial> materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - import_material.mBinding = model->mMaterialList[i]; - materials[model->mMaterialList[i]] = import_material; - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- // LLModelPreview //----------------------------------------------------------------------------- @@ -3125,7 +1181,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mPelvisZOffset( 0.0f ) , mLegacyRigValid( false ) , mRigValidJointUpload( false ) +, mPhysicsSearchLOD( LLModel::LOD_PHYSICS ) , mResetJoints( false ) +, mModelNoErrors( true ) , mRigParityWithScene( false ) , mLastJointUpdate( false ) { @@ -3170,51 +1228,20 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) glodInit(); - //move into joint mapper class - //1. joints for joint offset verification - mMasterJointList.push_front("mPelvis"); - mMasterJointList.push_front("mTorso"); - mMasterJointList.push_front("mChest"); - mMasterJointList.push_front("mNeck"); - mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mCollarLeft"); - mMasterJointList.push_front("mShoulderLeft"); - mMasterJointList.push_front("mElbowLeft"); - mMasterJointList.push_front("mWristLeft"); - mMasterJointList.push_front("mCollarRight"); - mMasterJointList.push_front("mShoulderRight"); - mMasterJointList.push_front("mElbowRight"); - mMasterJointList.push_front("mWristRight"); - mMasterJointList.push_front("mHipRight"); - mMasterJointList.push_front("mKneeRight"); - mMasterJointList.push_front("mFootRight"); - mMasterJointList.push_front("mHipLeft"); - mMasterJointList.push_front("mKneeLeft"); - mMasterJointList.push_front("mFootLeft"); - //2. legacy joint list - used to verify rigs that will not be using joint offsets - mMasterLegacyJointList.push_front("mPelvis"); - mMasterLegacyJointList.push_front("mTorso"); - mMasterLegacyJointList.push_front("mChest"); - mMasterLegacyJointList.push_front("mNeck"); - mMasterLegacyJointList.push_front("mHead"); - mMasterLegacyJointList.push_front("mHipRight"); - mMasterLegacyJointList.push_front("mKneeRight"); - mMasterLegacyJointList.push_front("mFootRight"); - mMasterLegacyJointList.push_front("mHipLeft"); - mMasterLegacyJointList.push_front("mKneeLeft"); - mMasterLegacyJointList.push_front("mFootLeft"); - createPreviewAvatar(); } LLModelPreview::~LLModelPreview() { - if (mModelLoader) - { - mModelLoader->mPreview = NULL; - mModelLoader = NULL; - } - //*HACK : *TODO : turn this back on when we understand why this crashes + // glod apparently has internal mem alignment issues that are angering + // the heap-check code in windows, these should be hunted down in that + // TP code, if possible + // + // kernel32.dll!HeapFree() + 0x14 bytes + // msvcr100.dll!free(void * pBlock) Line 51 C + // glod.dll!glodGetGroupParameteriv() + 0x119 bytes + // glod.dll!glodShutdown() + 0x77 bytes + // //glodShutdown(); } @@ -3284,7 +1311,9 @@ U32 LLModelPreview::calcResourceCost() decomp, mFMP->childGetValue("upload_skin").asBoolean(), mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); + TRUE, + FALSE, + instance.mModel->mSubmodelID); num_hulls += decomp.mHull.size(); for (U32 i = 0; i < decomp.mHull.size(); ++i) @@ -3351,29 +1380,12 @@ void LLModelPreview::rebuildUploadData() F32 max_scale = 0.f; - //reorder materials to match mBaseModel - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - if (mBaseModel.size() == mModel[i].size()) - { - for (U32 j = 0; j < mBaseModel.size(); ++j) - { - - int refFaceCnt = 0; - int modelFaceCnt = 0; - - if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable( "calculate_btn" ); - } - } - } - } + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene - LLMatrix4 mat = iter->first; + LLMatrix4 mat = iter->first; // compute position LLVector3 position = LLVector3(0, 0, 0) * mat; @@ -3390,38 +1402,171 @@ void LLModelPreview::rebuildUploadData() mat *= scale_mat; - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter; + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter++; LLModel* base_model = instance.mModel; - if (base_model) + if (base_model && !requested_name.empty()) { base_model->mRequestedLabel = requested_name; base_model->mMetric = metric; } - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) + for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) + { + LLModel* lod_model = NULL; + if (!legacyMatching) { - break; + // Fill LOD slots by finding matching meshes by label with name extensions + // in the appropriate scene for each LOD. This fixes all kinds of issues + // where the indexed method below fails in spectacular fashion. + // If you don't take the time to name your LOD and PHYS meshes + // with the name of their corresponding mesh in the HIGH LOD, + // then the indexed method will be attempted below. + + LLMatrix4 transform; + + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + int extensionLOD; + if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) + { + extensionLOD = i; + } + else + { + //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for + extensionLOD = mPhysicsSearchLOD; + } + + std::string toAdd; + switch (extensionLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == -1) + { + name_to_match += toAdd; + } + + FindModel(mScene[i], name_to_match, lod_model, transform); + + if (!lod_model && i != LLModel::LOD_PHYSICS) + { + if (importerDebug) + { + LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; + } + + int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; + while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) + { + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + std::string toAdd; + switch (searchLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == -1) + { + name_to_match += toAdd; + } + + // See if we can find an appropriately named model in LOD 'searchLOD' + // + FindModel(mScene[searchLOD], name_to_match, lod_model, transform); + searchLOD++; + } + } } - } + else + { + // Use old method of index-based association + U32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { + // find reference instance for this model + if (mBaseModel[idx] == base_model) + { + if (importerDebug) + { + LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; + } + break; + } + } - if(idx < mBaseModel.size()) - { - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index + // If the model list for the current LOD includes that index... + // if (mModel[i].size() > idx) { - instance.mLOD[i] = mModel[i][idx]; + // Assign that index from the model list for our LOD as the LOD model for this instance + // + lod_model = mModel[i][idx]; + if (importerDebug) + { + LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL; + } } - else + else if (importerDebug) { - instance.mLOD[i] = NULL; + LL_INFOS() << "List of models does not include index " << idx << LL_ENDL; + } + } + + if (lod_model) + { + if (importerDebug) + { + if (i == LLModel::LOD_PHYSICS) + { + LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; + } + else + { + LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; + } + } + instance.mLOD[i] = lod_model; + } + else if (importerDebug) + { + LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL; + } + } + + LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; + if (!high_lod_model) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } + else + { + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + int refFaceCnt = 0; + int modelFaceCnt = 0; + llassert(instance.mLOD[i]); + if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); } } } @@ -3430,6 +1575,34 @@ void LLModelPreview::rebuildUploadData() } } + for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++) + { + // Search for models that are not included into upload data + // If we found any, that means something we loaded is not a sub-model. + for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) + { + bool found_model = false; + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + if (instance.mLOD[lod] == mModel[lod][model_ind]) + { + found_model = true; + break; + } + } + if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) + { + if (importerDebug) + { + LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL; + } + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } + } + } + F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale; F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); @@ -3496,7 +1669,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw meshes.insert(instance.mModel); std::stringstream str; - LLModel::Decomposition& decomp = instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : @@ -3509,8 +1681,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw instance.mLOD[LLModel::LOD_LOW], instance.mLOD[LLModel::LOD_IMPOSTOR], decomp, - save_skinweights, save_joint_positions, FALSE, TRUE); - + save_skinweights, save_joint_positions, + FALSE, TRUE, instance.mModel->mSubmodelID); data["mesh"][instance.mModel->mLocalID] = str.str(); } @@ -3578,13 +1750,28 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable clearGLODGroup(); } - mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode ); + mModelLoader = new LLDAELoader( + filename, + lod, + &LLModelPreview::loadedCallback, + &LLModelPreview::lookupJointByName, + &LLModelPreview::loadTextures, + &LLModelPreview::stateChangedCallback, + this, + mJointTransformMap, + mJointsFromNode, + gSavedSettings.getU32("ImporterModelLimit")); if (force_disable_slm) { mModelLoader->mTrySLM = false; } - + else + { + //only try to load from slm if viewer is configured to do so and this is the + //initial model load (not an LoD or physics shape) + mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); + } mModelLoader->start(); mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); @@ -3615,6 +1802,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod) if (lod >= 0 && lod <= 3) { + mPhysicsSearchLOD = lod; mModel[LLModel::LOD_PHYSICS] = mModel[lod]; mScene[LLModel::LOD_PHYSICS] = mScene[lod]; mLODFile[LLModel::LOD_PHYSICS].clear(); @@ -3634,11 +1822,14 @@ void LLModelPreview::clearIncompatible(S32 lod) return; } + // at this point we don't care about sub-models, + // different amount of sub-models means face count mismatch, not incompatibility + U32 lod_size = countRootModels(mModel[lod]); for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) { //clear out any entries that aren't compatible with this model if (i != lod) { - if (mModel[i].size() != mModel[lod].size()) + if (countRootModels(mModel[i]) != lod_size) { mModel[i].clear(); mScene[i].clear(); @@ -3673,7 +1864,7 @@ void LLModelPreview::clearGLODGroup() } } -void LLModelPreview::loadModelCallback(S32 lod) +void LLModelPreview::loadModelCallback(S32 loaded_lod) { assert_main_thread(); @@ -3686,12 +1877,18 @@ void LLModelPreview::loadModelCallback(S32 lod) if(getLoadState() >= LLModelLoader::ERROR_PARSING) { mLoading = false ; + mModelLoader = NULL; return ; } + // Copy determinations about rig so UI will reflect them + // + setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); + setLegacyRigValid(mModelLoader->isLegacyRigValid()); + mModelLoader->loadTextures() ; - if (lod == -1) + if (loaded_lod == -1) { //populate all LoDs from model loader scene mBaseModel.clear(); mBaseScene.clear(); @@ -3723,6 +1920,11 @@ void LLModelPreview::loadModelCallback(S32 lod) //override displayed model with current LoD list_iter->mModel = list_iter->mLOD[lod]; + if (!list_iter->mModel) + { + continue; + } + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) S32 idx = list_iter->mModel->mLocalID; @@ -3731,7 +1933,7 @@ void LLModelPreview::loadModelCallback(S32 lod) mModel[lod].resize(idx+1); } - mModel[lod][idx] = list_iter->mModel; + mModel[lod][idx] = list_iter->mModel; if (!list_iter->mModel->mSkinWeights.empty()) { skin_weights = true; @@ -3774,31 +1976,108 @@ void LLModelPreview::loadModelCallback(S32 lod) } else { //only replace given LoD - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); + mModel[loaded_lod] = mModelLoader->mModelList; + mScene[loaded_lod] = mModelLoader->mScene; + mVertexBuffer[loaded_lod].clear(); - setPreviewLOD(lod); + setPreviewLOD(loaded_lod); - if (lod == LLModel::LOD_HIGH) + if (loaded_lod == LLModel::LOD_HIGH) { //save a copy of the highest LOD for automatic LOD manipulation if (mBaseModel.empty()) { //first time we've loaded a model, auto-gen LoD mGenLOD = true; } - mBaseModel = mModel[lod]; + mBaseModel = mModel[loaded_lod]; clearGLODGroup(); - mBaseScene = mScene[lod]; + mBaseScene = mScene[loaded_lod]; mVertexBuffer[5].clear(); } + else + { + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + if (!legacyMatching) + { + if (!mBaseModel.empty()) + { + BOOL name_based = FALSE; + BOOL has_submodels = FALSE; + for (U32 idx = 0; idx < mBaseModel.size(); ++idx) + { + if (mBaseModel[idx]->mSubmodelID) + { // don't do index-based renaming when the base model has submodels + has_submodels = TRUE; + if (importerDebug) + { + LL_INFOS() << "High LOD has submodels" << LL_ENDL; + } + break; + } + } + + for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx) + { + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + LLModel* found_model = NULL; + LLMatrix4 transform; + FindModel(mBaseScene, loaded_name, found_model, transform); + if (found_model) + { // don't rename correctly named models (even if they are placed in a wrong order) + name_based = TRUE; + } + + if (mModel[loaded_lod][idx]->mSubmodelID) + { // don't rename the models when loaded LOD model has submodels + has_submodels = TRUE; + } + } + + if (importerDebug) + { + LL_INFOS() << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found" << LL_ENDL; + } + + if (!name_based && !has_submodels) + { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601) + // this actually works like "ImporterLegacyMatching" for this particular LOD + for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx) + { + std::string name = mBaseModel[idx]->mLabel; + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + if (loaded_name != name) + { + switch (loaded_lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (importerDebug) + { + LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL; + } - clearIncompatible(lod); + mModel[loaded_lod][idx]->mLabel = name; + } + } + } + } + } + } + + clearIncompatible(loaded_lod); mDirty = true; - if (lod == LLModel::LOD_HIGH) + if (loaded_lod == LLModel::LOD_HIGH) { resetPreviewTarget(); } @@ -3817,6 +2096,8 @@ void LLModelPreview::loadModelCallback(S32 lod) refresh(); mModelLoadedSignal(); + + mModelLoader = NULL; } void LLModelPreview::resetPreviewTarget() @@ -4165,6 +2446,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + std::string name = base->mLabel; + + switch (lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + mModel[lod][mdl_idx]->mLabel = name; + mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; + GLint* sizes = new GLint[patch_count*2]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); stop_gloderror(); @@ -4277,17 +2572,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { shader->bind(); } - - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ } void LLModelPreview::updateStatusMessages() @@ -4304,43 +2588,89 @@ void LLModelPreview::updateStatusMessages() S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + total_tris[i] = 0; + total_verts[i] = 0; + total_submeshes[i] = 0; + } + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + LLModelInstance& instance = *iter; - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter) + LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; + if (!model_high_lod) { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - LLModel* model = instance->mModel; - if (model) - { - //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = model->getNumVolumeFaces(); + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + continue; + } - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + LLModel* lod_model = instance.mLOD[i]; + if (!lod_model) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } + + int refFaceCnt = 0; + int modelFaceCnt = 0; + + if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) ) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; + if (lod_model) + { + //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = lod_model->getNumVolumeFaces(); - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = lod_model->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; } + + std::string instance_name = instance.mLabel; + + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + if (importerDebug) + { + // Useful for debugging generalized complaints below about total submeshes which don't have enough + // context to address exactly what needs to be fixed to move towards compliance with the rules. + // + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL; + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL; + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL; + + LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); + while (mat_iter != lod_model->mMaterialList.end()) + { + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL; + mat_iter++; + } + } + + //add this model to the lod total + total_tris[i] += cur_tris; + total_verts[i] += cur_verts; + total_submeshes[i] += cur_submeshes; + + //store this model's counts to asset data + tris[i].push_back(cur_tris); + verts[i].push_back(cur_verts); + submeshes[i].push_back(cur_submeshes); } } - } + } if (mMaxTriangleLimit == 0) { @@ -4354,37 +2684,48 @@ void LLModelPreview::updateStatusMessages() const LLVector4a scale(0.5f); for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i) { //for each model in the lod - if (mModel[lod][i]->mPhysics.mHull.empty()) + if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty()) { //no decomp exists S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j) { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - for (S32 k = 0; k < face.mNumIndices && !has_degenerate; ) + LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; ) { - LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale); - LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale); - LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale); + U16 index_a = face.mIndices[k+0]; + U16 index_b = face.mIndices[k+1]; + U16 index_c = face.mIndices[k+2]; + + LLVector4a v1; v1.setMul(face.mPositions[index_a], scale); + LLVector4a v2; v2.setMul(face.mPositions[index_b], scale); + LLVector4a v3; v3.setMul(face.mPositions[index_c], scale); if (ll_is_degenerate(v1,v2,v3)) { has_degenerate = true; } + else + { + k += 3; + } } } } } } - + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); std::string mesh_status_na = mFMP->getString("mesh_status_na"); S32 upload_status[LLModel::LOD_HIGH+1]; - bool upload_ok = true; + mModelNoErrors = true; - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + const U32 lod_high = LLModel::LOD_HIGH; + U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); + + for (S32 lod = 0; lod <= lod_high; ++lod) { upload_status[lod] = 0; @@ -4397,7 +2738,7 @@ void LLModelPreview::updateStatusMessages() } else { - if (lod == LLModel::LOD_HIGH) + if (lod == lod_high) { upload_status[lod] = 2; message = "mesh_status_missing_lod"; @@ -4418,8 +2759,6 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na); } - const U32 lod_high = LLModel::LOD_HIGH; - if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -4427,6 +2766,13 @@ void LLModelPreview::updateStatusMessages() message = "mesh_status_submesh_mismatch"; upload_status[lod] = 2; } + else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) + {//number of submodels is different, not all faces are matched correctly. + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + // Note: Submodels in instance were loaded from higher LOD and as result face count + // returns same value and total_submeshes[lod] is identical to high_lod one. + } else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) { //number of meshes is different message = "mesh_status_mesh_mismatch"; @@ -4447,7 +2793,7 @@ void LLModelPreview::updateStatusMessages() { //too many vertices in this lod message = "mesh_status_too_many_vertices"; - upload_status[lod] = 2; + upload_status[lod] = 1; } } } @@ -4459,7 +2805,7 @@ void LLModelPreview::updateStatusMessages() if (upload_status[lod] >= 2) { - upload_ok = false; + mModelNoErrors = false; } if (lod == mPreviewLOD) @@ -4473,23 +2819,41 @@ void LLModelPreview::updateStatusMessages() } - //make sure no hulls have more than 256 points in them - for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + //warn if hulls have more than 256 points in them + BOOL physExceededVertexLimit = FALSE; + for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) { LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; - for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j) + if (mdl) { - if (mdl->mPhysics.mHull[j].size() > 256) + for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) { - upload_ok = false; + if (mdl->mPhysics.mHull[j].size() > 256) + { + physExceededVertexLimit = TRUE; + LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; + break; + } } } } + mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); + LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon"); + physStatusIcon->setVisible(physExceededVertexLimit); + if (physExceededVertexLimit) + { + mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded")); + LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning"); + physStatusIcon->setImage(img); + } - bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mModelNoErrors = false; + LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; + } - bool skinAndRigOk = true; bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); @@ -4497,19 +2861,23 @@ void LLModelPreview::updateStatusMessages() { if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) { - skinAndRigOk = false; - } + mModelNoErrors = false; + LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; + } } - - if(upload_ok && mModelLoader) + + if(mModelNoErrors && mModelLoader) { if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) { - upload_ok = false ; + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; } } - if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate) + // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics + // current use of has_degenerate won't block upload permanently - later checks will restore the button + if (!mModelNoErrors || has_degenerate) { mFMP->childDisable("ok_btn"); } @@ -4851,7 +3219,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLModel* base_mdl = *base_iter; base_iter++; - for (S32 i = 0, e = mdl->getNumVolumeFaces(); i < e; ++i) + S32 num_faces = mdl->getNumVolumeFaces(); + for (S32 i = 0; i < num_faces; ++i) { const LLVolumeFace &vf = mdl->getVolumeFace(i); U32 num_vertices = vf.mNumVertices; @@ -4946,23 +3315,23 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) void LLModelPreview::update() { - if (mDirty) + if (mGenLOD) { - mDirty = false; - mResourceCost = calcResourceCost(); + mGenLOD = false; + genLODs(); refresh(); updateStatusMessages(); } - if (mGenLOD) + if (mDirty) { - mGenLOD = false; - genLODs(); + mDirty = false; + mResourceCost = calcResourceCost(); refresh(); updateStatusMessages(); } - } + //----------------------------------------------------------------------------- // getTranslationForJointOffset() //----------------------------------------------------------------------------- @@ -4996,8 +3365,77 @@ void LLModelPreview::createPreviewAvatar( void ) } else { - LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL; + LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; + } +} + +//static +U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) +{ + U32 root_models = 0; + model_list::iterator model_iter = models.begin(); + while (model_iter != models.end()) + { + LLModel* mdl = *model_iter; + if (mdl && mdl->mSubmodelID == 0) + { + root_models++; + } + model_iter++; + } + return root_models; +} + +void LLModelPreview::loadedCallback( + LLModelLoader::scene& scene, + LLModelLoader::model_list& model_list, + S32 lod, + void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) + { + pPreview->loadModelCallback(lod); + } +} + +void LLModelPreview::stateChangedCallback(U32 state,void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + pPreview->setLoadState(state); + } +} + +LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + return pPreview->getPreviewAvatar()->getJoint(str); + } + return NULL; +} + +U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque) +{ + (void)opaque; + + if (material.mDiffuseMapFilename.size()) + { + material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; + LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); + + tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); + tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); + tex->forceToSaveRawImage(0, F32_MAX); + material.setDiffuseMap(tex->getID()); // record tex ID + return 1; } + + material.mOpaqueData = NULL; + return 0; } void LLModelPreview::addEmptyFace( LLModel* pTarget ) @@ -5245,7 +3683,7 @@ BOOL LLModelPreview::render() } else { - LL_INFOS(" ") << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; regen = TRUE; } } @@ -5255,24 +3693,6 @@ BOOL LLModelPreview::render() genBuffers(mPreviewLOD, skin_weight); } - //make sure material lists all match - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - if (mBaseModel.size() == mModel[i].size()) - { - for (U32 j = 0; j < mBaseModel.size(); ++j) - { - int refFaceCnt = 0; - int modelFaceCnt = 0; - - if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) - { - mFMP->childDisable( "calculate_btn" ); - } - } - } - } - if (!skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) @@ -5281,62 +3701,63 @@ BOOL LLModelPreview::render() LLModel* model = instance.mLOD[mPreviewLOD]; - if (!model) - { - continue; - } + if (!model) + { + continue; + } - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; - gGL.multMatrix((GLfloat*) mat.mMatrix); + gGL.multMatrix((GLfloat*) mat.mMatrix); - for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - if (textures) + U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < num_models; ++i) { - int materialCnt = instance.mModel->mMaterialList.size(); - if ( i < materialCnt ) + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + + if (textures) { - const std::string& binding = instance.mModel->mMaterialList[i]; - const LLImportMaterial& material = instance.mMaterial[binding]; + int materialCnt = instance.mModel->mMaterialList.size(); + if ( i < materialCnt ) + { + const std::string& binding = instance.mModel->mMaterialList[i]; + const LLImportMaterial& material = instance.mMaterial[binding]; - gGL.diffuseColor4fv(material.mDiffuseColor.mV); + gGL.diffuseColor4fv(material.mDiffuseColor.mV); - if (material.mDiffuseMap.notNull()) - { - if (material.mDiffuseMap->getDiscardLevel() > -1) + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) { - gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); - mTextureSet.insert(material.mDiffuseMap.get()); + mTextureSet.insert(tex); } } } - } - else - { - gGL.diffuseColor4f(1,1,1,1); - } - - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); + else + { + gGL.diffuseColor4f(1,1,1,1); + } - if (edges) - { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); + + if (edges) + { + glLineWidth(3.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } } + gGL.popMatrix(); } - gGL.popMatrix(); - } if (physics) { @@ -5364,97 +3785,99 @@ BOOL LLModelPreview::render() LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - if (!model) - { - continue; - } + if (!model) + { + continue; + } - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; gGL.multMatrix((GLfloat*) mat.mMatrix); - bool render_mesh = true; + bool render_mesh = true; - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); - LLModel::Decomposition& physics = model->mPhysics; + LLModel::Decomposition& physics = model->mPhysics; - if (!physics.mHull.empty()) - { - render_mesh = false; + if (!physics.mHull.empty()) + { + render_mesh = false; - if (physics.mMesh.empty()) - { //build vertex buffer for physics mesh - gMeshRepo.buildPhysicsMesh(physics); - } + if (physics.mMesh.empty()) + { //build vertex buffer for physics mesh + gMeshRepo.buildPhysicsMesh(physics); + } - if (!physics.mMesh.empty()) - { //render hull instead of mesh - for (U32 i = 0; i < physics.mMesh.size(); ++i) - { - if (explode > 0.f) + if (!physics.mMesh.empty()) + { //render hull instead of mesh + for (U32 i = 0; i < physics.mMesh.size(); ++i) { - gGL.pushMatrix(); + if (explode > 0.f) + { + gGL.pushMatrix(); - LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; - offset *= explode; + LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; + offset *= explode; - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } - static std::vector<LLColor4U> hull_colors; + static std::vector<LLColor4U> hull_colors; - if (i+1 >= hull_colors.size()) - { - hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); - } + if (i+1 >= hull_colors.size()) + { + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); + } - gGL.diffuseColor4ubv(hull_colors[i].mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); + gGL.diffuseColor4ubv(hull_colors[i].mV); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); - if (explode > 0.f) - { - gGL.popMatrix(); + if (explode > 0.f) + { + gGL.popMatrix(); + } } } } } - } - - if (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + + if (render_mesh) { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + for (U32 i = 0; i < num_models; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); - buffer->setBuffer(type_mask & buffer->getTypeMask()); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + buffer->setBuffer(type_mask & buffer->getTypeMask()); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - gGL.diffuseColor3f(1.f, 1.f, 0.f); + gGL.diffuseColor3f(1.f, 1.f, 0.f); - glLineWidth(2.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + glLineWidth(2.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } } - } - gGL.popMatrix(); - } + gGL.popMatrix(); + } glLineWidth(3.f); glPointSize(8.f); @@ -5635,20 +4058,20 @@ BOOL LLModelPreview::render() position[j] = v; } - llassert(model->mMaterialList.size() > i); + llassert(model->mMaterialList.size() > i); const std::string& binding = instance.mModel->mMaterialList[i]; const LLImportMaterial& material = instance.mMaterial[binding]; buffer->setBuffer(type_mask & buffer->getTypeMask()); gGL.diffuseColor4fv(material.mDiffuseColor.mV); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (material.mDiffuseMap.notNull()) + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) { - if (material.mDiffuseMap->getDiscardLevel() > -1) - { - gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); - mTextureSet.insert(material.mDiffuseMap.get()); - } + mTextureSet.insert(tex); } buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); @@ -5763,14 +4186,14 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); LLModelPreview* mp = fmp->mModelPreview; - std::string filename = mp->mLODFile[3]; + std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; fmp->resetDisplayOptions(); //reset model preview fmp->initModelPreview(); mp = fmp->mModelPreview; - mp->loadModel(filename,3,true); + mp->loadModel(filename,LLModel::LOD_HIGH,true); } //static @@ -5864,7 +4287,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) } mUploadBtn->setVisible(!visible); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + mUploadBtn->setEnabled(isModelUploadAllowed()); if (visible) { @@ -5930,7 +4353,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger())); childSetVisible("upload_fee", true); childSetVisible("price_breakdown", true); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + mUploadBtn->setEnabled(isModelUploadAllowed()); } void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) @@ -5954,6 +4377,16 @@ void LLFloaterModelPreview::onModelUploadFailure() mUploadBtn->setEnabled(true); } +bool LLFloaterModelPreview::isModelUploadAllowed() +{ + bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty(); + if (mModelPreview) + { + allow_upload &= mModelPreview->mModelNoErrors; + } + return allow_upload; +} + S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) { if (mContinue) @@ -6003,8 +4436,17 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result) // BAP HACK: handle "" for case that MeshUploadFlag cap is broken. mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status)); - //mUploadBtn->setEnabled(mHasUploadPerm); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + if (!mHasUploadPerm) + { + LL_WARNS() << "Upload permission set to false because upload_status=\"" << upload_status << "\"" << LL_ENDL; + } + else if (mHasUploadPerm && mUploadModelUrl.empty()) + { + LL_WARNS() << "Upload permission set to true but uploadModelUrl is empty!" << LL_ENDL; + } + + // isModelUploadAllowed() includes mHasUploadPerm + mUploadBtn->setEnabled(isModelUploadAllowed()); getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm); getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 618748bd4e..7a518c798b 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -37,6 +37,8 @@ #include "llviewermenufile.h" #include "llfloatermodeluploadbase.h" +#include "lldaeloader.h" + class LLComboBox; class LLJoint; class LLViewerJointMesh; @@ -45,103 +47,18 @@ class LLTextBox; class LLVertexBuffer; class LLModelPreview; class LLFloaterModelPreview; +class DAE; class daeElement; class domProfile_COMMON; class domInstance_geometry; class domNode; class domTranslate; class domController; +class domSkin; +class domMesh; class LLMenuButton; class LLToggleableMenu; -typedef std::map<std::string, LLMatrix4> JointTransformMap; -typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt; - -const S32 NUM_LOD = 4; - -class LLModelLoader : public LLThread -{ -public: - typedef enum - { - STARTING = 0, - READING_FILE, - CREATING_FACES, - GENERATING_VERTEX_BUFFERS, - GENERATING_LOD, - DONE, - ERROR_PARSING, //basically loading failed - ERROR_MATERIALS, - } eLoadState; - - U32 mState; - std::string mFilename; - S32 mLod; - LLModelPreview* mPreview; - LLMatrix4 mTransform; - BOOL mFirstTransform; - LLVector3 mExtents[2]; - bool mTrySLM; - - std::map<daeElement*, LLPointer<LLModel> > mModel; - - typedef std::vector<LLPointer<LLModel> > model_list; - model_list mModelList; - - typedef std::vector<LLModelInstance> model_instance_list; - - typedef std::map<LLMatrix4, model_instance_list > scene; - - scene mScene; - - typedef std::queue<LLPointer<LLModel> > model_queue; - - //queue of models that need a physics rep - model_queue mPhysicsQ; - - LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, - std::deque<std::string>& jointsFromNodes ); - ~LLModelLoader() ; - - virtual void run(); - bool doLoadModel(); - bool loadFromSLM(const std::string& filename); - void loadModelCallback(); - - void loadTextures() ; //called in the main thread. - void processElement(daeElement* element, bool& badElement); - std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo); - LLImportMaterial profileToMaterial(domProfile_COMMON* material); - std::string getElementLabel(daeElement *element); - LLColor4 getDaeColor(daeElement* element); - - daeElement* getChildFromElement( daeElement* pElement, std::string const & name ); - - bool isNodeAJoint( domNode* pNode ); - void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms ); - void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ); - void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ); - void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ); - - void setLoadState(U32 state); - - void buildJointToNodeMappingFromScene( daeElement* pRoot ); - void processJointToNodeMapping( domNode* pNode ); - void processChildJoints( domNode* pParentNode ); - - //map of avatar joints as named in COLLADA assets to internal joint names - std::map<std::string, std::string> mJointMap; - JointTransformMap& mJointList; - std::deque<std::string>& mJointsFromNode; - - S32 mNumOfFetchingTextures ; //updated in the main thread - bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. - -private: - static std::list<LLModelLoader*> sActiveLoaderList; - static bool isAlive(LLModelLoader* loader) ; -}; - class LLFloaterModelPreview : public LLFloaterModelUploadBase { public: @@ -172,6 +89,7 @@ public: BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } @@ -210,6 +128,8 @@ public: /*virtual*/ void onModelUploadFailure(); + bool isModelUploadAllowed(); + protected: friend class LLModelPreview; friend class LLMeshFilePicker; @@ -359,21 +279,14 @@ public: void setHasPivot( bool val ) { mHasPivot = val; } void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } - //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) - void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ); - void critiqueJointToNodeMappingFromScene( void ); //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions //Accessors for joint position upload friendly rigs const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } - bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); - //Determines if a rig is a legacy from the joint list - bool isRigLegacy( const std::vector<std::string> &jointListFromAsset ); + //Accessors for the legacy rigs const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } - void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } - //Verify that a controller matches vertex counts - bool verifyController( domController* pController ); + void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); @@ -388,6 +301,16 @@ public: LLVector3 getTranslationForJointOffset( std::string joint ); + static bool sIgnoreLoadedCallback; + +protected: + + static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); + static void stateChangedCallback(U32 state, void* opaque); + + static LLJoint* lookupJointByName(const std::string&, void* opaque); + static U32 loadTextures(LLImportMaterial& material, void* opaque); + private: //Utility function for controller vertex compare bool verifyCount( int expected, int result ); @@ -395,6 +318,8 @@ private: void createPreviewAvatar( void ); //Accessor for the dummy avatar LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } + // Count amount of original models, excluding sub-models + static U32 countRootModels(LLModelLoader::model_list models); protected: friend class LLModelLoader; @@ -416,13 +341,15 @@ private: LLVector3 mPreviewTarget; LLVector3 mPreviewScale; S32 mPreviewLOD; + S32 mPhysicsSearchLOD; U32 mResourceCost; std::string mLODFile[LLModel::NUM_LODS]; bool mLoading; U32 mLoadState; bool mResetJoints; bool mRigParityWithScene; - + bool mModelNoErrors; + std::map<std::string, bool> mViewOption; //GLOD object parameters (must rebuild object if these change) @@ -459,7 +386,7 @@ private: U32 mMaxTriangleLimit; LLMeshUploadThread::instance_list mUploadData; - std::set<LLViewerFetchedTexture* > mTextureSet; + std::set<LLViewerFetchedTexture * > mTextureSet; //map of vertex buffers to models (one vertex buffer in vector per face in model std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; @@ -478,10 +405,9 @@ private: bool mLastJointUpdate; - std::deque<std::string> mMasterJointList; - std::deque<std::string> mMasterLegacyJointList; - std::deque<std::string> mJointsFromNode; - JointTransformMap mJointTransformMap; + JointSet mJointsFromNode; + JointTransformMap mJointTransformMap; + LLPointer<LLVOAvatar> mPreviewAvatar; }; diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 22a8ac4705..0fe97fd610 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -30,6 +30,7 @@ #include "llagent.h" #include "llviewerregion.h" #include "llnotificationsutil.h" +#include "llcorehttputil.h" LLFloaterModelUploadBase::LLFloaterModelUploadBase(const LLSD& key) :LLFloater(key), @@ -47,7 +48,8 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() LL_INFOS()<< typeid(*this).name() << "::requestAgentUploadPermissions() requesting for upload model permissions from: " << url << LL_ENDL; - LLHTTPClient::get(url, new LLUploadModelPermissionsResponder(getPermObserverHandle())); + LLCoros::instance().launch("LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro", + boost::bind(&LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro, this, url, getPermObserverHandle())); } else { @@ -58,3 +60,34 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() mHasUploadPerm = true; } } + +void LLFloaterModelUploadBase::requestAgentUploadPermissionsCoro(std::string url, + LLHandle<LLUploadPermissionsObserver> observerHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("MeshUploadFlag", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLUploadPermissionsObserver* observer = observerHandle.get(); + + if (!observer) + { + LL_WARNS("MeshUploadFlag") << "Unable to get observer after call to '" << url << "' aborting." << LL_ENDL; + } + + if (!status) + { + observer->setPermissonsErrorStatus(status.getStatus(), status.getMessage()); + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + observer->onPermissionsReceived(result); +} diff --git a/indra/newview/llfloatermodeluploadbase.h b/indra/newview/llfloatermodeluploadbase.h index d9a8879687..0d4c834122 100755 --- a/indra/newview/llfloatermodeluploadbase.h +++ b/indra/newview/llfloatermodeluploadbase.h @@ -28,6 +28,8 @@ #define LL_LLFLOATERMODELUPLOADBASE_H #include "lluploadfloaterobservers.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLFloaterModelUploadBase : public LLFloater, public LLUploadPermissionsObserver, public LLWholeModelFeeObserver, public LLWholeModelUploadObserver { @@ -54,6 +56,8 @@ protected: // requests agent's permissions to upload model void requestAgentUploadPermissions(); + void requestAgentUploadPermissionsCoro(std::string url, LLHandle<LLUploadPermissionsObserver> observerHandle); + std::string mUploadModelUrl; bool mHasUploadPerm; }; diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index 0cca715fe2..135bbb335e 100755 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -164,14 +164,18 @@ void LLFloaterNameDesc::onBtnOK( ) void *nruserdata = NULL; std::string display_name = LLStringUtil::null; - upload_new_resource(mFilenameAndPath, // file - getChild<LLUICtrl>("name_form")->getValue().asString(), - getChild<LLUICtrl>("description_form")->getValue().asString(), - 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - display_name, callback, expected_upload_cost, nruserdata); + LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + mFilenameAndPath, + getChild<LLUICtrl>("name_form")->getValue().asString(), + getChild<LLUICtrl>("description_form")->getValue().asString(), 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost)); + + upload_new_resource(uploadInfo, callback, nruserdata); + closeFloater(false); } diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp deleted file mode 100755 index b7b1634a5f..0000000000 --- a/indra/newview/llfloateroutbox.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/** - * @file llfloateroutbox.cpp - * @brief Implementation of the merchant outbox window - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloateroutbox.h" - -#include "llfloaterreg.h" -#include "llfolderview.h" -#include "llinventorybridge.h" -#include "llinventorymodelbackgroundfetch.h" -#include "llinventoryobserver.h" -#include "llinventorypanel.h" -#include "llmarketplacefunctions.h" -#include "llnotificationhandler.h" -#include "llnotificationmanager.h" -#include "llnotificationsutil.h" -#include "lltextbox.h" -#include "lltransientfloatermgr.h" -#include "lltrans.h" -#include "llviewernetwork.h" -#include "llwindowshade.h" - - -///---------------------------------------------------------------------------- -/// LLOutboxNotification class -///---------------------------------------------------------------------------- - -LLNotificationsUI::LLOutboxNotification::LLOutboxNotification() - : LLSystemNotificationHandler("Outbox", "outbox") -{ -} - -bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLNotificationPtr& notify) -{ - LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox"); - - outbox_floater->showNotification(notify); - - return false; -} - -void LLNotificationsUI::LLOutboxNotification::onDelete(LLNotificationPtr p) -{ - LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get()); - if (notification_handler) - { - notification_handler->onDelete(p); - } -} - -///---------------------------------------------------------------------------- -/// LLOutboxAddedObserver helper class -///---------------------------------------------------------------------------- - -class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver -{ -public: - LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater) - : LLInventoryCategoryAddedObserver() - , mOutboxFloater(outboxFloater) - { - } - - void done() - { - for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it) - { - LLViewerInventoryCategory* added_category = *it; - - LLFolderType::EType added_category_type = added_category->getPreferredType(); - - if (added_category_type == LLFolderType::FT_OUTBOX) - { - mOutboxFloater->initializeMarketPlace(); - } - } - } - -private: - LLFloaterOutbox * mOutboxFloater; -}; - -///---------------------------------------------------------------------------- -/// LLFloaterOutbox -///---------------------------------------------------------------------------- - -LLFloaterOutbox::LLFloaterOutbox(const LLSD& key) - : LLFloater(key) - , mCategoriesObserver(NULL) - , mCategoryAddedObserver(NULL) - , mImportBusy(false) - , mImportButton(NULL) - , mInventoryFolderCountText(NULL) - , mInventoryImportInProgress(NULL) - , mInventoryPlaceholder(NULL) - , mInventoryText(NULL) - , mInventoryTitle(NULL) - , mOutboxId(LLUUID::null) - , mOutboxItemCount(0) - , mOutboxTopLevelDropZone(NULL) - , mWindowShade(NULL) -{ -} - -LLFloaterOutbox::~LLFloaterOutbox() -{ - if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) - { - gInventory.removeObserver(mCategoriesObserver); - } - delete mCategoriesObserver; - - if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) - { - gInventory.removeObserver(mCategoryAddedObserver); - } - delete mCategoryAddedObserver; -} - -BOOL LLFloaterOutbox::postBuild() -{ - mInventoryFolderCountText = getChild<LLTextBox>("outbox_folder_count"); - mInventoryImportInProgress = getChild<LLView>("import_progress_indicator"); - mInventoryPlaceholder = getChild<LLView>("outbox_inventory_placeholder_panel"); - mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_text"); - mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_title"); - - mImportButton = getChild<LLButton>("outbox_import_btn"); - mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this)); - - mOutboxTopLevelDropZone = getChild<LLPanel>("outbox_generic_drag_target"); - - LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this)); - - // Observe category creation to catch outbox creation (moot if already existing) - mCategoryAddedObserver = new LLOutboxAddedObserver(this); - gInventory.addObserver(mCategoryAddedObserver); - - // Setup callbacks for importer - LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance(); - importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2)); - importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); - importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); - - return TRUE; -} - -void LLFloaterOutbox::cleanOutbox() -{ - // Note: we cannot delete the mOutboxInventoryPanel as that point - // as this is called through callback observers of the panel itself. - // Doing so would crash rapidly. - - // Invalidate the outbox data - mOutboxId.setNull(); - mOutboxItemCount = 0; -} - -void LLFloaterOutbox::onClose(bool app_quitting) -{ - if (mWindowShade) - { - delete mWindowShade; - - mWindowShade = NULL; - } -} - -void LLFloaterOutbox::onOpen(const LLSD& key) -{ - // - // Initialize the Market Place or go update the outbox - // - if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED) - { - initializeMarketPlace(); - } - else - { - setupOutbox(); - } - - // - // Update the floater view - // - updateView(); - - // - // Trigger fetch of outbox contents - // - fetchOutboxContents(); -} - -void LLFloaterOutbox::onFocusReceived() -{ - fetchOutboxContents(); -} - -void LLFloaterOutbox::fetchOutboxContents() -{ - if (mOutboxId.notNull()) - { - LLInventoryModelBackgroundFetch::instance().start(mOutboxId); - } -} - -void LLFloaterOutbox::setupOutbox() -{ - if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) - { - // If we are *not* a merchant or we have no market place connection established yet, do nothing - return; - } - - // We are a merchant. Get the outbox, create it if needs be. - LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true); - if (outbox_id.isNull()) - { - // We should never get there unless the inventory fails badly - LL_ERRS() << "Inventory problem: failure to create the outbox for a merchant!" << LL_ENDL; - return; - } - - // Consolidate Merchant Outbox - // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, things get messy and conventions get broken down eventually - gInventory.consolidateForType(outbox_id, LLFolderType::FT_OUTBOX); - - if (outbox_id == mOutboxId) - { - LL_WARNS() << "Inventory warning: Merchant outbox already set" << LL_ENDL; - return; - } - mOutboxId = outbox_id; - - // No longer need to observe new category creation - if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) - { - gInventory.removeObserver(mCategoryAddedObserver); - delete mCategoryAddedObserver; - mCategoryAddedObserver = NULL; - } - llassert(!mCategoryAddedObserver); - - // Create observer for outbox modifications : clear the old one and create a new one - if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) - { - gInventory.removeObserver(mCategoriesObserver); - delete mCategoriesObserver; - } - mCategoriesObserver = new LLInventoryCategoriesObserver(); - gInventory.addObserver(mCategoriesObserver); - mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); - llassert(mCategoriesObserver); - - // Set up the outbox inventory view - LLInventoryPanel* inventory_panel = mOutboxInventoryPanel.get(); - if (inventory_panel) - { - delete inventory_panel; - } - inventory_panel = LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_outbox_inventory.xml", mInventoryPlaceholder->getParent(), LLInventoryPanel::child_registry_t::instance()); - mOutboxInventoryPanel = inventory_panel->getInventoryPanelHandle(); - llassert(mOutboxInventoryPanel.get() != NULL); - - // Reshape the inventory to the proper size - LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect(); - inventory_panel->setShape(inventory_placeholder_rect); - - // Set the sort order newest to oldest - inventory_panel->getFolderViewModel()->setSorter(LLInventoryFilter::SO_FOLDERS_BY_NAME); - inventory_panel->getFilter().markDefault(); - - // Get the content of the outbox - fetchOutboxContents(); -} - -void LLFloaterOutbox::initializeMarketPlace() -{ - // - // Initialize the marketplace import API - // - LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance(); - if (!importer.isInitialized()) - { - importer.initialize(); - } -} - -void LLFloaterOutbox::setStatusString(const std::string& statusString) -{ - llassert(mInventoryFolderCountText != NULL); - - mInventoryFolderCountText->setText(statusString); -} - -void LLFloaterOutbox::updateFolderCount() -{ - if (mOutboxInventoryPanel.get() && mOutboxId.notNull()) - { - U32 item_count = 0; - - if (mOutboxId.notNull()) - { - LLInventoryModel::cat_array_t * cats; - LLInventoryModel::item_array_t * items; - gInventory.getDirectDescendentsOf(mOutboxId, cats, items); - - item_count = cats->size() + items->size(); - } - - mOutboxItemCount = item_count; - } - else - { - // If there's no outbox, the number of items in it should be set to 0 for consistency - mOutboxItemCount = 0; - } - - if (!mImportBusy) - { - updateFolderCountStatus(); - } -} - -void LLFloaterOutbox::updateFolderCountStatus() -{ - if (mOutboxInventoryPanel.get() && mOutboxId.notNull()) - { - switch (mOutboxItemCount) - { - case 0: setStatusString(getString("OutboxFolderCount0")); break; - case 1: setStatusString(getString("OutboxFolderCount1")); break; - default: - { - std::string item_count_str = llformat("%d", mOutboxItemCount); - - LLStringUtil::format_map_t args; - args["[NUM]"] = item_count_str; - - setStatusString(getString("OutboxFolderCountN", args)); - break; - } - } - } - - mImportButton->setEnabled(mOutboxItemCount > 0); -} - -void LLFloaterOutbox::updateView() -{ - updateFolderCount(); - LLInventoryPanel* panel = mOutboxInventoryPanel.get(); - - if (mOutboxItemCount > 0) - { - panel->setVisible(TRUE); - mInventoryPlaceholder->setVisible(FALSE); - mOutboxTopLevelDropZone->setVisible(TRUE); - } - else - { - if (panel) - { - panel->setVisible(FALSE); - } - - // Show the drop zone if there is an outbox folder - mOutboxTopLevelDropZone->setVisible(mOutboxId.notNull()); - - mInventoryPlaceholder->setVisible(TRUE); - - std::string outbox_text; - std::string outbox_title; - std::string outbox_tooltip; - - const LLSD& subs = getMarketplaceStringSubstitutions(); - U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus(); - - if (mOutboxId.notNull()) - { - // Does the outbox needs recreation? - if ((mOutboxInventoryPanel.get() == NULL) || !gInventory.getCategory(mOutboxId)) - { - setupOutbox(); - } - // "Outbox is empty!" message strings - outbox_text = LLTrans::getString("InventoryOutboxNoItems", subs); - outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip"); - } - else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) - { - // "Initializing!" message strings - outbox_text = LLTrans::getString("InventoryOutboxInitializing", subs); - outbox_title = LLTrans::getString("InventoryOutboxInitializingTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip"); - } - else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT) - { - // "Not a merchant!" message strings - outbox_text = LLTrans::getString("InventoryOutboxNotMerchant", subs); - outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); - } - else - { - // "Errors!" message strings - outbox_text = LLTrans::getString("InventoryOutboxError", subs); - outbox_title = LLTrans::getString("InventoryOutboxErrorTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); - } - - mInventoryText->setValue(outbox_text); - mInventoryTitle->setValue(outbox_title); - mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip); - } -} - -bool isAccepted(EAcceptance accept) -{ - return (accept >= ACCEPT_YES_COPY_SINGLE); -} - -BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - if ((mOutboxInventoryPanel.get() == NULL) || - (mWindowShade && mWindowShade->isShown()) || - LLMarketplaceInventoryImporter::getInstance()->isImportInProgress() || - mOutboxId.isNull()) - { - return FALSE; - } - - LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - BOOL handled = (handled_view != NULL); - - // Determine if the mouse is inside the inventory panel itself or just within the floater - bool pointInInventoryPanel = false; - bool pointInInventoryPanelChild = false; - LLInventoryPanel* panel = mOutboxInventoryPanel.get(); - LLFolderView* root_folder = panel->getRootFolder(); - if (panel->getVisible()) - { - S32 inv_x, inv_y; - localPointToOtherView(x, y, &inv_x, &inv_y, panel); - - pointInInventoryPanel = panel->getRect().pointInRect(inv_x, inv_y); - - LLView * inventory_panel_child_at_point = panel->childFromPoint(inv_x, inv_y, true); - pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder); - } - - // Pass all drag and drop for this floater to the outbox inventory control - if (!handled || !isAccepted(*accept)) - { - // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel - // (otherwise the inventory panel itself will handle the drag and drop operation, without any override) - if (!pointInInventoryPanel) - { - handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } - - mOutboxTopLevelDropZone->setBackgroundVisible(handled && !drop && isAccepted(*accept)); - } - else - { - mOutboxTopLevelDropZone->setBackgroundVisible(!pointInInventoryPanelChild); - } - - return handled; -} - -BOOL LLFloaterOutbox::handleHover(S32 x, S32 y, MASK mask) -{ - mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); - - return LLFloater::handleHover(x, y, mask); -} - -void LLFloaterOutbox::onMouseLeave(S32 x, S32 y, MASK mask) -{ - mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); - - LLFloater::onMouseLeave(x, y, mask); -} - -void LLFloaterOutbox::onImportButtonClicked() -{ - if (mOutboxInventoryPanel.get()) - { - mOutboxInventoryPanel.get()->clearSelection(); - } - - mImportBusy = LLMarketplaceInventoryImporter::instance().triggerImport(); -} - -void LLFloaterOutbox::onOutboxChanged() -{ - LLViewerInventoryCategory* category = gInventory.getCategory(mOutboxId); - if (mOutboxId.notNull() && category) - { - fetchOutboxContents(); - updateView(); - } - else - { - cleanOutbox(); - } -} - -void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content) -{ - if (status == MarketplaceErrorCodes::IMPORT_DONE) - { - LLNotificationsUtil::add("OutboxImportComplete"); - } - else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) - { - const LLSD& subs = getMarketplaceStringSubstitutions(); - - LLNotificationsUtil::add("OutboxImportHadErrors", subs); - } - else - { - char status_string[16]; - sprintf(status_string, "%d", status); - - LLSD subs; - subs["[ERROR_CODE]"] = status_string; - - LLNotificationsUtil::add("OutboxImportFailed", subs); - } - - updateView(); -} - -void LLFloaterOutbox::importStatusChanged(bool inProgress) -{ - if (mOutboxId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)) - { - setupOutbox(); - } - - if (inProgress) - { - if (mImportBusy) - { - setStatusString(getString("OutboxImporting")); - } - else - { - setStatusString(getString("OutboxInitializing")); - } - - mImportBusy = true; - mImportButton->setEnabled(false); - mInventoryImportInProgress->setVisible(true); - } - else - { - setStatusString(""); - mImportBusy = false; - mImportButton->setEnabled(mOutboxItemCount > 0); - mInventoryImportInProgress->setVisible(false); - } - - updateView(); -} - -void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content) -{ - if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) - { - char status_string[16]; - sprintf(status_string, "%d", status); - - LLSD subs; - subs["[ERROR_CODE]"] = status_string; - - LLNotificationsUtil::add("OutboxInitFailed", subs); - } - - updateView(); -} - -void LLFloaterOutbox::showNotification(const LLNotificationPtr& notification) -{ - LLNotificationsUI::LLNotificationHandler * notification_handler = dynamic_cast<LLNotificationsUI::LLNotificationHandler*>(LLNotifications::instance().getChannel("AlertModal").get()); - llassert(notification_handler); - - notification_handler->processNotification(notification); -} - - - diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h deleted file mode 100755 index 2cf69fc3cc..0000000000 --- a/indra/newview/llfloateroutbox.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file llfloateroutbox.h - * @brief Implementation of the merchant outbox window - * - * $LicenseInfo:firstyear=2001&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 - * ABILITY 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$ - */ - -#ifndef LL_LLFLOATEROUTBOX_H -#define LL_LLFLOATEROUTBOX_H - -#include "llfloater.h" -#include "llfoldertype.h" -#include "llinventoryfilter.h" -#include "llnotificationptr.h" - - -class LLButton; -class LLInventoryCategoriesObserver; -class LLInventoryCategoryAddedObserver; -class LLInventoryPanel; -class LLLoadingIndicator; -class LLNotification; -class LLTextBox; -class LLView; -class LLWindowShade; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFloaterOutbox -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLFloaterOutbox : public LLFloater -{ -public: - LLFloaterOutbox(const LLSD& key); - ~LLFloaterOutbox(); - - void initializeMarketPlace(); - - // virtuals - BOOL postBuild(); - BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - void showNotification(const LLNotificationPtr& notification); - - BOOL handleHover(S32 x, S32 y, MASK mask); - void onMouseLeave(S32 x, S32 y, MASK mask); - -protected: - void setupOutbox(); - void cleanOutbox(); - void fetchOutboxContents(); - - void importReportResults(U32 status, const LLSD& content); - void importStatusChanged(bool inProgress); - void initializationReportError(U32 status, const LLSD& content); - - void onClose(bool app_quitting); - void onOpen(const LLSD& key); - - void onFocusReceived(); - - void onImportButtonClicked(); - void onOutboxChanged(); - - void setStatusString(const std::string& statusString); - - void updateFolderCount(); - void updateFolderCountStatus(); - void updateView(); - -private: - LLInventoryCategoriesObserver * mCategoriesObserver; - LLInventoryCategoryAddedObserver * mCategoryAddedObserver; - - bool mImportBusy; - LLButton * mImportButton; - - LLTextBox * mInventoryFolderCountText; - LLView * mInventoryImportInProgress; - LLView * mInventoryPlaceholder; - LLTextBox * mInventoryText; - LLTextBox * mInventoryTitle; - - LLUUID mOutboxId; - LLHandle<LLInventoryPanel> mOutboxInventoryPanel; - U32 mOutboxItemCount; - LLPanel * mOutboxTopLevelDropZone; - - LLWindowShade * mWindowShade; -}; - -#endif // LL_LLFLOATEROUTBOX_H diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 042cf47070..31c2a6f9aa 100755 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -37,6 +37,7 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llvoavatar.h" +#include "llcorehttputil.h" LLFloaterPerms::LLFloaterPerms(const LLSD& seed) : LLFloater(seed) @@ -166,41 +167,6 @@ void LLFloaterPermsDefault::onCommitCopy(const LLSD& user_data) xfer->setEnabled(copyable); } -class LLFloaterPermsResponder : public LLHTTPClient::Responder -{ -public: - LLFloaterPermsResponder(): LLHTTPClient::Responder() {} -private: - static std::string sPreviousReason; - - void httpFailure() - { - const std::string& reason = getReason(); - // Do not display the same error more than once in a row - if (reason != sPreviousReason) - { - sPreviousReason = reason; - LLSD args; - args["REASON"] = reason; - LLNotificationsUtil::add("DefaultObjectPermissions", args); - } - } - - void httpSuccess() - { - //const LLSD& content = getContent(); - //dump_sequential_xml("perms_responder_result.xml", content); - - // Since we have had a successful POST call be sure to display the next error message - // even if it is the same as a previous one. - sPreviousReason = ""; - LLFloaterPermsDefault::setCapSent(true); - LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; - } -}; - - std::string LLFloaterPermsResponder::sPreviousReason; - void LLFloaterPermsDefault::sendInitialPerms() { if(!mCapSent) @@ -215,23 +181,8 @@ void LLFloaterPermsDefault::updateCap() if(!object_url.empty()) { - LLSD report = LLSD::emptyMap(); - report["default_object_perm_masks"]["Group"] = - (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]); - report["default_object_perm_masks"]["Everyone"] = - (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]); - report["default_object_perm_masks"]["NextOwner"] = - (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]); - - { - LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '" - << object_url << "'\n"; - std::ostringstream sent_perms_log; - LLSDSerialize::toPrettyXML(report, sent_perms_log); - LL_CONT << sent_perms_log.str() << LL_ENDL; - } - - LLHTTPClient::post(object_url, report, new LLFloaterPermsResponder()); + LLCoros::instance().launch("LLFloaterPermsDefault::updateCapCoro", + boost::bind(&LLFloaterPermsDefault::updateCapCoro, object_url)); } else { @@ -239,6 +190,57 @@ void LLFloaterPermsDefault::updateCap() } } +/*static*/ +void LLFloaterPermsDefault::updateCapCoro(std::string url) +{ + static std::string previousReason; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD postData = LLSD::emptyMap(); + postData["default_object_perm_masks"]["Group"] = + (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]); + postData["default_object_perm_masks"]["Everyone"] = + (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]); + postData["default_object_perm_masks"]["NextOwner"] = + (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]); + + { + LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '" + << url << "'\n"; + std::ostringstream sent_perms_log; + LLSDSerialize::toPrettyXML(postData, sent_perms_log); + LL_CONT << sent_perms_log.str() << LL_ENDL; + } + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + const std::string& reason = status.toString(); + // Do not display the same error more than once in a row + if (reason != previousReason) + { + previousReason = reason; + LLSD args; + args["REASON"] = reason; + LLNotificationsUtil::add("DefaultObjectPermissions", args); + } + return; + } + + // Since we have had a successful POST call be sure to display the next error message + // even if it is the same as a previous one. + previousReason.clear(); + LLFloaterPermsDefault::setCapSent(true); + LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; +} + void LLFloaterPermsDefault::setCapSent(bool cap_sent) { mCapSent = cap_sent; diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index 2bb0a19dc1..e866b6de7d 100755 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -29,6 +29,8 @@ #define LL_LLFLOATERPERMPREFS_H #include "llfloater.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLFloaterPerms : public LLFloater { @@ -80,6 +82,8 @@ private: void refresh(); static const std::string sCategoryNames[CAT_LAST]; + static void updateCapCoro(std::string url); + // cached values only for implementing cancel. bool mShareWithGroup[CAT_LAST]; diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 40757a4d04..271fb2f9a3 100755 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -30,11 +30,11 @@ #include "llfloaterregiondebugconsole.h" #include "llagent.h" -#include "llhttpclient.h" #include "llhttpnode.h" #include "lllineeditor.h" #include "lltexteditor.h" #include "llviewerregion.h" +#include "llcorehttputil.h" // Two versions of the sim console API are supported. // @@ -68,58 +68,6 @@ namespace const std::string CONSOLE_NOT_SUPPORTED( "This region does not support the simulator console."); - // This responder handles the initial response. Unless error() is called - // we assume that the simulator has received our request. Error will be - // called if this request times out. - class AsyncConsoleResponder : public LLHTTPClient::Responder - { - LOG_CLASS(AsyncConsoleResponder); - protected: - /* virtual */ - void httpFailure() - { - LL_WARNS("Console") << dumpResponse() << LL_ENDL; - sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); - } - }; - - class ConsoleResponder : public LLHTTPClient::Responder - { - LOG_CLASS(ConsoleResponder); - public: - ConsoleResponder(LLTextEditor *output) : mOutput(output) - { - } - - protected: - /*virtual*/ - void httpFailure() - { - LL_WARNS("Console") << dumpResponse() << LL_ENDL; - if (mOutput) - { - mOutput->appendText( - UNABLE_TO_SEND_COMMAND + PROMPT, - false); - } - } - - /*virtual*/ - void httpSuccess() - { - const LLSD& content = getContent(); - LL_DEBUGS("Console") << content << LL_ENDL; - if (mOutput) - { - mOutput->appendText( - content.asString() + PROMPT, false); - } - } - - public: - LLTextEditor * mOutput; - }; - // This handles responses for console commands sent via the asynchronous // API. class ConsoleResponseNode : public LLHTTPNode @@ -202,26 +150,57 @@ void LLFloaterRegionDebugConsole::onInput(LLUICtrl* ctrl, const LLSD& param) } else { - // Using SimConsole (deprecated) - LLHTTPClient::post( - url, - LLSD(input->getText()), - new ConsoleResponder(mOutput)); + LLSD postData = LLSD(input->getText()); + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData, + boost::bind(&LLFloaterRegionDebugConsole::onConsoleSuccess, this, _1), + boost::bind(&LLFloaterRegionDebugConsole::onConsoleError, this, _1)); } } else { - // Using SimConsoleAsync - LLHTTPClient::post( - url, - LLSD(input->getText()), - new AsyncConsoleResponder); + LLSD postData = LLSD(input->getText()); + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, postData, + NULL, + boost::bind(&LLFloaterRegionDebugConsole::onAsyncConsoleError, this, _1)); + } mOutput->appendText(text, false); input->clear(); } +void LLFloaterRegionDebugConsole::onAsyncConsoleError(LLSD result) +{ + LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL; + sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); +} + +void LLFloaterRegionDebugConsole::onConsoleError(LLSD result) +{ + LL_WARNS("Console") << UNABLE_TO_SEND_COMMAND << LL_ENDL; + if (mOutput) + { + mOutput->appendText( + UNABLE_TO_SEND_COMMAND + PROMPT, + false); + } + +} + +void LLFloaterRegionDebugConsole::onConsoleSuccess(LLSD result) +{ + if (mOutput) + { + LLSD response = result; + if (response.isMap() && response.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT)) + { + response = response[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; + } + mOutput->appendText( + response.asString() + PROMPT, false); + } +} + void LLFloaterRegionDebugConsole::onReplyReceived(const std::string& output) { mOutput->appendText(output + PROMPT, false); diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index fd3af4152e..f55d964924 100755 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -31,14 +31,13 @@ #include <boost/signals2.hpp> #include "llfloater.h" -#include "llhttpclient.h" class LLTextEditor; typedef boost::signals2::signal< void (const std::string& output)> console_reply_signal_t; -class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder +class LLFloaterRegionDebugConsole : public LLFloater { public: LLFloaterRegionDebugConsole(LLSD const & key); @@ -56,6 +55,10 @@ public: private: void onReplyReceived(const std::string& output); + void onAsyncConsoleError(LLSD result); + void onConsoleError(LLSD result); + void onConsoleSuccess(LLSD result); + boost::signals2::connection mReplySignalConnection; }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 5d1e01c1f7..94f3a45d88 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -97,6 +97,7 @@ #include "llpanelexperiencepicker.h" #include "llexperiencecache.h" #include "llpanelexperiences.h" +#include "llcorehttputil.h" const S32 TERRAIN_TEXTURE_COUNT = 4; const S32 CORNER_COUNT = 4; @@ -803,30 +804,6 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L return false; } -class ConsoleRequestResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(ConsoleRequestResponder); -protected: - /*virtual*/ - void httpFailure() - { - LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL; - } -}; - - -// called if this request times out. -class ConsoleUpdateResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(ConsoleUpdateResponder); -protected: - /* virtual */ - void httpFailure() - { - LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL; - } -}; - void LLFloaterRegionInfo::requestMeshRezInfo() { std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync"); @@ -835,10 +812,8 @@ void LLFloaterRegionInfo::requestMeshRezInfo() { std::string request_str = "get mesh_rez_enabled"; - LLHTTPClient::post( - sim_console_url, - LLSD(request_str), - new ConsoleRequestResponder); + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(sim_console_url, LLSD(request_str), + "Requested mesh_rez_enabled", "Error requesting mesh_rez_enabled"); } } @@ -874,7 +849,8 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() body["allow_parcel_changes"] = getChild<LLUICtrl>("allow_parcel_changes_check")->getValue(); body["block_parcel_search"] = getChild<LLUICtrl>("block_parcel_search_check")->getValue(); - LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "Region info update posted.", "Region info update not posted."); } else { @@ -2303,36 +2279,6 @@ void LLPanelEstateInfo::getEstateOwner() } */ -class LLEstateChangeInfoResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLEstateChangeInfoResponder); -public: - LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) - { - mpPanel = panel->getHandle(); - } - -protected: - // if we get a normal response, handle it here - virtual void httpSuccess() - { - LL_INFOS("Windlight") << "Successfully committed estate info" << LL_ENDL; - - // refresh the panel from the database - LLPanelEstateInfo* panel = dynamic_cast<LLPanelEstateInfo*>(mpPanel.get()); - if (panel) - panel->refresh(); - } - - // if we get an error response - virtual void httpFailure() - { - LL_WARNS("Windlight") << dumpResponse() << LL_ENDL; - } -private: - LLHandle<LLPanel> mpPanel; -}; - const std::string LLPanelEstateInfo::getOwnerName() const { return getChild<LLUICtrl>("estate_owner")->getValue().asString(); @@ -3640,29 +3586,6 @@ void LLPanelRegionExperiences::processResponse( const LLSD& content ) } - -class LLRegionExperienceResponder : public LLHTTPClient::Responder -{ -public: - typedef boost::function<void (const LLSD&)> callback_t; - - callback_t mCallback; - - LLRegionExperienceResponder(callback_t callback) : mCallback(callback) { } - -protected: - /*virtual*/ void httpSuccess() - { - mCallback(getContent()); - } - - /*virtual*/ void httpFailure() - { - LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL; - } -}; - - // Used for both access add and remove operations, depending on the flag // passed in (ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE, etc.) // static @@ -3745,6 +3668,13 @@ void LLPanelRegionExperiences::infoCallback(LLHandle<LLPanelRegionExperiences> h } } +/*static*/ +std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* region, const std::string &cap) +{ + // region->getHandle() How to get a region * from a handle? + + return region->getCapability(cap); +} bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region) { @@ -3769,13 +3699,10 @@ bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region) mTrusted->loading(); mTrusted->setReadonly(!allow_modify); - std::string url = region->getCapability("RegionExperiences"); - if (!url.empty()) - { - LLHTTPClient::get(url, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback, - getDerivedHandle<LLPanelRegionExperiences>(), _1))); - } - return LLPanelRegionInfo::refreshFromRegion(region); + LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), + boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1)); + + return LLPanelRegionInfo::refreshFromRegion(region); } LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel) @@ -3793,18 +3720,15 @@ LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel) BOOL LLPanelRegionExperiences::sendUpdate() { LLViewerRegion* region = gAgent.getRegion(); - std::string url = region->getCapability("RegionExperiences"); - if (!url.empty()) - { - LLSD content; - content["allowed"]=addIds(mAllowed); - content["blocked"]=addIds(mBlocked); - content["trusted"]=addIds(mTrusted); + LLSD content; - LLHTTPClient::post(url, content, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback, - getDerivedHandle<LLPanelRegionExperiences>(), _1))); - } + content["allowed"]=addIds(mAllowed); + content["blocked"]=addIds(mBlocked); + content["trusted"]=addIds(mTrusted); + + LLExperienceCache::instance().setRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), + content, boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle<LLPanelRegionExperiences>(), _1)); return TRUE; } diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index e7b49d8553..3c74618fff 100755 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -36,6 +36,7 @@ #include "llextendedstatus.h" #include "llenvmanager.h" // for LLEnvironmentSettings +#include "lleventcoro.h" class LLAvatarName; class LLDispatcher; @@ -107,6 +108,8 @@ private: LLFloaterRegionInfo(const LLSD& seed); ~LLFloaterRegionInfo(); + + protected: void onTabSelected(const LLSD& param); @@ -476,6 +479,8 @@ public: private: void refreshRegionExperiences(); + static std::string regionCapabilityQuery(LLViewerRegion* region, const std::string &cap); + LLPanelExperienceListEditor* setupList(const char* control_name, U32 add_id, U32 remove_id); static LLSD addIds( LLPanelExperienceListEditor* panel ); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 2f4d2a93b2..1c2340b0ef 100755 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -77,12 +77,66 @@ #include "lluictrlfactory.h" #include "llviewernetwork.h" -#include "llassetuploadresponders.h" #include "llagentui.h" #include "lltrans.h" #include "llexperiencecache.h" +#include "llcorehttputil.h" +#include "llviewerassetupload.h" + + +//========================================================================= +//----------------------------------------------------------------------------- +// Support classes +//----------------------------------------------------------------------------- +class LLARScreenShotUploader : public LLResourceUploadInfo +{ +public: + LLARScreenShotUploader(LLSD report, LLUUID assetId, LLAssetType::EType assetType); + + virtual LLSD prepareUpload(); + virtual LLSD generatePostBody(); + virtual S32 getEconomyUploadCost(); + virtual LLUUID finishUpload(LLSD &result); + + virtual bool showInventoryPanel() const { return false; } + virtual std::string getDisplayName() const { return "Abuse Report"; } + +private: + + LLSD mReport; +}; + +LLARScreenShotUploader::LLARScreenShotUploader(LLSD report, LLUUID assetId, LLAssetType::EType assetType) : + LLResourceUploadInfo(assetId, assetType, "Abuse Report"), + mReport(report) +{ +} + +LLSD LLARScreenShotUploader::prepareUpload() +{ + return LLSD().with("success", LLSD::Boolean(true)); +} + +LLSD LLARScreenShotUploader::generatePostBody() +{ // The report was pregenerated and passed in the constructor. + return mReport; +} + +S32 LLARScreenShotUploader::getEconomyUploadCost() +{ // Abuse report screen shots do not cost anything to upload. + return 0; +} + +LLUUID LLARScreenShotUploader::finishUpload(LLSD &result) +{ + /* *TODO$: Report success or failure. Carried over from previous todo on responder*/ + return LLUUID::null; +} + + +//========================================================================= //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- @@ -214,7 +268,7 @@ void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id) if (LLUUID::null != mExperienceID) { - const LLSD& experience = LLExperienceCache::get(mExperienceID); + const LLSD& experience = LLExperienceCache::instance().get(mExperienceID); std::stringstream desc; if(experience.isDefined()) @@ -706,59 +760,25 @@ void LLFloaterReporter::sendReportViaLegacy(const LLSD & report) msg->sendReliable(regionp->getHost()); } -class LLUserReportScreenshotResponder : public LLAssetUploadResponder +void LLFloaterReporter::finishedARPost(const LLSD &) { -public: - LLUserReportScreenshotResponder(const LLSD & post_data, - const LLUUID & vfile_id, - LLAssetType::EType asset_type): - LLAssetUploadResponder(post_data, vfile_id, asset_type) - { - } - void uploadFailed(const LLSD& content) - { - // *TODO pop up a dialog so the user knows their report screenshot didn't make it - LLUploadDialog::modalUploadFinished(); - } - void uploadComplete(const LLSD& content) - { - // we don't care about what the server returns from this post, just clean up the UI - LLUploadDialog::modalUploadFinished(); - } -}; + LLUploadDialog::modalUploadFinished(); -class LLUserReportResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLUserReportResponder); -public: - LLUserReportResponder(): LLHTTPClient::Responder() {} - -private: - void httpCompleted() - { - if (!isGoodStatus()) - { - // *TODO do some user messaging here - LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; - } - // we don't care about what the server returns - LLUploadDialog::modalUploadFinished(); - } -}; +} void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report) { if(getChild<LLUICtrl>("screen_check")->getValue().asBoolean() && !sshot_url.empty()) - { + { // try to upload screenshot - LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report, - mResourceDatap->mAssetInfo.mUuid, - mResourceDatap->mAssetInfo.mType)); + LLResourceUploadInfo::ptr_t uploadInfo(new LLARScreenShotUploader(report, mResourceDatap->mAssetInfo.mUuid, mResourceDatap->mAssetInfo.mType)); + LLViewerAssetUpload::EnqueueInventoryUpload(sshot_url, uploadInfo); } else { - // screenshot not wanted or we don't have screenshot cap - LLHTTPClient::post(url, report, new LLUserReportResponder()); + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t proc = boost::bind(&LLFloaterReporter::finishedARPost, _1); + LLUploadDialog::modalUploadDialog("Abuse Report"); + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, report, proc, proc); } } diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index d857528f10..1aff07bd37 100755 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -122,6 +122,8 @@ private: void setFromAvatarID(const LLUUID& avatar_id); void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name); + static void finishedARPost(const LLSD &); + private: EReportType mReportType; LLUUID mObjectID; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 5fbdd75e97..7b8fc5b35b 100755 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -50,6 +50,7 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llcorehttputil.h" ///---------------------------------------------------------------------------- /// LLFloaterScriptLimits @@ -180,372 +181,6 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr) } ///---------------------------------------------------------------------------- -// Responders -///---------------------------------------------------------------------------- - -void fetchScriptLimitsRegionInfoResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - //we don't need to test with a fake respose here (shouldn't anyway) - -#ifdef DUMP_REPLIES_TO_LLINFOS - - LLSDNotationStreamer notation_streamer(content); - std::ostringstream nice_llsd; - nice_llsd << notation_streamer; - - OSMessageBox(nice_llsd.str(), "main cap response:", 0); - - LL_INFOS() << "main cap response:" << content << LL_ENDL; - -#endif - - // at this point we have an llsd which should contain ether one or two urls to the services we want. - // first we look for the details service: - if(content.has("ScriptResourceDetails")) - { - LLHTTPClient::get(content["ScriptResourceDetails"], new fetchScriptLimitsRegionDetailsResponder(mInfo)); - } - else - { - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - if(!instance) - { - LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; - } - } - - // then the summary service: - if(content.has("ScriptResourceSummary")) - { - LLHTTPClient::get(content["ScriptResourceSummary"], new fetchScriptLimitsRegionSummaryResponder(mInfo)); - } -} - -void fetchScriptLimitsRegionInfoResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsRegionSummaryResponder::httpSuccess() -{ - const LLSD& content_ref = getContent(); -#ifdef USE_FAKE_RESPONSES - - LLSD fake_content; - LLSD summary = LLSD::emptyMap(); - LLSD available = LLSD::emptyArray(); - LLSD available_urls = LLSD::emptyMap(); - LLSD available_memory = LLSD::emptyMap(); - LLSD used = LLSD::emptyArray(); - LLSD used_urls = LLSD::emptyMap(); - LLSD used_memory = LLSD::emptyMap(); - - used_urls["type"] = "urls"; - used_urls["amount"] = FAKE_NUMBER_OF_URLS; - available_urls["type"] = "urls"; - available_urls["amount"] = FAKE_AVAILABLE_URLS; - used_memory["type"] = "memory"; - used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY; - available_memory["type"] = "memory"; - available_memory["amount"] = FAKE_AVAILABLE_MEMORY; - -//summary response:{'summary':{'available':[{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'},{'amount':i731,'type':'urls'},{'amount':i895577,'type':'memory'}],'used':[{'amount':i329,'type':'urls'},{'amount':i66741,'type':'memory'}]}} - - used.append(used_urls); - used.append(used_memory); - available.append(available_urls); - available.append(available_memory); - - summary["available"] = available; - summary["used"] = used; - - fake_content["summary"] = summary; - - const LLSD& content = fake_content; - -#else - - const LLSD& content = content_ref; - -#endif - - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - - -#ifdef DUMP_REPLIES_TO_LLINFOS - - LLSDNotationStreamer notation_streamer(content); - std::ostringstream nice_llsd; - nice_llsd << notation_streamer; - - OSMessageBox(nice_llsd.str(), "summary response:", 0); - - LL_WARNS() << "summary response:" << *content << LL_ENDL; - -#endif - - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - if(!instance) - { - LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; - } - else - { - LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); - if(tab) - { - LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); - if(panel_memory) - { - panel_memory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); - - LLButton* btn = panel_memory->getChild<LLButton>("refresh_list_btn"); - if(btn) - { - btn->setEnabled(true); - } - - panel_memory->setRegionSummary(content); - } - } - } -} - -void fetchScriptLimitsRegionSummaryResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsRegionDetailsResponder::httpSuccess() -{ - const LLSD& content_ref = getContent(); -#ifdef USE_FAKE_RESPONSES -/* -Updated detail service, ** denotes field added: - -result (map) -+-parcels (array of maps) - +-id (uuid) - +-local_id (S32)** - +-name (string) - +-owner_id (uuid) (in ERS as owner, but owner_id in code) - +-objects (array of maps) - +-id (uuid) - +-name (string) - +-owner_id (uuid) (in ERS as owner, in code as owner_id) - +-owner_name (sting)** - +-location (map)** - +-x (float) - +-y (float) - +-z (float) - +-resources (map) (this is wrong in the ERS but right in code) - +-type (string) - +-amount (int) -*/ - LLSD fake_content; - LLSD resource = LLSD::emptyMap(); - LLSD location = LLSD::emptyMap(); - LLSD object = LLSD::emptyMap(); - LLSD objects = LLSD::emptyArray(); - LLSD parcel = LLSD::emptyMap(); - LLSD parcels = LLSD::emptyArray(); - - resource["urls"] = FAKE_NUMBER_OF_URLS; - resource["memory"] = FAKE_AMOUNT_OF_MEMORY; - - location["x"] = 128.0f; - location["y"] = 128.0f; - location["z"] = 0.0f; - - object["id"] = LLUUID("d574a375-0c6c-fe3d-5733-da669465afc7"); - object["name"] = "Gabs fake Object!"; - object["owner_id"] = LLUUID("8dbf2d41-69a0-4e5e-9787-0c9d297bc570"); - object["owner_name"] = "Gabs Linden"; - object["location"] = location; - object["resources"] = resource; - - objects.append(object); - - parcel["id"] = LLUUID("da05fb28-0d20-e593-2728-bddb42dd0160"); - parcel["local_id"] = 42; - parcel["name"] = "Gabriel Linden\'s Sub Plot"; - parcel["objects"] = objects; - parcels.append(parcel); - - fake_content["parcels"] = parcels; - const LLSD& content = fake_content; - -#else - - const LLSD& content = content_ref; - -#endif - - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - -#ifdef DUMP_REPLIES_TO_LLINFOS - - LLSDNotationStreamer notation_streamer(content); - std::ostringstream nice_llsd; - nice_llsd << notation_streamer; - - OSMessageBox(nice_llsd.str(), "details response:", 0); - - LL_INFOS() << "details response:" << content << LL_ENDL; - -#endif - - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - - if(!instance) - { - LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; - } - else - { - LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); - if(tab) - { - LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); - if(panel_memory) - { - panel_memory->setRegionDetails(content); - } - else - { - LL_WARNS() << "Failed to get scriptlimits memory panel" << LL_ENDL; - } - } - else - { - LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; - } - } -} - -void fetchScriptLimitsRegionDetailsResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} - -void fetchScriptLimitsAttachmentInfoResponder::httpSuccess() -{ - const LLSD& content_ref = getContent(); - -#ifdef USE_FAKE_RESPONSES - - // just add the summary, as that's all I'm testing currently! - LLSD fake_content = LLSD::emptyMap(); - LLSD summary = LLSD::emptyMap(); - LLSD available = LLSD::emptyArray(); - LLSD available_urls = LLSD::emptyMap(); - LLSD available_memory = LLSD::emptyMap(); - LLSD used = LLSD::emptyArray(); - LLSD used_urls = LLSD::emptyMap(); - LLSD used_memory = LLSD::emptyMap(); - - used_urls["type"] = "urls"; - used_urls["amount"] = FAKE_NUMBER_OF_URLS; - available_urls["type"] = "urls"; - available_urls["amount"] = FAKE_AVAILABLE_URLS; - used_memory["type"] = "memory"; - used_memory["amount"] = FAKE_AMOUNT_OF_MEMORY; - available_memory["type"] = "memory"; - available_memory["amount"] = FAKE_AVAILABLE_MEMORY; - - used.append(used_urls); - used.append(used_memory); - available.append(available_urls); - available.append(available_memory); - - summary["available"] = available; - summary["used"] = used; - - fake_content["summary"] = summary; - fake_content["attachments"] = content_ref["attachments"]; - - const LLSD& content = fake_content; - -#else - - const LLSD& content = content_ref; - -#endif - - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - -#ifdef DUMP_REPLIES_TO_LLINFOS - - LLSDNotationStreamer notation_streamer(content); - std::ostringstream nice_llsd; - nice_llsd << notation_streamer; - - OSMessageBox(nice_llsd.str(), "attachment response:", 0); - - LL_INFOS() << "attachment response:" << content << LL_ENDL; - -#endif - - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); - - if(!instance) - { - LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; - } - else - { - LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); - if(tab) - { - LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel"); - if(panel) - { - panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); - - LLButton* btn = panel->getChild<LLButton>("refresh_list_btn"); - if(btn) - { - btn->setEnabled(true); - } - - panel->setAttachmentDetails(content); - } - else - { - LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; - } - } - else - { - LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; - } - } -} - -void fetchScriptLimitsAttachmentInfoResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} - -///---------------------------------------------------------------------------- // Memory Panel ///---------------------------------------------------------------------------- @@ -564,12 +199,8 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources() std::string url = gAgent.getRegion()->getCapability("LandResources"); if (!url.empty()) { - body["parcel_id"] = mParcelId; - - LLSD info; - info["parcel_id"] = mParcelId; - LLHTTPClient::post(url, body, new fetchScriptLimitsRegionInfoResponder(info)); - + LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro", + boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro, this, url)); return TRUE; } else @@ -578,6 +209,147 @@ BOOL LLPanelScriptLimitsRegionMemory::getLandScriptResources() } } +void LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptResourcesCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD postData; + + postData["parcel_id"] = mParcelId; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Failed to get script resource info" << LL_ENDL; + return; + } + + // We could retrieve these sequentially inline from this coroutine. But + // since the original code retrieved them in parallel I'll spawn two + // coroutines to do the retrieval. + + // The summary service: + if (result.has("ScriptResourceSummary")) + { + std::string urlResourceSummary = result["ScriptResourceSummary"].asString(); + LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro", + boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro, this, urlResourceSummary)); + } + + if (result.has("ScriptResourceDetails")) + { + std::string urlResourceDetails = result["ScriptResourceDetails"].asString(); + LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro", + boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro, this, urlResourceDetails)); + } + + +} + +void LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptSummaryCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve script summary." << LL_ENDL; + return; + } + + LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); + if (!instance) + { + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; + return; + } + + LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); + if (!tab) + { + LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; + return; + } + + LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); + if (!panelMemory) + { + LL_WARNS() << "Unable to get memory panel." << LL_ENDL; + return; + } + + panelMemory->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); + + LLButton* btn = panelMemory->getChild<LLButton>("refresh_list_btn"); + if (btn) + { + btn->setEnabled(true); + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + panelMemory->setRegionSummary(result); + +} + +void LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptDetailsCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve script details." << LL_ENDL; + return; + } + + LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); + + if (!instance) + { + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; + return; + } + + LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); + if (!tab) + { + LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; + return; + } + + LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild<LLPanel>("script_limits_region_memory_panel"); + + if (!panelMemory) + { + LL_WARNS() << "Unable to get memory panel." << LL_ENDL; + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + panelMemory->setRegionDetails(result); +} + void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data) { if(!getLandScriptResources()) @@ -935,17 +707,8 @@ BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain() std::string url = region->getCapability("RemoteParcelRequest"); if (!url.empty()) { - body["location"] = ll_sd_from_vector3(parcel_center); - if (!region_id.isNull()) - { - body["region_id"] = region_id; - } - if (!pos_global.isExactlyZero()) - { - U64 region_handle = to_region_handle(pos_global); - body["region_handle"] = ll_sd_from_U64(region_handle); - } - LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); + LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, + region_id, parcel_center, pos_global, getObserverHandle()); } else { @@ -1183,7 +946,8 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails() std::string url = gAgent.getRegion()->getCapability("AttachmentResources"); if (!url.empty()) { - LLHTTPClient::get(url, body, new fetchScriptLimitsAttachmentInfoResponder()); + LLCoros::instance().launch("LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro", + boost::bind(&LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro, this, url)); return TRUE; } else @@ -1192,6 +956,59 @@ BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails() } } +void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; + return; + } + + LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance<LLFloaterScriptLimits>("script_limits"); + + if (!instance) + { + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; + return; + } + + LLTabContainer* tab = instance->getChild<LLTabContainer>("scriptlimits_panels"); + if (!tab) + { + LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; + return; + } + + LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild<LLPanel>("script_limits_my_avatar_panel"); + if (!panel) + { + LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; + return; + } + + panel->getChild<LLUICtrl>("loading_text")->setValue(LLSD(std::string(""))); + + LLButton* btn = panel->getChild<LLButton>("refresh_list_btn"); + if (btn) + { + btn->setEnabled(true); + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + panel->setAttachmentDetails(result); +} + + void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content) { LLScrollListCtrl *list = getChild<LLScrollListCtrl>("scripts_list"); diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index 5ba0185d32..e3cbbd185f 100755 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -33,6 +33,8 @@ #include "llhost.h" #include "llpanel.h" #include "llremoteparcelrequest.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLPanelScriptLimitsInfo; class LLTabContainer; @@ -80,57 +82,6 @@ protected: }; ///////////////////////////////////////////////////////////////////////////// -// Responders -///////////////////////////////////////////////////////////////////////////// - -class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(fetchScriptLimitsRegionInfoResponder); -public: - fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - LLSD mInfo; -}; - -class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(fetchScriptLimitsRegionSummaryResponder); -public: - fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - LLSD mInfo; -}; - -class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(fetchScriptLimitsRegionDetailsResponder); -public: - fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - LLSD mInfo; -}; - -class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(fetchScriptLimitsAttachmentInfoResponder); -public: - fetchScriptLimitsAttachmentInfoResponder() {}; - -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); -}; - -///////////////////////////////////////////////////////////////////////////// // Memory panel ///////////////////////////////////////////////////////////////////////////// @@ -181,6 +132,10 @@ private: std::vector<LLSD> mObjectListItems; + void getLandScriptResourcesCoro(std::string url); + void getLandScriptSummaryCoro(std::string url); + void getLandScriptDetailsCoro(std::string url); + protected: // LLRemoteParcelInfoObserver interface: @@ -225,6 +180,7 @@ public: void clearList(); private: + void getAttachmentLimitsCoro(std::string url); bool mGotAttachmentMemoryUsed; S32 mAttachmentMemoryMax; diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index c1c21c593e..f6cfaf5522 100755 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -35,8 +35,6 @@ // linden library includes #include "llbutton.h" #include "llevents.h" -#include "llhttpclient.h" -#include "llhttpconstants.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "lltextbox.h" @@ -45,7 +43,7 @@ #include "llvfile.h" #include "message.h" #include "llstartup.h" // login_alert_done - +#include "llcorehttputil.h" LLFloaterTOS::LLFloaterTOS(const LLSD& data) : LLModalDialog( data["message"].asString() ), @@ -57,57 +55,6 @@ LLFloaterTOS::LLFloaterTOS(const LLSD& data) { } -// helper class that trys to download a URL from a web site and calls a method -// on parent class indicating if the web server is working or not -class LLIamHere : public LLHTTPClient::Responder -{ - LOG_CLASS(LLIamHere); -private: - LLIamHere( LLFloaterTOS* parent ) : - mParent( parent ) - {} - - LLFloaterTOS* mParent; - -public: - static LLIamHere* build( LLFloaterTOS* parent ) - { - return new LLIamHere( parent ); - } - - virtual void setParent( LLFloaterTOS* parentIn ) - { - mParent = parentIn; - } - -protected: - virtual void httpSuccess() - { - if ( mParent ) - { - mParent->setSiteIsAlive( true ); - } - } - - virtual void httpFailure() - { - LL_DEBUGS("LLIamHere") << dumpResponse() << LL_ENDL; - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (getStatus() == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - } -}; - -// this is global and not a class member to keep crud out of the header file -namespace { - LLPointer< LLIamHere > gResponsePtr = 0; -}; - BOOL LLFloaterTOS::postBuild() { childSetAction("Continue", onContinue, this); @@ -180,9 +127,6 @@ void LLFloaterTOS::setSiteIsAlive( bool alive ) LLFloaterTOS::~LLFloaterTOS() { - // tell the responder we're not here anymore - if ( gResponsePtr ) - gResponsePtr->setParent( 0 ); } // virtual @@ -243,9 +187,10 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev if(!mLoadingScreenLoaded) { mLoadingScreenLoaded = true; + std::string url(getString("real_url")); - gResponsePtr = LLIamHere::build( this ); - LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); + LLCoros::instance().launch("LLFloaterTOS::testSiteIsAliveCoro", + boost::bind(&LLFloaterTOS::testSiteIsAliveCoro, this, url)); } else if(mRealNavigateBegun) { @@ -257,3 +202,26 @@ void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev } } +void LLFloaterTOS::testSiteIsAliveCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + + LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + // double not. + // First ! returns a boolean error status, second ! is true if success result. + setSiteIsAlive(!!status); +} + + diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h index 47126d06a6..2748b20513 100755 --- a/indra/newview/llfloatertos.h +++ b/indra/newview/llfloatertos.h @@ -31,6 +31,8 @@ #include "llassetstorage.h" #include "llmediactrl.h" #include <boost/function.hpp> +#include "lleventcoro.h" +#include "llcoros.h" class LLButton; class LLRadioGroup; @@ -60,12 +62,15 @@ public: /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: + void testSiteIsAliveCoro(std::string url); std::string mMessage; bool mLoadingScreenLoaded; bool mSiteAlive; bool mRealNavigateBegun; std::string mReplyPumpName; + + }; #endif // LL_LLFLOATERTOS_H diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index 965d29b09c..b1316e386d 100755 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -42,41 +42,6 @@ #include "llnotificationsutil.h" #include "llradiogroup.h" -class EnteredKeyVerifier : public LLTranslate::KeyVerificationReceiver -{ -public: - EnteredKeyVerifier(LLTranslate::EService service, bool alert) - : LLTranslate::KeyVerificationReceiver(service) - , mAlert(alert) - { - } - -private: - /*virtual*/ void setVerificationStatus(bool ok) - { - LLFloaterTranslationSettings* floater = - LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation"); - - if (!floater) - { - LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL; - return; - } - - switch (getService()) - { - case LLTranslate::SERVICE_BING: - floater->setBingVerified(ok, mAlert); - break; - case LLTranslate::SERVICE_GOOGLE: - floater->setGoogleVerified(ok, mAlert); - break; - } - } - - bool mAlert; -}; - LLFloaterTranslationSettings::LLFloaterTranslationSettings(const LLSD& key) : LLFloater(key) , mMachineTranslationCB(NULL) @@ -231,11 +196,34 @@ void LLFloaterTranslationSettings::updateControlsEnabledState() mOKBtn->setEnabled(!on || service_verified); } +/*static*/ +void LLFloaterTranslationSettings::setVerificationStatus(int service, bool ok, bool alert) +{ + LLFloaterTranslationSettings* floater = + LLFloaterReg::getTypedInstance<LLFloaterTranslationSettings>("prefs_translation"); + + if (!floater) + { + LL_WARNS() << "Cannot find translation settings floater" << LL_ENDL; + return; + } + + switch (service) + { + case LLTranslate::SERVICE_BING: + floater->setBingVerified(ok, alert); + break; + case LLTranslate::SERVICE_GOOGLE: + floater->setGoogleVerified(ok, alert); + break; + } +} + + void LLFloaterTranslationSettings::verifyKey(int service, const std::string& key, bool alert) { - LLTranslate::KeyVerificationReceiverPtr receiver = - new EnteredKeyVerifier((LLTranslate::EService) service, alert); - LLTranslate::verifyKey(receiver, key); + LLTranslate::verifyKey(static_cast<LLTranslate::EService>(service), key, + boost::bind(&LLFloaterTranslationSettings::setVerificationStatus, _1, _2, alert)); } void LLFloaterTranslationSettings::onEditorFocused(LLFocusableElement* control) diff --git a/indra/newview/llfloatertranslationsettings.h b/indra/newview/llfloatertranslationsettings.h index b9bfd6265a..2a15eacded 100755 --- a/indra/newview/llfloatertranslationsettings.h +++ b/indra/newview/llfloatertranslationsettings.h @@ -61,6 +61,8 @@ private: void onBtnGoogleVerify(); void onBtnOK(); + static void setVerificationStatus(int service, bool alert, bool ok); + LLCheckBoxCtrl* mMachineTranslationCB; LLComboBox* mLanguageCombo; LLLineEditor* mBingAPIKeyEditor; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index e02e8eeb5a..f2efef0c33 100755 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -26,8 +26,6 @@ #include "llviewerprecompiledheaders.h" -#include "llhttpclient.h" - #include "llfloaterurlentry.h" #include "llpanellandmedia.h" @@ -40,40 +38,10 @@ #include "lluictrlfactory.h" #include "llwindow.h" #include "llviewerwindow.h" +#include "llcorehttputil.h" static LLFloaterURLEntry* sInstance = NULL; -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMediaTypeResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLMediaTypeResponder); -public: - LLMediaTypeResponder( const LLHandle<LLFloater> parent ) : - mParent( parent ) - {} - - LLHandle<LLFloater> mParent; - -private: - /* virtual */ void httpCompleted() - { - const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - - // Set empty type to none/none. Empty string is reserved for legacy parcels - // which have no mime type set. - std::string resolved_mime_type = ! mime_type.empty() ? mime_type : LLMIMETypes::getDefaultMimeType(); - LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mParent.get(); - if ( floater_url_entry ) - { - floater_url_entry->headerFetchComplete( getStatus(), resolved_mime_type ); - } - } -}; - //----------------------------------------------------------------------------- // LLFloaterURLEntry() //----------------------------------------------------------------------------- @@ -225,8 +193,8 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) if(!media_url.empty() && (scheme == "http" || scheme == "https")) { - LLHTTPClient::getHeaderOnly( media_url, - new LLMediaTypeResponder(self->getHandle())); + LLCoros::instance().launch("LLFloaterURLEntry::getMediaTypeCoro", + boost::bind(&LLFloaterURLEntry::getMediaTypeCoro, media_url, self->getHandle())); } else { @@ -240,6 +208,58 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) } // static +void LLFloaterURLEntry::getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMediaTypeCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + httpOpts->setHeadersOnly(true); + + LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLFloaterURLEntry* floaterUrlEntry = (LLFloaterURLEntry*)parentHandle.get(); + if (!floaterUrlEntry) + { + LL_WARNS() << "Could not get URL entry floater." << LL_ENDL; + return; + } + + // Set empty type to none/none. Empty string is reserved for legacy parcels + // which have no mime type set. + std::string resolvedMimeType = LLMIMETypes::getDefaultMimeType(); + + if (!status) + { + floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType); + return; + } + + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + + if (resultHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) + { + const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE]; + std::string::size_type idx1 = mediaType.find_first_of(";"); + std::string mimeType = mediaType.substr(0, idx1); + if (!mimeType.empty()) + { + resolvedMimeType = mimeType; + } + } + + floaterUrlEntry->headerFetchComplete(status.getType(), resolvedMimeType); + +} + +// static //----------------------------------------------------------------------------- // onBtnCancel() //----------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index bdd1ebe592..20f4604907 100755 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -29,6 +29,8 @@ #include "llfloater.h" #include "llpanellandmedia.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLLineEditor; class LLComboBox; @@ -56,7 +58,10 @@ private: static void onBtnOK(void*); static void onBtnCancel(void*); static void onBtnClear(void*); - bool callback_clear_url_list(const LLSD& notification, const LLSD& response); + bool callback_clear_url_list(const LLSD& notification, const LLSD& response); + + static void getMediaTypeCoro(std::string url, LLHandle<LLFloater> parentHandle); + }; #endif // LL_LLFLOATERURLENTRY_H diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 86f9da6318..4559132aeb 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -41,7 +41,6 @@ #include "llui.h" #include "message.h" #include "roles_constants.h" -#include "llhttpclient.h" #include "lltransactiontypes.h" #include "llstatusbar.h" #include "lleconomy.h" @@ -53,6 +52,7 @@ #include "lltrans.h" #include "llviewerregion.h" #include <boost/regex.hpp> +#include "llcorehttputil.h" #if LL_MSVC #pragma warning(push) @@ -768,9 +768,9 @@ void LLGroupMgrGroupData::removeBanEntry(const LLUUID& ban_id) // LLGroupMgr // -LLGroupMgr::LLGroupMgr() +LLGroupMgr::LLGroupMgr(): + mMemberRequestInFlight(false) { - mLastGroupMembersRequestFrame = 0; } LLGroupMgr::~LLGroupMgr() @@ -1861,49 +1861,94 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, group_datap->mMemberVersion.generate(); } - -// Responder class for capability group management -class GroupBanDataResponder : public LLHTTPClient::Responder +void LLGroupMgr::getGroupBanRequestCoro(std::string url, LLUUID groupId) { -public: - GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false); - virtual ~GroupBanDataResponder() {} - virtual void httpSuccess(); - virtual void httpFailure(); -private: - LLUUID mGroupID; - BOOL mForceRefresh; -}; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); -GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) : - mGroupID(gropup_id), - mForceRefresh(force_refresh) -{} + std::string finalUrl = url + "?group_id=" + groupId.asString(); -void GroupBanDataResponder::httpFailure() -{ - LL_WARNS("GrpMgr") << "Error receiving group member data [status:" - << mStatus << "]: " << mContent << LL_ENDL; + LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; + return; + } + + if (result.has("ban_list")) + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + // group ban data received + processGroupBanRequest(result); + } } -void GroupBanDataResponder::httpSuccess() +void LLGroupMgr::postGroupBanRequestCoro(std::string url, LLUUID groupId, + U32 action, uuid_vec_t banList, bool update) { - if (mContent.has("ban_list")) - { - // group ban data received - LLGroupMgr::processGroupBanRequest(mContent); - } - else if (mForceRefresh) - { - // no ban data received, refreshing data after successful operation - LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions); + + httpOptions->setFollowRedirects(false); + + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + + + std::string finalUrl = url + "?group_id=" + groupId.asString(); + + LLSD postData = LLSD::emptyMap(); + postData["ban_action"] = (LLSD::Integer)action; + // Add our list of potential banned residents to the list + postData["ban_ids"] = LLSD::emptyArray(); + LLSD banEntry; + + uuid_vec_t::const_iterator it = banList.begin(); + for (; it != banList.end(); ++it) + { + banEntry = (*it); + postData["ban_ids"].append(banEntry); + } + + LL_WARNS() << "post: " << ll_pretty_print_sd(postData) << LL_ENDL; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, finalUrl, postData, httpOptions, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("GrpMgr") << "Error posting group member data " << LL_ENDL; + return; + } + + if (result.has("ban_list")) + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + // group ban data received + processGroupBanRequest(result); + } + + if (update) + { + getGroupBanRequestCoro(url, groupId); + } } void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, const LLUUID& group_id, U32 ban_action, /* = BAN_NO_ACTION */ - const std::vector<LLUUID> ban_list) /* = std::vector<LLUUID>() */ + const std::vector<LLUUID> &ban_list) /* = std::vector<LLUUID>() */ { LLViewerRegion* currentRegion = gAgent.getRegion(); if(!currentRegion) @@ -1925,37 +1970,27 @@ void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, { return; } - cap_url += "?group_id=" + group_id.asString(); - - LLSD body = LLSD::emptyMap(); - body["ban_action"] = (LLSD::Integer)(ban_action & ~BAN_UPDATE); - // Add our list of potential banned residents to the list - body["ban_ids"] = LLSD::emptyArray(); - LLSD ban_entry; - uuid_vec_t::const_iterator iter = ban_list.begin(); - for(;iter != ban_list.end(); ++iter) - { - ban_entry = (*iter); - body["ban_ids"].append(ban_entry); - } + U32 action = ban_action & ~BAN_UPDATE; + bool update = ((ban_action & BAN_UPDATE) == BAN_UPDATE); - LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder(group_id, ban_action & BAN_UPDATE); - switch(request_type) - { - case REQUEST_GET: - LLHTTPClient::get(cap_url, grp_ban_responder); - break; - case REQUEST_POST: - LLHTTPClient::post(cap_url, body, grp_ban_responder); - break; - case REQUEST_PUT: - case REQUEST_DEL: - break; - } + switch (request_type) + { + case REQUEST_GET: + LLCoros::instance().launch("LLGroupMgr::getGroupBanRequestCoro", + boost::bind(&LLGroupMgr::getGroupBanRequestCoro, this, cap_url, group_id)); + break; + case REQUEST_POST: + LLCoros::instance().launch("LLGroupMgr::postGroupBanRequestCoro", + boost::bind(&LLGroupMgr::postGroupBanRequestCoro, this, cap_url, group_id, + action, ban_list, update)); + break; + case REQUEST_PUT: + case REQUEST_DEL: + break; + } } - void LLGroupMgr::processGroupBanRequest(const LLSD& content) { // Did we get anything in content? @@ -1993,45 +2028,42 @@ void LLGroupMgr::processGroupBanRequest(const LLSD& content) LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST); } +void LLGroupMgr::groupMembersRequestCoro(std::string url, LLUUID groupId) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + mMemberRequestInFlight = true; -// Responder class for capability group management -class GroupMemberDataResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(GroupMemberDataResponder); -public: - GroupMemberDataResponder() {} - virtual ~GroupMemberDataResponder() {} + LLSD postData = LLSD::emptyMap(); + postData["group_id"] = groupId; -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - LLSD mMemberData; -}; + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts); -void GroupMemberDataResponder::httpFailure() -{ - LL_WARNS("GrpMgr") << "Error receiving group member data " - << dumpResponse() << LL_ENDL; -} + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -void GroupMemberDataResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLGroupMgr::processCapGroupMembersRequest(content); -} + if (!status) + { + LL_WARNS("GrpMgr") << "Error receiving group member data " << LL_ENDL; + mMemberRequestInFlight = false; + return; + } + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + LLGroupMgr::processCapGroupMembersRequest(result); + mMemberRequestInFlight = false; +} -// static void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id) { + static U32 lastGroupMemberRequestFrame = 0; + // Have we requested the information already this frame? - if(mLastGroupMembersRequestFrame == gFrameCount) + if ((lastGroupMemberRequestFrame == gFrameCount) || (mMemberRequestInFlight)) return; LLViewerRegion* currentRegion = gAgent.getRegion(); @@ -2060,20 +2092,13 @@ void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id) return; } - // Post to our service. Add a body containing the group_id. - LLSD body = LLSD::emptyMap(); - body["group_id"] = group_id; + lastGroupMemberRequestFrame = gFrameCount; - LLHTTPClient::ResponderPtr grp_data_responder = new GroupMemberDataResponder(); - - // This could take a while to finish, timeout after 5 minutes. - LLHTTPClient::post(cap_url, body, grp_data_responder, LLSD(), 300); - - mLastGroupMembersRequestFrame = gFrameCount; + LLCoros::instance().launch("LLGroupMgr::groupMembersRequestCoro", + boost::bind(&LLGroupMgr::groupMembersRequestCoro, this, cap_url, group_id)); } -// static void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) { // Did we get anything in content? @@ -2090,7 +2115,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) LLUUID group_id = content["group_id"].asUUID(); - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); + LLGroupMgrGroupData* group_datap = getGroupData(group_id); if(!group_datap) { LL_WARNS("GrpMgr") << "Received incorrect, possibly stale, group or request id" << LL_ENDL; @@ -2184,7 +2209,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) // TODO: // Refactor to reduce multiple calls for data we already have. if(group_datap->mTitles.size() < 1) - LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); + sendGroupTitlesRequest(group_id); group_datap->mMemberDataComplete = true; @@ -2193,11 +2218,11 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete) { group_datap->mPendingRoleMemberRequest = false; - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id); + sendGroupRoleMembersRequest(group_id); } group_datap->mChanged = TRUE; - LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); + notifyObservers(GC_MEMBER_DATA); } diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index 2e94e8d9a0..fd0c2de854 100755 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -32,6 +32,8 @@ #include <vector> #include <string> #include <map> +#include "lleventcoro.h" +#include "llcoros.h" // Forward Declarations class LLMessageSystem; @@ -362,6 +364,7 @@ public: BAN_UPDATE = 4 }; + public: LLGroupMgr(); ~LLGroupMgr(); @@ -396,15 +399,13 @@ public: static void sendGroupMemberEjects(const LLUUID& group_id, uuid_vec_t& member_ids); - static void sendGroupBanRequest(EBanRequestType request_type, + void sendGroupBanRequest(EBanRequestType request_type, const LLUUID& group_id, U32 ban_action = BAN_NO_ACTION, - const uuid_vec_t ban_list = uuid_vec_t()); + const uuid_vec_t &ban_list = uuid_vec_t()); - static void processGroupBanRequest(const LLSD& content); void sendCapGroupMembersRequest(const LLUUID& group_id); - static void processCapGroupMembersRequest(const LLSD& content); void cancelGroupRoleChanges(const LLUUID& group_id); @@ -427,6 +428,14 @@ public: void clearGroupData(const LLUUID& group_id); private: + void groupMembersRequestCoro(std::string url, LLUUID groupId); + void processCapGroupMembersRequest(const LLSD& content); + + void getGroupBanRequestCoro(std::string url, LLUUID groupId); + void postGroupBanRequestCoro(std::string url, LLUUID groupId, U32 action, uuid_vec_t banList, bool update); + + static void processGroupBanRequest(const LLSD& content); + void notifyObservers(LLGroupChange gc); void notifyObserver(const LLUUID& group_id, LLGroupChange gc); void addGroup(LLGroupMgrGroupData* group_datap); @@ -442,7 +451,7 @@ private: typedef std::map<LLUUID,observer_set_t> observer_map_t; observer_map_t mParticularObservers; - S32 mLastGroupMembersRequestFrame; + bool mMemberRequestInFlight; }; diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp deleted file mode 100755 index d0492bcdb4..0000000000 --- a/indra/newview/llhomelocationresponder.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file llhomelocationresponder.cpp - * @author Meadhbh Hamrick - * @brief Processes responses to the HomeLocation CapReq - * - * $LicenseInfo:firstyear=2008&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$ - */ - -/* File Inclusions */ -#include "llviewerprecompiledheaders.h" - -#include "llhomelocationresponder.h" -#include "llsdutil.h" -#include "llagent.h" -#include "llviewerregion.h" - -void LLHomeLocationResponder::httpSuccess() -{ - const LLSD& content = getContent(); - LLVector3 agent_pos; - bool error = true; - - do { - - // was the call to /agent/<agent-id>/home-location successful? - // If not, we keep error set to true - if( ! content.has("success") ) - { - break; - } - - if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) ) - { - break; - } - - // did the simulator return a "justified" home location? - // If no, we keep error set to true - if( ! content.has( "HomeLocation" ) ) - { - break; - } - - if( ! content["HomeLocation"].has("LocationPos") ) - { - break; - } - - if( ! content["HomeLocation"]["LocationPos"].has("X") ) - { - break; - } - - agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); - - if( ! content["HomeLocation"]["LocationPos"].has("Y") ) - { - break; - } - - agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); - - if( ! content["HomeLocation"]["LocationPos"].has("Z") ) - { - break; - } - - agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); - - error = false; - } while( 0 ); - - if( error ) - { - failureResult(HTTP_INTERNAL_ERROR, "Invalid server response content", content); - } - else - { - LL_INFOS() << "setting home position" << LL_ENDL; - - LLViewerRegion *viewer_region = gAgent.getRegion(); - gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); - } -} - -void LLHomeLocationResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; -} diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h deleted file mode 100755 index adc6c8cb58..0000000000 --- a/indra/newview/llhomelocationresponder.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file llhomelocationresponder.h - * @author Meadhbh Hamrick - * @brief Processes responses to the HomeLocation CapReq - * - * $LicenseInfo:firstyear=2008&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$ - */ - - /* Macro Definitions */ -#ifndef LL_LLHOMELOCATIONRESPONDER_H -#define LL_LLHOMELOCATIONRESPONDER_H - -/* File Inclusions */ -#include "llhttpclient.h" - -/* Typedef, Enum, Class, Struct, etc. */ -class LLHomeLocationResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLHomeLocationResponder); -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); -}; - -#endif diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp index 2d4ce6c883..6a2daeeb90 100755 --- a/indra/newview/llhttpretrypolicy.cpp +++ b/indra/newview/llhttpretrypolicy.cpp @@ -25,9 +25,23 @@ */ #include "llviewerprecompiledheaders.h" - #include "llhttpretrypolicy.h" +namespace +{ + // Moved from httpconstants.h... only used in this file. + bool isHttpServerErrorStatus(S32 status) + { + // Status 499 is sometimes used for re-interpreted status 2xx errors. + // Allow retry of these, since we don't have enough information in this + // context to know if this will always fail. + if (HTTP_INTERNAL_ERROR == status) return true; + + // Check for status 5xx. + return((500 <= status) && (status < 600)); + } +} + LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx): mMinDelay(min_delay), mMaxDelay(max_delay), @@ -56,7 +70,7 @@ bool LLAdaptiveRetryPolicy::getRetryAfter(const LLSD& headers, F32& retry_header && getSecondsUntilRetryAfter(headers[HTTP_IN_HEADER_RETRY_AFTER].asStringRef(), retry_header_time)); } -bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time) +bool LLAdaptiveRetryPolicy::getRetryAfter(const LLCore::HttpHeaders::ptr_t &headers, F32& retry_header_time) { if (headers) { @@ -85,9 +99,9 @@ void LLAdaptiveRetryPolicy::onFailure(S32 status, const LLSD& headers) void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response) { F32 retry_header_time; - const LLCore::HttpHeaders *headers = response->getHeaders(); + const LLCore::HttpHeaders::ptr_t headers = response->getHeaders(); bool has_retry_header_time = getRetryAfter(headers,retry_header_time); - onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time); + onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time); } void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) @@ -140,3 +154,34 @@ bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX; return mShouldRetry; } + +// Moved from httpconstants. Only used by this file. +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +/*static*/ +bool LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait) +{ + // *TODO: This needs testing! Not in use yet. + // Examples of Retry-After headers: + // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT + // Retry-After: 120 + + // Check for number of seconds version, first: + char* end = 0; + // Parse as double + double seconds = std::strtod(retry_after.c_str(), &end); + if (end != 0 && *end == 0) + { + // Successful parse + seconds_to_wait = (F32)seconds; + return true; + } + + // Parse rfc1123 date. + time_t date = curl_getdate(retry_after.c_str(), NULL); + if (-1 == date) return false; + + seconds_to_wait = (F64)date - LLTimer::getTotalSeconds(); + + return true; +} + diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h index cf79e0b401..af07b4afec 100755 --- a/indra/newview/llhttpretrypolicy.h +++ b/indra/newview/llhttpretrypolicy.h @@ -76,10 +76,12 @@ public: // virtual bool shouldRetry(F32& seconds_to_wait) const; + static bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait); + protected: void init(); bool getRetryAfter(const LLSD& headers, F32& retry_header_time); - bool getRetryAfter(const LLCore::HttpHeaders *headers, F32& retry_header_time); + bool getRetryAfter(const LLCore::HttpHeaders::ptr_t &headers, F32& retry_header_time); void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); private: diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index b8b6bdaa11..53b97a58c5 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -37,7 +37,6 @@ #include "llrect.h" #include "llerror.h" #include "llbutton.h" -#include "llhttpclient.h" #include "llsdutil_math.h" #include "llstring.h" #include "lltextutil.h" @@ -69,6 +68,7 @@ #include "llconversationlog.h" #include "message.h" #include "llviewerregion.h" +#include "llcorehttputil.h" const static std::string ADHOC_NAME_SUFFIX(" Conference"); @@ -79,6 +79,10 @@ const static std::string NEARBY_P2P_BY_AGENT("nearby_P2P_by_agent"); /** Timeout of outgoing session initialization (in seconds) */ const static U32 SESSION_INITIALIZATION_TIMEOUT = 30; +void startConfrenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents); +void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType); +void start_deprecated_conference_chat(const LLUUID& temp_session_id, const LLUUID& creator_id, const LLUUID& other_participant_id, const LLSD& agents_to_invite); + std::string LLCallDialogManager::sPreviousSessionlName = ""; LLIMModel::LLIMSession::SType LLCallDialogManager::sPreviousSessionType = LLIMModel::LLIMSession::P2P_SESSION; std::string LLCallDialogManager::sCurrentSessionlName = ""; @@ -110,7 +114,7 @@ void process_dnd_im(const LLSD& notification) { LLSD data = notification["substitutions"]; LLUUID sessionID = data["SESSION_ID"].asUUID(); - LLUUID fromID = data["FROM_ID"].asUUID(); + LLUUID fromID = data["FROM_ID"].asUUID(); //re-create the IM session if needed //(when coming out of DND mode upon app restart) @@ -131,12 +135,10 @@ void process_dnd_im(const LLSD& notification) fromID, false, false); //will need slight refactor to retrieve whether offline message or not (assume online for now) - } - - notify_of_message(data, true); } - + notify_of_message(data, true); +} static void on_avatar_name_cache_toast(const LLUUID& agent_id, @@ -387,6 +389,130 @@ void on_new_message(const LLSD& msg) notify_of_message(msg, false); } +void startConfrenceCoro(std::string url, + LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD postData; + postData["method"] = "start conference"; + postData["session-id"] = tempSessionId; + postData["params"] = agents; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("LLIMModel") << "Failed to start conference" << LL_ENDL; + //try an "old school" way. + // *TODO: What about other error status codes? 4xx 5xx? + if (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)) + { + start_deprecated_conference_chat( + tempSessionId, + creatorId, + otherParticipantId, + agents); + } + + //else throw an error back to the client? + //in theory we should have just have these error strings + //etc. set up in this file as opposed to the IMMgr, + //but the error string were unneeded here previously + //and it is not worth the effort switching over all + //the possible different language translations + } +} + +void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD postData; + postData["method"] = "accept invitation"; + postData["session-id"] = sessionId; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!gIMMgr) + { + LL_WARNS("") << "Global IM Manager is NULL" << LL_ENDL; + return; + } + + if (!status) + { + LL_WARNS("LLIMModel") << "Bad HTTP response in chatterBoxInvitationCoro" << LL_ENDL; + //throw something back to the viewer here? + + gIMMgr->clearPendingAgentListUpdates(sessionId); + gIMMgr->clearPendingInvitation(sessionId); + + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + static const std::string error_string("session_does_not_exist_error"); + gIMMgr->showSessionStartError(error_string, sessionId); + } + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + + LLIMSpeakerMgr* speakerMgr = LLIMModel::getInstance()->getSpeakerManager(sessionId); + if (speakerMgr) + { + //we've accepted our invitation + //and received a list of agents that were + //currently in the session when the reply was sent + //to us. Now, it is possible that there were some agents + //to slip in/out between when that message was sent to us + //and now. + + //the agent list updates we've received have been + //accurate from the time we were added to the session + //but unfortunately, our base that we are receiving here + //may not be the most up to date. It was accurate at + //some point in time though. + speakerMgr->setSpeakers(result); + + //we now have our base of users in the session + //that was accurate at some point, but maybe not now + //so now we apply all of the updates we've received + //in case of race conditions + speakerMgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(sessionId)); + } + + if (LLIMMgr::INVITATION_TYPE_VOICE == invitationType) + { + gIMMgr->startCall(sessionId, LLVoiceChannel::INCOMING_CALL); + } + + if ((invitationType == LLIMMgr::INVITATION_TYPE_VOICE + || invitationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) + && LLIMModel::getInstance()->findIMSession(sessionId)) + { + // TODO remove in 2010, for voice calls we do not open an IM window + //LLFloaterIMSession::show(mSessionID); + } + + gIMMgr->clearPendingAgentListUpdates(sessionId); + gIMMgr->clearPendingInvitation(sessionId); + +} + + LLIMModel::LLIMModel() { addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1)); @@ -1465,54 +1591,6 @@ void start_deprecated_conference_chat( delete[] bucket; } -class LLStartConferenceChatResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLStartConferenceChatResponder); -public: - LLStartConferenceChatResponder( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) - { - mTempSessionID = temp_session_id; - mCreatorID = creator_id; - mOtherParticipantID = other_participant_id; - mAgents = agents_to_invite; - } - -protected: - virtual void httpFailure() - { - //try an "old school" way. - // *TODO: What about other error status codes? 4xx 5xx? - if ( getStatus() == HTTP_BAD_REQUEST ) - { - start_deprecated_conference_chat( - mTempSessionID, - mCreatorID, - mOtherParticipantID, - mAgents); - } - - LL_WARNS() << dumpResponse() << LL_ENDL; - - //else throw an error back to the client? - //in theory we should have just have these error strings - //etc. set up in this file as opposed to the IMMgr, - //but the error string were unneeded here previously - //and it is not worth the effort switching over all - //the possible different language translations - } - -private: - LLUUID mTempSessionID; - LLUUID mCreatorID; - LLUUID mOtherParticipantID; - - LLSD mAgents; -}; - // Returns true if any messages were sent, false otherwise. // Is sort of equivalent to "does the server need to do anything?" bool LLIMModel::sendStartSession( @@ -1549,20 +1627,10 @@ bool LLIMModel::sendStartSession( { std::string url = region->getCapability( "ChatSessionRequest"); - LLSD data; - data["method"] = "start conference"; - data["session-id"] = temp_session_id; - - data["params"] = agents; - LLHTTPClient::post( - url, - data, - new LLStartConferenceChatResponder( - temp_session_id, - gAgent.getID(), - other_participant_id, - data["params"])); + LLCoros::instance().launch("startConfrenceCoro", + boost::bind(&startConfrenceCoro, url, + temp_session_id, gAgent.getID(), other_participant_id, agents)); } else { @@ -1580,97 +1648,6 @@ bool LLIMModel::sendStartSession( return false; } -// -// Helper Functions -// - -class LLViewerChatterBoxInvitationAcceptResponder : - public LLHTTPClient::Responder -{ - LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder); -public: - LLViewerChatterBoxInvitationAcceptResponder( - const LLUUID& session_id, - LLIMMgr::EInvitationType invitation_type) - { - mSessionID = session_id; - mInvitiationType = invitation_type; - } - -private: - void httpSuccess() - { - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - if ( gIMMgr) - { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); - if (speaker_mgr) - { - //we've accepted our invitation - //and received a list of agents that were - //currently in the session when the reply was sent - //to us. Now, it is possible that there were some agents - //to slip in/out between when that message was sent to us - //and now. - - //the agent list updates we've received have been - //accurate from the time we were added to the session - //but unfortunately, our base that we are receiving here - //may not be the most up to date. It was accurate at - //some point in time though. - speaker_mgr->setSpeakers(content); - - //we now have our base of users in the session - //that was accurate at some point, but maybe not now - //so now we apply all of the udpates we've received - //in case of race conditions - speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); - } - - if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType) - { - gIMMgr->startCall(mSessionID, LLVoiceChannel::INCOMING_CALL); - } - - if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE - || mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) - && LLIMModel::getInstance()->findIMSession(mSessionID)) - { - // TODO remove in 2010, for voice calls we do not open an IM window - //LLFloaterIMSession::show(mSessionID); - } - - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInvitation(mSessionID); - } - } - - void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - //throw something back to the viewer here? - if ( gIMMgr ) - { - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInvitation(mSessionID); - if ( HTTP_NOT_FOUND == getStatus() ) - { - static const std::string error_string("session_does_not_exist_error"); - gIMMgr->showSessionStartError(error_string, mSessionID); - } - } - } - -private: - LLUUID mSessionID; - LLIMMgr::EInvitationType mInvitiationType; -}; - // the other_participant_id is either an agent_id, a group_id, or an inventory // folder item_id (collection of calling cards) @@ -2496,15 +2473,9 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload if (voice) { - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - inv_type)); + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, + session_id, inv_type)); // send notification message to the corresponding chat if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc") @@ -2539,10 +2510,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload LLSD data; data["method"] = "decline invitation"; data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - NULL); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, + "Invitation declined", + "Invitation decline failed."); } } @@ -2589,15 +2560,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) std::string url = gAgent.getRegion()->getCapability( "ChatSessionRequest"); - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - inv_type)); + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, + session_id, inv_type)); } } break; @@ -2627,10 +2592,9 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) LLSD data; data["method"] = "decline invitation"; data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - NULL); + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, + "Invitation declined.", + "Invitation decline failed."); } } @@ -3687,15 +3651,9 @@ public: if ( url != "" ) { - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); + LLCoros::instance().launch("chatterBoxInvitationCoro", + boost::bind(&chatterBoxInvitationCoro, url, + session_id, LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); } } //end if invitation has instant message else if ( input["body"].has("voice") ) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index f92eff4845..41a8813acb 100755 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,6 +34,9 @@ #include "lllogchat.h" #include "llvoicechannel.h" +#include "llcoros.h" +#include "lleventcoro.h" + class LLAvatarName; class LLFriendObserver; class LLCallDialogManager; @@ -292,6 +295,7 @@ private: * Add message to a list of message associated with session specified by session_id */ bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text); + }; class LLIMSessionObserver diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 605f71f412..0c70b074bf 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -124,11 +124,6 @@ bool isRemoveAction(const std::string& action) return ("take_off" == action || "detach" == action || "deactivate" == action); } -bool isMarketplaceCopyAction(const std::string& action) -{ - return (("copy_to_outbox" == action) || ("move_to_outbox" == action)); -} - bool isMarketplaceSendAction(const std::string& action) { return ("send_to_marketplace" == action); @@ -777,14 +772,6 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, { items.push_back(std::string("Marketplace Separator")); - if (gMenuHolder->getChild<LLView>("MerchantOutbox")->getVisible()) - { - items.push_back(std::string("Merchant Copy")); - if (!canListOnOutboxNow()) - { - disabled_items.push_back(std::string("Merchant Copy")); - } - } if (gMenuHolder->getChild<LLView>("MarketplaceListings")->getVisible()) { items.push_back(std::string("Marketplace Copy")); @@ -799,8 +786,8 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } - // Don't allow items to be pasted directly into the COF or the inbox/outbox - if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder()) + // Don't allow items to be pasted directly into the COF or the inbox + if (!isCOFFolder() && !isInboxFolder()) { items.push_back(std::string("Paste")); } @@ -838,10 +825,6 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } else { items.push_back(std::string("Share")); @@ -942,19 +925,6 @@ void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items) items.push_back(std::string("Open")); } -void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags, - menuentry_vec_t &items, - menuentry_vec_t &disabled_items) -{ - items.push_back(std::string("Rename")); - items.push_back(std::string("Delete")); - - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Rename")); - } -} - void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags, menuentry_vec_t &items, menuentry_vec_t &disabled_items) @@ -1204,41 +1174,6 @@ BOOL LLInvFVBridge::isMarketplaceListingsFolder() const return gInventory.isObjectDescendentOf(mUUID, folder_id); } -BOOL LLInvFVBridge::isOutboxFolder() const -{ - const LLUUID outbox_id = getOutboxFolder(); - - if (outbox_id.isNull()) - { - return FALSE; - } - - return gInventory.isObjectDescendentOf(mUUID, outbox_id); -} - -BOOL LLInvFVBridge::isOutboxFolderDirectParent() const -{ - BOOL outbox_is_parent = FALSE; - - const LLInventoryCategory *cat = gInventory.getCategory(mUUID); - - if (cat) - { - const LLUUID outbox_id = getOutboxFolder(); - - outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID())); - } - - return outbox_is_parent; -} - -const LLUUID LLInvFVBridge::getOutboxFolder() const -{ - const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - - return outbox_id; -} - BOOL LLInvFVBridge::isItemPermissive() const { return FALSE; @@ -1495,56 +1430,6 @@ bool LLInvFVBridge::canListOnMarketplace() const return true; } -// *TODO : Suppress canListOnOutboxNow() once we deprecate Merchant Outbox completely -bool LLInvFVBridge::canListOnOutboxNow() const -{ - bool can_list = true; - - // Do not allow listing while import is in progress - if (LLMarketplaceInventoryImporter::instanceExists()) - { - can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress(); - } - - const LLInventoryObject* obj = getInventoryObject(); - can_list &= (obj != NULL); - - if (can_list) - { - const LLUUID& object_id = obj->getLinkedUUID(); - can_list = object_id.notNull(); - - if (can_list) - { - LLFolderViewFolder * object_folderp = mInventoryPanel.get() ? mInventoryPanel.get()->getFolderByID(object_id) : NULL; - if (object_folderp) - { - can_list = !static_cast<LLFolderBridge*>(object_folderp->getViewModelItem())->isLoading(); - } - } - - if (can_list) - { - // Get outbox id - const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - LLFolderViewItem * outbox_itemp = mInventoryPanel.get() ? mInventoryPanel.get()->getItemByID(outbox_id) : NULL; - - if (outbox_itemp) - { - MASK mask = 0x0; - BOOL drop = FALSE; - EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); - void * cargo_data = (void *) obj; - std::string tooltip_msg; - - can_list = outbox_itemp->getViewModelItem()->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg); - } - } - } - - return can_list; -} - bool LLInvFVBridge::canListOnMarketplaceNow() const { bool can_list = true; @@ -1714,16 +1599,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) folder_view_itemp->getViewModelItem()->pasteLinkFromClipboard(); return; } - else if (isMarketplaceCopyAction(action)) - { - LL_INFOS() << "Copy item to marketplace action!" << LL_ENDL; - - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - - const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId()); - } else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) { LLInventoryItem* itemp = model->getItem(mUUID); @@ -2455,13 +2330,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID from_folder_uuid = inv_cat->getParentUUID(); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); - const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id); const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id); @@ -2602,9 +2474,9 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } - if (is_movable && (move_is_into_outbox || move_is_into_marketplacelistings)) + if (is_movable && move_is_into_marketplacelistings) { - const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID)); + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); LLViewerInventoryCategory * dest_folder = getCategory(); S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount()); is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size); @@ -2713,10 +2585,6 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL append = true; LLAppearanceMgr::instance().wearInventoryCategory(inv_cat, false, append); } - else if (move_is_into_outbox && !move_is_from_outbox) - { - copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId()); - } else if (move_is_into_marketplacelistings) { move_folder_to_marketplacelistings(inv_cat, mUUID); @@ -2767,7 +2635,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -2779,7 +2647,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) { - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -3296,16 +3164,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) removeSystemFolder(); } #endif - else if (isMarketplaceCopyAction(action)) - { - LL_INFOS() << "Copy folder to marketplace action!" << LL_ENDL; - - LLInventoryCategory * cat = gInventory.getCategory(mUUID); - if (!cat) return; - - const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId()); - } else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) { LLInventoryCategory * cat = gInventory.getCategory(mUUID); @@ -3546,7 +3404,6 @@ void LLFolderBridge::perform_pasteFromClipboard() if (model && isClipboardPasteable()) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); @@ -3554,7 +3411,6 @@ void LLFolderBridge::perform_pasteFromClipboard() const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const BOOL move_is_into_favorites = (mUUID == favorites_id); @@ -3562,10 +3418,10 @@ void LLFolderBridge::perform_pasteFromClipboard() LLClipboard::instance().pasteFromClipboard(objects); LLViewerInventoryCategory * dest_folder = getCategory(); - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { std::string error_msg; - const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID)); + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); int index = 0; for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) { @@ -3744,17 +3600,15 @@ void LLFolderBridge::pasteLinkFromClipboard() if(model) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { // Notify user of failure somehow -- play error sound? modal dialog? return; @@ -3875,10 +3729,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items items.clear(); // clear any items that used to exist addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } else if(isAgentInventory()) // do not allow creating in library { LLViewerInventoryCategory *cat = getCategory(); @@ -3886,7 +3736,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items // Not sure what the right thing is to do here. if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) { - if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox + if (!isInboxFolder()) // don't allow creation in inbox { // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) @@ -3948,7 +3798,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items disabled_items.push_back(std::string("Delete System Folder")); } - if (!isOutboxFolder() && !isMarketplaceListingsFolder()) + if (!isMarketplaceListingsFolder()) { items.push_back(std::string("Share")); if (!canShare()) @@ -3994,7 +3844,6 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& if (trash_id == mUUID) return; if (isItemInTrash()) return; if (!isAgentInventory()) return; - if (isOutboxFolder()) return; if (!isItemRemovable()) { @@ -4588,7 +4437,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); const LLUUID from_folder_uuid = inv_item->getParentUUID(); @@ -4598,8 +4446,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); - const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_id); const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id); @@ -4675,9 +4521,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = can_move_to_landmarks(inv_item); } - else if (user_confirm && (move_is_into_outbox || move_is_into_marketplacelistings)) + else if (user_confirm && move_is_into_marketplacelistings) { - const LLViewerInventoryCategory * master_folder = (move_is_into_outbox ? model->getFirstDescendantOf(outbox_id, mUUID) : model->getFirstDescendantOf(marketplacelistings_id, mUUID)); + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); LLViewerInventoryCategory * dest_folder = getCategory(); accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex()); } @@ -4762,19 +4608,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { dropToOutfit(inv_item, move_is_into_current_outfit); } - // MERCHANT OUTBOX folder - // Move the item - else if (move_is_into_outbox) - { - if (move_is_from_outbox) - { - move_item_within_outbox(inv_item, mUUID, LLToolDragAndDrop::getOperationId()); - } - else - { - copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId()); - } - } // MARKETPLACE LISTINGS folder // Move the item else if (move_is_into_marketplacelistings) @@ -4861,7 +4694,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = FALSE; } - else if (move_is_into_outbox || move_is_into_marketplacelistings) + else if (move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -4899,7 +4732,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -4933,7 +4766,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = TRUE; - if (move_is_into_outbox || move_is_into_marketplacelistings) + if (move_is_into_marketplacelistings) { tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); accept = FALSE; @@ -5102,10 +4935,6 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); @@ -5175,11 +5004,7 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - if (isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } - else if (isMarketplaceListingsFolder()) + if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); items.push_back(std::string("Properties")); @@ -5256,11 +5081,7 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items; LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL; - if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } - else if (isMarketplaceListingsFolder()) + if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); items.push_back(std::string("Properties")); @@ -5554,10 +5375,6 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - items.push_back(std::string("Delete")); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); @@ -5846,10 +5663,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - items.push_back(std::string("Delete")); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); @@ -5906,11 +5719,7 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items; LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL; - if(isOutboxFolder()) - { - items.push_back(std::string("Delete")); - } - else if (isMarketplaceListingsFolder()) + if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); items.push_back(std::string("Properties")); @@ -6171,10 +5980,6 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - items.push_back(std::string("Delete")); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); @@ -6399,10 +6204,6 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) - { - items.push_back(std::string("Delete")); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); @@ -6705,10 +6506,6 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Restore Item")); } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); - } else if (isMarketplaceListingsFolder()) { addMarketplaceContextMenuOptions(flags, items, disabled_items); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 7e7cf9c7dd..30419ae930 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -77,7 +77,6 @@ public: bool canShare() const; bool canListOnMarketplace() const; - bool canListOnOutboxNow() const; bool canListOnMarketplaceNow() const; //-------------------------------------------------------------------- @@ -145,9 +144,6 @@ protected: virtual void addDeleteContextMenuOptions(menuentry_vec_t &items, menuentry_vec_t &disabled_items); virtual void addOpenRightClickMenuOption(menuentry_vec_t &items); - virtual void addOutboxContextMenuOptions(U32 flags, - menuentry_vec_t &items, - menuentry_vec_t &disabled_items); virtual void addMarketplaceContextMenuOptions(U32 flags, menuentry_vec_t &items, menuentry_vec_t &disabled_items); @@ -164,9 +160,7 @@ protected: BOOL isCOFFolder() const; // true if COF or descendant of BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox - BOOL isOutboxFolderDirectParent() const; BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder - const LLUUID getOutboxFolder() const; virtual BOOL isItemPermissive() const; static void changeItemParent(LLInventoryModel* model, @@ -182,10 +176,6 @@ protected: BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response); BOOL perform_cutToClipboard(); -public: - BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox - -protected: LLHandle<LLInventoryPanel> mInventoryPanel; LLFolderView* mRoot; const LLUUID mUUID; // item id diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 990343c205..973bf59125 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -782,11 +782,6 @@ void reset_inventory_filter() } } -void open_outbox() -{ - LLFloaterReg::showInstance("outbox"); -} - void open_marketplace_listings() { LLFloaterReg::showInstance("marketplace_listings"); @@ -808,157 +803,6 @@ LLUUID create_folder_for_item(LLInventoryItem* item, const LLUUID& destFolderId) return created_folder_id; } -void move_to_outbox_cb_action(const LLSD& payload) -{ - LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID()); - LLUUID dest_folder_id = payload["dest_folder_id"].asUUID(); - - if (viitem) - { - // when moving item directly into outbox create folder with that name - if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) - { - dest_folder_id = create_folder_for_item(viitem, dest_folder_id); - } - - LLUUID parent = viitem->getParentUUID(); - - gInventory.changeItemParent( - viitem, - dest_folder_id, - false); - - LLUUID top_level_folder = payload["top_level_folder"].asUUID(); - - if (top_level_folder != LLUUID::null) - { - LLViewerInventoryCategory* category; - - while (parent.notNull()) - { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(parent,cat_array,item_array); - - LLUUID next_parent; - - category = gInventory.getCategory(parent); - - if (!category) break; - - next_parent = category->getParentUUID(); - - if (cat_array->empty() && item_array->empty()) - { - gInventory.removeCategory(parent); - } - - if (parent == top_level_folder) - { - break; - } - - parent = next_parent; - } - } - - open_outbox(); - } -} - -void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id) -{ - // Collapse links directly to items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); - if (linked_category != NULL) - { - copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id); - } - else - { - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); - if (linked_item != NULL) - { - inv_item = (LLInventoryItem *) linked_item; - } - - // Check for copy permissions - if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) - { - // when moving item directly into outbox create folder with that name - if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) - { - dest_folder = create_folder_for_item(inv_item, dest_folder); - } - - copy_inventory_item(gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - dest_folder, - inv_item->getName(), - LLPointer<LLInventoryCallback>(NULL)); - - open_outbox(); - } - else - { - LLSD payload; - payload["item_id"] = inv_item->getUUID(); - payload["dest_folder_id"] = dest_folder; - payload["top_level_folder"] = top_level_folder; - payload["operation_id"] = operation_id; - - LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action); - } - } -} - -void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id) -{ - // when moving item directly into outbox create folder with that name - if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) - { - dest_folder = create_folder_for_item(inv_item, dest_folder); - } - - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - - gInventory.changeItemParent( - viewer_inv_item, - dest_folder, - false); -} - -void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id) -{ - LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName()); - gInventory.notifyObservers(); - - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array); - - // copy the vector because otherwise the iterator won't be happy if we delete from it - LLInventoryModel::item_array_t item_array_copy = *item_array; - - for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) - { - LLInventoryItem* item = *iter; - copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id); - } - - LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - - for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) - { - LLViewerInventoryCategory* category = *iter; - copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id); - } - - open_outbox(); -} - ///---------------------------------------------------------------------------- // Marketplace functions // @@ -975,7 +819,7 @@ S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { return -1; } - // If not a descendent of the marketplace listings root, then the nesting depth is -1 by definition + // If not a descendant of the marketplace listings root, then the nesting depth is -1 by definition if (!gInventory.isObjectDescendentOf(cur_uuid, marketplace_listings_uuid)) { return -1; @@ -1605,7 +1449,7 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level) { - llinfos << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << llendl; + LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL; } // Make all relevant business logic checks on the marketplace listings starting with the folder as argument. diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 6ae8fd0f13..8aa8370f91 100755 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -75,10 +75,6 @@ void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* // Generates a string containing the path to the item specified by item_id. void append_path(const LLUUID& id, std::string& path); -void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id); -void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id); -void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id); - typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t; bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 0bad4702e0..53a58aff4c 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -149,8 +149,8 @@ LLInventoryModel::LLInventoryModel() mObservers(), mHttpRequestFG(NULL), mHttpRequestBG(NULL), - mHttpOptions(NULL), - mHttpHeaders(NULL), + mHttpOptions(), + mHttpHeaders(), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpPriorityFG(0), mHttpPriorityBG(0), @@ -179,16 +179,9 @@ void LLInventoryModel::cleanupInventory() mObservers.clear(); // Run down HTTP transport - if (mHttpHeaders) - { - mHttpHeaders->release(); - mHttpHeaders = NULL; - } - if (mHttpOptions) - { - mHttpOptions->release(); - mHttpOptions = NULL; - } + mHttpHeaders.reset(); + mHttpOptions.reset(); + delete mHttpRequestFG; mHttpRequestFG = NULL; delete mHttpRequestBG; @@ -525,59 +518,6 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID()); } -class LLCreateInventoryCategoryResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLCreateInventoryCategoryResponder); -public: - LLCreateInventoryCategoryResponder(LLInventoryModel* model, - boost::optional<inventory_func_type> callback): - mModel(model), - mCallback(callback) - { - } - -protected: - virtual void httpFailure() - { - LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL; - } - - virtual void httpSuccess() - { - //Server has created folder. - const LLSD& content = getContent(); - if (!content.isMap() || !content.has("folder_id")) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLUUID category_id = content["folder_id"].asUUID(); - - LL_DEBUGS(LOG_INV) << ll_pretty_print_sd(content) << LL_ENDL; - // Add the category to the internal representation - LLPointer<LLViewerInventoryCategory> cat = - new LLViewerInventoryCategory( category_id, - content["parent_id"].asUUID(), - (LLFolderType::EType)content["type"].asInteger(), - content["name"].asString(), - gAgent.getID() ); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); - cat->setDescendentCount(0); - LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); - mModel->accountForUpdate(update); - mModel->updateCategory(cat); - - if (mCallback) - { - mCallback.get()(category_id); - } - } - -private: - boost::optional<inventory_func_type> mCallback; - LLInventoryModel* mModel; -}; - // Convenience function to create a new category. You could call // updateCategory() with a newly generated UUID category, but this // version will take care of details like what the name should be @@ -585,7 +525,7 @@ private: LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& pname, - boost::optional<inventory_func_type> callback) + inventory_func_type callback) { LLUUID id; @@ -617,7 +557,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, if ( viewer_region ) url = viewer_region->getCapability("CreateInventoryCategory"); - if (!url.empty() && callback.get_ptr()) + if (!url.empty() && callback) { //Let's use the new capability. @@ -631,11 +571,8 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, request["payload"] = body; LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; - // viewer_region->getCapAPI().post(request); - LLHTTPClient::post( - url, - body, - new LLCreateInventoryCategoryResponder(this, callback) ); + LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro", + boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback)); return LLUUID::null; } @@ -664,6 +601,57 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return id; } +void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("createNewCategoryCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + + httpOpts->setWantHeaders(true); + + LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL; + return; + } + + if (!result.has("folder_id")) + { + LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL; + return; + } + + LLUUID categoryId = result["folder_id"].asUUID(); + + // Add the category to the internal representation + LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(categoryId, + result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), + result["name"].asString(), gAgent.getID()); + + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setDescendentCount(0); + LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); + + accountForUpdate(update); + updateCategory(cat); + + if (callback) + { + callback(categoryId); + } + +} + // This is optimized for the case that we just want to know whether a // category has any immediate children meeting a condition, without // needing to recurse or build up any lists. @@ -2442,11 +2430,11 @@ void LLInventoryModel::initHttpRequest() mHttpRequestFG = new LLCore::HttpRequest; mHttpRequestBG = new LLCore::HttpRequest; - mHttpOptions = new LLCore::HttpOptions; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpOptions->setTransferTimeout(300); mHttpOptions->setUseRetryAfter(true); // mHttpOptions->setTrace(2); // Do tracing of requests - mHttpHeaders = new LLCore::HttpHeaders; + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML); mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index ac336e347c..a74e3b69f4 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -35,7 +35,6 @@ #include "llassettype.h" #include "llfoldertype.h" #include "llframetimer.h" -#include "llcurl.h" #include "lluuid.h" #include "llpermissionsflags.h" #include "llviewerinventory.h" @@ -46,6 +45,8 @@ #include "httpoptions.h" #include "httpheaders.h" #include "httphandler.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLInventoryObserver; class LLInventoryObject; @@ -207,14 +208,14 @@ private: **/ //-------------------------------------------------------------------- - // Descendents + // Descendants //-------------------------------------------------------------------- public: - // Make sure we have the descendents in the structure. Returns true + // Make sure we have the descendants in the structure. Returns true // if a fetch was performed. bool fetchDescendentsOf(const LLUUID& folder_id) const; - // Return the direct descendents of the id provided.Set passed + // Return the direct descendants of the id provided.Set passed // in values to NULL if the call fails. // NOTE: The array provided points straight into the guts of // this object, and should only be used for read operations, since @@ -223,10 +224,10 @@ public: cat_array_t*& categories, item_array_t*& items) const; - // Compute a hash of direct descendent names (for detecting child name changes) + // Compute a hash of direct descendant names (for detecting child name changes) LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; - // Starting with the object specified, add its descendents to the + // Starting with the object specified, add its descendants to the // array provided, but do not add the inventory object specified // by id. There is no guaranteed order. // NOTE: Neither array will be erased before adding objects to it. @@ -340,7 +341,7 @@ public: U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0); // Change an existing item with the matching id or add - // the category. No notifcation will be sent to observers. This + // the category. No notification will be sent to observers. This // method will only generate network traffic if the item had to be // reparented. // NOTE: In usage, you will want to perform cache accounting @@ -378,7 +379,7 @@ public: bool update_parent_version = true, bool do_notify_observers = true); - // Update model after all descendents removed from server. + // Update model after all descendants removed from server. void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); // Update model after an existing item gets updated on server. @@ -409,7 +410,7 @@ public: // Changes items order by insertion of the item identified by src_item_id // before (or after) the item identified by dest_item_id. Both items must exist in items array. // Sorting is stored after method is finished. Only src_item_id is moved before (or after) dest_item_id. - // The parameter "insert_before" controls on which side of dest_item_id src_item_id gets rensinserted. + // The parameter "insert_before" controls on which side of dest_item_id src_item_id gets reinserted. static void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id, @@ -433,7 +434,7 @@ public: LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& name, - boost::optional<inventory_func_type> callback = boost::optional<inventory_func_type>()); + inventory_func_type callback = NULL); protected: // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods @@ -441,6 +442,8 @@ protected: // instance will take over the memory management from there. void addCategory(LLViewerInventoryCategory* category); void addItem(LLViewerInventoryItem* item); + + void createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback); /** Mutators ** ** @@ -567,8 +570,8 @@ private: // Usual plumbing for LLCore:: HTTP operations. LLCore::HttpRequest * mHttpRequestFG; LLCore::HttpRequest * mHttpRequestBG; - LLCore::HttpOptions * mHttpOptions; - LLCore::HttpHeaders * mHttpHeaders; + LLCore::HttpOptions::ptr_t mHttpOptions; + LLCore::HttpHeaders::ptr_t mHttpHeaders; LLCore::HttpRequest::policy_t mHttpPolicyClass; LLCore::HttpRequest::priority_t mHttpPriorityFG; LLCore::HttpRequest::priority_t mHttpPriorityBG; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 5194cba891..02d378bc51 100755 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1437,16 +1437,20 @@ BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) // Open selected items if enter key hit on the inventory panel if (mask == MASK_NONE) { - //Don't allow attaching or opening items from Merchant Outbox - LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem(); - if(folder_item) - { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); - if(bridge && bridge->isOutboxFolder() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY)) - { - return handled; - } - } + +// @TODO$: Rider: This code is dead with Outbox, however should something similar be +// done for VMM? +// +// //Don't allow attaching or opening items from Merchant Outbox +// LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem(); +// if(folder_item) +// { +// LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getViewModelItem(); +// if(bridge && bridge->is() && (bridge->getInventoryType() != LLInventoryType::IT_CATEGORY)) +// { +// return handled; +// } +// } LLInventoryAction::doToSelected(mInventory, mFolderRoot.get(), "open"); handled = TRUE; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index d5bfe1df4a..e8e56ef0cd 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -30,7 +30,6 @@ #include "llagent.h" #include "llbufferstream.h" -#include "llhttpclient.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llnotificationsutil.h" @@ -42,609 +41,112 @@ #include "llviewermedia.h" #include "llviewernetwork.h" #include "llviewerregion.h" - #include "reader.h" // JSON #include "writer.h" // JSON +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h" +#include "llsdutil.h" // // Helpers // -static std::string getMarketplaceDomain() -{ - std::string domain = "secondlife.com"; - - if (!LLGridManager::getInstance()->isInProductionGrid()) - { - const std::string& grid_id = LLGridManager::getInstance()->getGridId(); - const std::string& grid_id_lower = utf8str_tolower(grid_id); - - if (grid_id_lower == "damballah") - { - domain = "secondlife-staging.com"; - } - else - { - domain = llformat("%s.lindenlab.com", grid_id_lower.c_str()); - } - } - - return domain; -} - -static std::string getMarketplaceURL(const std::string& urlStringName) -{ - LLStringUtil::format_map_t domain_arg; - domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain(); - - std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg); - - return marketplace_url; -} - -LLSD getMarketplaceStringSubstitutions() -{ - std::string marketplace_url = getMarketplaceURL("MarketplaceURL"); - std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore"); - std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard"); - std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports"); - std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore"); - - LLSD marketplace_sub_map; - - marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url; - marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create; - marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info; - marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard; - marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports; - - return marketplace_sub_map; -} - -// Get the version folder: if there is only one subfolder, we will use it as a version folder -LLUUID getVersionFolderIfUnique(const LLUUID& folder_id) -{ - LLUUID version_id = LLUUID::null; - LLInventoryModel::cat_array_t* categories; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(folder_id, categories, items); - if (categories->size() == 1) - { - version_id = categories->begin()->get()->getUUID(); - } - else - { - LLNotificationsUtil::add("AlertMerchantListingActivateRequired"); - } - return version_id; -} +namespace { -/////////////////////////////////////////////////////////////////////////////// -// SLM Responders -void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description) -{ - LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL; - if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]")) - { - // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing - LLNotificationsUtil::add("MerchantUnprocessableEntity"); - } - else + static std::string getMarketplaceDomain() { - // Prompt the user with the warning (so they know why things are failing) - LLSD subs; - subs["[ERROR_REASON]"] = reason; - // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though. - subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : ""); - LLNotificationsUtil::add("MerchantTransactionFailed", subs); - } -} -void log_SLM_infos(const std::string& request, U32 status, const std::string& body) -{ - if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) - { - LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL; - } -} -void log_SLM_infos(const std::string& request, const std::string& url, const std::string& body) -{ - if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) - { - LL_INFOS("SLM") << "SLM API : Sending " << request << ". url : " << url << ", body : " << body << LL_ENDL; - } -} + std::string domain = "secondlife.com"; -class LLSLMGetMerchantResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMGetMerchantResponder); -public: - - LLSLMGetMerchantResponder() {} - -protected: - virtual void httpFailure() - { - if (HTTP_NOT_FOUND == getStatus()) - { - log_SLM_infos("Get /merchant", getStatus(), "User is not a merchant"); - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT); - } - else if (HTTP_SERVICE_UNAVAILABLE == getStatus()) + if (!LLGridManager::getInstance()->isInProductionGrid()) { - log_SLM_infos("Get /merchant", getStatus(), "Merchant is not migrated"); - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); - } - else - { - log_SLM_warning("Get /merchant", getStatus(), getReason(), getContent().get("error_code"), getContent().get("error_description")); - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); - } - } - - virtual void httpSuccess() - { - log_SLM_infos("Get /merchant", getStatus(), "User is a merchant"); - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT); - } - -}; + const std::string& grid_id = LLGridManager::getInstance()->getGridId(); + const std::string& grid_id_lower = utf8str_tolower(grid_id); -class LLSLMGetListingsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMGetListingsResponder); -public: - - LLSLMGetListingsResponder(const LLUUID& folder_id) - { - mExpectedFolderId = folder_id; - } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - log_SLM_warning("Get /listings", getStatus(), getReason(), "", body); - LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) - { - log_SLM_warning("Get /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - log_SLM_infos("Get /listings", getStatus(), body); - - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) - { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - bool is_listed = listing["is_listed"].asBool(); - std::string edit_url = listing["edit_url"].asString(); - std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); - std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); - int count = listing["inventory_info"]["count_on_hand"].asInt(); - - LLUUID folder_id(folder_uuid_string); - LLUUID version_id(version_uuid_string); - if (folder_id.notNull()) + if (grid_id_lower == "damballah") { - LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count); + domain = "secondlife-staging.com"; + } + else + { + domain = llformat("%s.lindenlab.com", grid_id_lower.c_str()); } - it++; } - - // Update all folders under the root - LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - } -private: - LLUUID mExpectedFolderId; -}; -class LLSLMCreateListingsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMCreateListingsResponder); -public: - - LLSLMCreateListingsResponder(const LLUUID& folder_id) - { - mExpectedFolderId = folder_id; + return domain; } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + + static std::string getMarketplaceURL(const std::string& urlStringName) { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - log_SLM_warning("Post /listings", getStatus(), getReason(), "", body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) - { - log_SLM_warning("Post /listings", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } + LLStringUtil::format_map_t domain_arg; + domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain(); - log_SLM_infos("Post /listings", getStatus(), body); + std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg); - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) - { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - bool is_listed = listing["is_listed"].asBool(); - std::string edit_url = listing["edit_url"].asString(); - std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); - std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); - int count = listing["inventory_info"]["count_on_hand"].asInt(); - - LLUUID folder_id(folder_uuid_string); - LLUUID version_id(version_uuid_string); - LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count); - update_marketplace_category(folder_id, false); - gInventory.notifyObservers(); - it++; - } + return marketplace_url; } -private: - LLUUID mExpectedFolderId; -}; -class LLSLMGetListingResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMGetListingResponder); -public: - - LLSLMGetListingResponder(const LLUUID& folder_id) - { - mExpectedFolderId = folder_id; - } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + // Get the version folder: if there is only one subfolder, we will use it as a version folder + LLUUID getVersionFolderIfUnique(const LLUUID& folder_id) { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - if (getStatus() == 404) - { - // That listing does not exist -> delete its record from the local SLM data store - LLMarketplaceData::instance().deleteListing(mExpectedFolderId, false); - } - else - { - log_SLM_warning("Get /listing", getStatus(), getReason(), "", body); - } - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) + LLUUID version_id = LLUUID::null; + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, categories, items); + if (categories->size() == 1) { - log_SLM_warning("Get /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; + version_id = categories->begin()->get()->getUUID(); } - - log_SLM_infos("Get /listing", getStatus(), body); - - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) + else { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - bool is_listed = listing["is_listed"].asBool(); - std::string edit_url = listing["edit_url"].asString(); - std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); - std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); - int count = listing["inventory_info"]["count_on_hand"].asInt(); - - LLUUID folder_id(folder_uuid_string); - LLUUID version_id(version_uuid_string); - - // Update that listing - LLMarketplaceData::instance().setListingID(folder_id, listing_id, false); - LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false); - LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false); - LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false); - LLMarketplaceData::instance().setCountOnHand(folder_id,count,false); - update_marketplace_category(folder_id, false); - gInventory.notifyObservers(); - - it++; + LLNotificationsUtil::add("AlertMerchantListingActivateRequired"); } + return version_id; } -private: - LLUUID mExpectedFolderId; -}; -class LLSLMUpdateListingsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMUpdateListingsResponder); -public: - - LLSLMUpdateListingsResponder(const LLUUID& folder_id, bool expected_listed_state, const LLUUID& expected_version_id) + /////////////////////////////////////////////////////////////////////////////// + // SLM Reporters + void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const std::string& description) { - mExpectedFolderId = folder_id; - mExpectedListedState = expected_listed_state; - mExpectedVersionUUID = expected_version_id; - } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - log_SLM_warning("Put /listing", getStatus(), getReason(), "", body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) + LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << description << LL_ENDL; + if ((status == 422) && (description == "[\"You must have an English description to list the product\", \"You must choose a category for your product before it can be listed\", \"Listing could not change state.\", \"Price can't be blank\"]")) { - log_SLM_warning("Put /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; + // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing + LLNotificationsUtil::add("MerchantUnprocessableEntity"); } - - log_SLM_infos("Put /listing", getStatus(), body); - - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) + else { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - bool is_listed = listing["is_listed"].asBool(); - std::string edit_url = listing["edit_url"].asString(); - std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); - std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); - int count = listing["inventory_info"]["count_on_hand"].asInt(); - - LLUUID folder_id(folder_uuid_string); - LLUUID version_id(version_uuid_string); - - // Update that listing - LLMarketplaceData::instance().setListingID(folder_id, listing_id, false); - LLMarketplaceData::instance().setVersionFolderID(folder_id, version_id, false); - LLMarketplaceData::instance().setActivationState(folder_id, is_listed, false); - LLMarketplaceData::instance().setListingURL(folder_id, edit_url, false); - LLMarketplaceData::instance().setCountOnHand(folder_id,count,false); - update_marketplace_category(folder_id, false); - gInventory.notifyObservers(); - - // Show a notification alert if what we got is not what we expected - // (this actually doesn't result in an error status from the SLM API protocol) - if ((mExpectedListedState != is_listed) || (mExpectedVersionUUID != version_id)) - { - LLSD subs; - subs["[URL]"] = edit_url; - LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs); - } - - it++; + // Prompt the user with the warning (so they know why things are failing) + LLSD subs; + subs["[ERROR_REASON]"] = reason; + // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though. + subs["[ERROR_DESCRIPTION]"] = (description.length() <= 512 ? description : ""); + LLNotificationsUtil::add("MerchantTransactionFailed", subs); } } -private: - LLUUID mExpectedFolderId; - bool mExpectedListedState; - LLUUID mExpectedVersionUUID; -}; -class LLSLMAssociateListingsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMAssociateListingsResponder); -public: - - LLSLMAssociateListingsResponder(const LLUUID& folder_id, const LLUUID& source_folder_id) + void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const LLSD& description) { - mExpectedFolderId = folder_id; - mSourceFolderId = source_folder_id; + log_SLM_warning(request, status, reason, code, std::string(ll_pretty_print_sd(description))); } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + + void log_SLM_infos(const std::string& request, U32 status, const std::string& body) { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - LLMarketplaceData::instance().setUpdating(mSourceFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), "", body); - update_marketplace_category(mExpectedFolderId, false); - update_marketplace_category(mSourceFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) - { - log_SLM_warning("Put /associate_inventory", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - update_marketplace_category(mExpectedFolderId, false); - update_marketplace_category(mSourceFolderId, false); - gInventory.notifyObservers(); - return; - } - - log_SLM_infos("Put /associate_inventory", getStatus(), body); - - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) + if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - bool is_listed = listing["is_listed"].asBool(); - std::string edit_url = listing["edit_url"].asString(); - std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); - std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); - int count = listing["inventory_info"]["count_on_hand"].asInt(); - - LLUUID folder_id(folder_uuid_string); - LLUUID version_id(version_uuid_string); - - // Check that the listing ID is not already associated to some other record - LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id); - if (old_listing.notNull()) - { - // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID) - LLMarketplaceData::instance().deleteListing(old_listing); - } - - // Add the new association - LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count); - update_marketplace_category(folder_id, false); - gInventory.notifyObservers(); - - // The stock count needs to be updated with the new local count now - LLMarketplaceData::instance().updateCountOnHand(folder_id,1); - - it++; + LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL; } - - // Always update the source folder so its widget updates - update_marketplace_category(mSourceFolderId, false); } -private: - LLUUID mExpectedFolderId; // This is the folder now associated with the id. - LLUUID mSourceFolderId; // This is the folder initially associated with the id. Can be LLUUI::null -}; -class LLSLMDeleteListingsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSLMDeleteListingsResponder); -public: - - LLSLMDeleteListingsResponder(const LLUUID& folder_id) + void log_SLM_infos(const std::string& request, U32 status, const LLSD& body) { - mExpectedFolderId = folder_id; - } - - virtual void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLMarketplaceData::instance().setUpdating(mExpectedFolderId,false); - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (!isGoodStatus()) - { - log_SLM_warning("Delete /listing", getStatus(), getReason(), "", body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body,root)) - { - log_SLM_warning("Delete /listing", getStatus(), "Json parsing failed", reader.getFormatedErrorMessages(), body); - update_marketplace_category(mExpectedFolderId, false); - gInventory.notifyObservers(); - return; - } - - log_SLM_infos("Delete /listing", getStatus(), body); - - // Extract the info from the Json string - Json::ValueIterator it = root["listings"].begin(); - - while (it != root["listings"].end()) - { - Json::Value listing = *it; - - int listing_id = listing["id"].asInt(); - LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); - LLMarketplaceData::instance().deleteListing(folder_id); - - it++; - } + log_SLM_infos(request, status, std::string(ll_pretty_print_sd(body))); } -private: - LLUUID mExpectedFolderId; -}; -// SLM Responders End -/////////////////////////////////////////////////////////////////////////////// +} + +#if 1 namespace LLMarketplaceImport { // Basic interface for this namespace @@ -669,105 +171,133 @@ namespace LLMarketplaceImport static S32 sImportResultStatus = 0; static LLSD sImportResults = LLSD::emptyMap(); - static LLTimer slmGetTimer; - static LLTimer slmPostTimer; - // Responders - - class LLImportPostResponder : public LLHTTPClient::Responder - { - LOG_CLASS(LLImportPostResponder); - public: - LLImportPostResponder() : LLCurl::Responder() {} - protected: - /* virtual */ void httpCompleted() - { - slmPostTimer.stop(); - - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " - << dumpResponse() << LL_ENDL; - } - - S32 status = getStatus(); - if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || - (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || - // MAINT-2301 : we determined we can safely ignore that error in that context - (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) - { - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL; - } - status = MarketplaceErrorCodes::IMPORT_DONE; - } - - if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) - { - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM POST : Clearing marketplace cookie due to client or server error" << LL_ENDL; - } - sMarketplaceCookie.clear(); - } - - sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); - sImportPostPending = false; - sImportResultStatus = status; - sImportId = getContent(); - } - }; - - class LLImportGetResponder : public LLHTTPClient::Responder - { - LOG_CLASS(LLImportGetResponder); - public: - LLImportGetResponder() : LLCurl::Responder() {} - - protected: - /* virtual */ void httpCompleted() - { - const std::string& set_cookie_string = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); - - if (!set_cookie_string.empty()) - { - sMarketplaceCookie = set_cookie_string; - } - - slmGetTimer.stop(); - - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " - << dumpResponse() << LL_ENDL; - } - - // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions - // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty - S32 status = getStatus(); - if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && - (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && - (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) - { - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL; - } - sMarketplaceCookie.clear(); - } - else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)) + void marketplacePostCoro(std::string url) + { + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplacePostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(true); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + httpHeaders->append(HTTP_OUT_HEADER_CONNECTION, "Keep-Alive"); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + S32 httpCode = status.getType(); + if ((httpCode == MarketplaceErrorCodes::IMPORT_REDIRECT) || + (httpCode == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || + // MAINT-2301 : we determined we can safely ignore that error in that context + (httpCode == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) + { + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - LL_INFOS() << " SLM GET : Got error status = " << status << ", but marketplace cookie not cleared." << LL_ENDL; + LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL; } + httpCode = MarketplaceErrorCodes::IMPORT_DONE; + } - sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); - sImportGetPending = false; - sImportResultStatus = status; - sImportResults = getContent(); - } - }; + if (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) + { + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + LL_INFOS() << " SLM POST clearing marketplace cookie due to client or server error" << LL_ENDL; + } + sMarketplaceCookie.clear(); + } + + sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_DONE); + sImportPostPending = false; + sImportResultStatus = httpCode; + + { + std::stringstream str; + LLSDSerialize::toPrettyXML(result, str); + + LL_INFOS() << "Full results:\n" << str.str() << "\n" << LL_ENDL; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + sImportId = result; + + } + + void marketplaceGetCoro(std::string url, bool buildHeaders) + { + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("marketplaceGetCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(!sMarketplaceCookie.empty()); + + if (buildHeaders) + { + httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sMarketplaceCookie); + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, LLViewerMedia::getCurrentUserAgent()); + } + else + { + httpHeaders = LLViewerMedia::getHttpHeaders(); + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + + if (sMarketplaceCookie.empty() && resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) + { + sMarketplaceCookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asString(); + } + + // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions + // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty + S32 httpCode = status.getType(); + if ((httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && + (httpCode != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && + (httpCode != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) + { + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL; + } + sMarketplaceCookie.clear(); + } + else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)) + { + LL_INFOS() << " SLM GET : Got error status = " << httpCode << ", but marketplace cookie not cleared." << LL_ENDL; + } + + sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_PROCESSING); + sImportGetPending = false; + sImportResultStatus = httpCode; + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + sImportResults = result; + + + } // Basic API @@ -818,20 +348,10 @@ namespace LLMarketplaceImport sImportGetPending = true; std::string url = getInventoryImportURL(); - - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << LL_ENDL; - LLSD headers = LLViewerMedia::getHeaders(); - std::stringstream str; - LLSDSerialize::toPrettyXML(headers, str); - LL_INFOS() << " SLM GET: headers " << LL_ENDL; - LL_INFOS() << str.str() << LL_ENDL; - } - slmGetTimer.start(); - LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders()); - + LLCoros::instance().launch("marketplaceGetCoro", + boost::bind(&marketplaceGetCoro, url, false)); + return true; } @@ -848,26 +368,9 @@ namespace LLMarketplaceImport url += sImportId.asString(); - // Make the headers for the post - LLSD headers = LLSD::emptyMap(); - headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; - headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; - // *TODO: Why are we setting Content-Type for a GET request? - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; - headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); - - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM GET: pollStatus, LLHTTPClient::get, url = " << url << LL_ENDL; - std::stringstream str; - LLSDSerialize::toPrettyXML(headers, str); - LL_INFOS() << " SLM GET: headers " << LL_ENDL; - LL_INFOS() << str.str() << LL_ENDL; - } - - slmGetTimer.start(); - LLHTTPClient::get(url, new LLImportGetResponder(), headers); - + LLCoros::instance().launch("marketplaceGetCoro", + boost::bind(&marketplaceGetCoro, url, true)); + return true; } @@ -886,35 +389,17 @@ namespace LLMarketplaceImport std::string url = getInventoryImportURL(); - // Make the headers for the post - LLSD headers = LLSD::emptyMap(); - headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; - headers[HTTP_OUT_HEADER_CONNECTION] = "Keep-Alive"; - headers[HTTP_OUT_HEADER_COOKIE] = sMarketplaceCookie; - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_XML; - headers[HTTP_OUT_HEADER_USER_AGENT] = LLViewerMedia::getCurrentUserAgent(); - - if (gSavedSettings.getBOOL("InventoryOutboxLogging")) - { - LL_INFOS() << " SLM POST: triggerImport, LLHTTPClient::post, url = " << url << LL_ENDL; - std::stringstream str; - LLSDSerialize::toPrettyXML(headers, str); - LL_INFOS() << " SLM POST: headers " << LL_ENDL; - LL_INFOS() << str.str() << LL_ENDL; - } + LLCoros::instance().launch("marketplacePostCoro", + boost::bind(&marketplacePostCoro, url)); - slmPostTimer.start(); - LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers); - return true; } } - +#endif // // Interface class // - static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 1.0f; //static @@ -1212,6 +697,26 @@ LLMarketplaceData::~LLMarketplaceData() gInventory.removeObserver(mInventoryObserver); } + +LLSD LLMarketplaceData::getMarketplaceStringSubstitutions() +{ + std::string marketplace_url = getMarketplaceURL("MarketplaceURL"); + std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore"); + std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard"); + std::string marketplace_url_imports = getMarketplaceURL("MarketplaceURL_Imports"); + std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore"); + + LLSD marketplace_sub_map; + + marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url; + marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create; + marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info; + marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard; + marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports; + + return marketplace_sub_map; +} + void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& cb) { if (mStatusUpdatedSignal == NULL) @@ -1227,15 +732,60 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& } else { - // Initiate SLM connection and set responder - std::string url = getSLMConnectURL("/merchant"); - if (url != "") + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING; + + LLCoros::instance().launch("getMerchantStatus", + boost::bind(&LLMarketplaceData::getMerchantStatusCoro, this)); + } +} + +void LLMarketplaceData::getMerchantStatusCoro() +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setFollowRedirects(true); + + std::string url = getSLMConnectURL("/merchant"); + if (url.empty()) + { + LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + S32 httpCode = status.getType(); + + if (httpCode == HTTP_NOT_FOUND) + { + log_SLM_infos("Get /merchant", httpCode, std::string("User is not a merchant")); + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT); + } + else if (httpCode == HTTP_SERVICE_UNAVAILABLE) + { + log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated")); + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); + } + else { - mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING; - log_SLM_infos("LLHTTPClient::get", url, ""); - LLHTTPClient::get(url, new LLSLMGetMerchantResponder(), LLSD()); + std::string err_code = result["error_code"].asString(); + std::string err_description = result["error_description"].asString(); + log_SLM_warning("Get /merchant", httpCode, status.toString(), err_code, err_description); + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); } + return; } + + log_SLM_infos("Get /merchant", status.getType(), std::string("User is a merchant")); + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT); } void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb) @@ -1250,151 +800,434 @@ void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot // Get/Post/Put requests to the SLM Server using the SLM API void LLMarketplaceData::getSLMListings() { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - // Send request + const LLUUID marketplaceFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + setUpdating(marketplaceFolderId, true); + + LLCoros::instance().launch("getSLMListings", + boost::bind(&LLMarketplaceData::getSLMListingsCoro, this, marketplaceFolderId)); +} + +void LLMarketplaceData::getSLMListingsCoro(LLUUID folderId) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); + std::string url = getSLMConnectURL("/listings"); - log_SLM_infos("LLHTTPClient::get", url, ""); - const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - setUpdating(marketplacelistings_id,true); - LLHTTPClient::get(url, new LLSLMGetListingsResponder(marketplacelistings_id), headers); + + LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders); + + setUpdating(folderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + log_SLM_warning("Get /listings", status.getType(), status.toString(), "", result); + setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result); + + // Extract the info from the results + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int listingId = listing["id"].asInteger(); + bool isListed = listing["is_listed"].asBoolean(); + std::string editUrl = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + if (folderUuid.notNull()) + { + addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count); + } + } + + // Update all folders under the root + setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); } -void LLMarketplaceData::getSLMListing(S32 listing_id) +void LLMarketplaceData::getSLMListing(S32 listingId) { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - // Send request - std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id); - log_SLM_infos("LLHTTPClient::get", url, ""); - LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); - setUpdating(folder_id,true); - LLHTTPClient::get(url, new LLSLMGetListingResponder(folder_id), headers); + LLUUID folderId = getListingFolder(listingId); + setUpdating(folderId, true); + + LLCoros::instance().launch("getSingleListingCoro", + boost::bind(&LLMarketplaceData::getSingleListingCoro, this, listingId, folderId)); +} + +void LLMarketplaceData::getSingleListingCoro(S32 listingId, LLUUID folderId) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); + + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + + LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, url, httpHeaders); + + setUpdating(folderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if (status.getType() == HTTP_NOT_FOUND) + { + // That listing does not exist -> delete its record from the local SLM data store + deleteListing(folderId, false); + } + else + { + log_SLM_warning("Get /listing", status.getType(), status.toString(), "", result); + } + + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Get /listings", static_cast<U32>(status.getType()), result); + + + // Extract the info from the results + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int resListingId = listing["id"].asInteger(); + bool isListed = listing["is_listed"].asBoolean(); + std::string editUrl = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Update that listing + setListingID(folderUuid, resListingId, false); + setVersionFolderID(folderUuid, versionUuid, false); + setActivationState(folderUuid, isListed, false); + setListingURL(folderUuid, editUrl, false); + setCountOnHand(folderUuid, count, false); + update_marketplace_category(folderUuid, false); + gInventory.notifyObservers(); + } } void LLMarketplaceData::createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count) { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - // Build the json message - Json::Value root; - Json::FastWriter writer; - - LLViewerInventoryCategory* category = gInventory.getCategory(folder_id); - root["listing"]["name"] = category->getName(); - root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString(); - root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString(); - root["listing"]["inventory_info"]["count_on_hand"] = count; - - std::string json_str = writer.write(root); - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = json_str.size(); - U8 *data = new U8[size]; - memcpy(data, (U8*)(json_str.c_str()), size); - - // Send request - std::string url = getSLMConnectURL("/listings"); - log_SLM_infos("LLHTTPClient::postRaw", url, json_str); - setUpdating(folder_id,true); - LLHTTPClient::postRaw(url, data, size, new LLSLMCreateListingsResponder(folder_id), headers); + setUpdating(folder_id, true); + LLCoros::instance().launch("createSLMListingCoro", + boost::bind(&LLMarketplaceData::createSLMListingCoro, this, folder_id, version_id, count)); } -void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count) +void LLMarketplaceData::createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count) { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); - Json::Value root; - Json::FastWriter writer; + LLViewerInventoryCategory* category = gInventory.getCategory(folderId); + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + invInfo["count_on_hand"] = count; + LLSD listing; + listing["name"] = category->getName(); + listing["inventory_info"] = invInfo; + LLSD postData; + postData["listing"] = listing; - // Note : auto unlist if the count is 0 (out of stock) - if (is_listed && (count == 0)) + std::string url = getSLMConnectURL("/listings"); + + LLSD result = httpAdapter->postJsonAndSuspend(httpRequest, url, postData, httpHeaders); + + setUpdating(folderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) { - is_listed = false; - LLNotificationsUtil::add("AlertMerchantStockFolderEmpty"); + log_SLM_warning("Post /listings", status.getType(), status.toString(), "", result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; } - // Note : we're assuming that sending unchanged info won't break anything server side... - root["listing"]["id"] = listing_id; - root["listing"]["is_listed"] = is_listed; - root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString(); - root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString(); - root["listing"]["inventory_info"]["count_on_hand"] = count; - - std::string json_str = writer.write(root); - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = json_str.size(); - U8 *data = new U8[size]; - memcpy(data, (U8*)(json_str.c_str()), size); + log_SLM_infos("Post /listings", status.getType(), result); + + // Extract the info from the results + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int listingId = listing["id"].asInteger(); + bool isListed = listing["is_listed"].asBoolean(); + std::string editUrl = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count); + update_marketplace_category(folderUuid, false); + gInventory.notifyObservers(); + } + +} + +void LLMarketplaceData::updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count) +{ + setUpdating(folder_id, true); + LLCoros::instance().launch("updateSLMListingCoro", + boost::bind(&LLMarketplaceData::updateSLMListingCoro, this, folder_id, listing_id, version_id, is_listed, count)); +} + +void LLMarketplaceData::updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); - // Send request - std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id); - log_SLM_infos("LLHTTPClient::putRaw", url, json_str); - setUpdating(folder_id,true); - LLHTTPClient::putRaw(url, data, size, new LLSLMUpdateListingsResponder(folder_id, is_listed, version_id), headers); + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + invInfo["count_on_hand"] = count; + LLSD listing; + listing["inventory_info"] = invInfo; + listing["id"] = listingId; + listing["is_listed"] = isListed; + LLSD postData; + postData["listing"] = listing; + + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders); + + setUpdating(folderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + log_SLM_warning("Put /listing", status.getType(), status.toString(), "", result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Put /listing", status.getType(), result); + + // Extract the info from the Json string + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int listing_id = listing["id"].asInteger(); + bool is_listed = listing["is_listed"].asBoolean(); + std::string edit_url = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int onHand = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Update that listing + setListingID(folderUuid, listing_id, false); + setVersionFolderID(folderUuid, versionUuid, false); + setActivationState(folderUuid, is_listed, false); + setListingURL(folderUuid, edit_url, false); + setCountOnHand(folderUuid, onHand, false); + update_marketplace_category(folderUuid, false); + gInventory.notifyObservers(); + + // Show a notification alert if what we got is not what we expected + // (this actually doesn't result in an error status from the SLM API protocol) + if ((isListed != is_listed) || (versionId != versionUuid)) + { + LLSD subs; + subs["[URL]"] = edit_url; + LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs); + } + } + } void LLMarketplaceData::associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id) { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - Json::Value root; - Json::FastWriter writer; - - // Note : we're assuming that sending unchanged info won't break anything server side... - root["listing"]["id"] = listing_id; - root["listing"]["inventory_info"]["listing_folder_id"] = folder_id.asString(); - root["listing"]["inventory_info"]["version_folder_id"] = version_id.asString(); - - std::string json_str = writer.write(root); - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = json_str.size(); - U8 *data = new U8[size]; - memcpy(data, (U8*)(json_str.c_str()), size); - - // Send request - std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d",listing_id); - log_SLM_infos("LLHTTPClient::putRaw", url, json_str); - setUpdating(folder_id,true); - setUpdating(source_folder_id,true); - LLHTTPClient::putRaw(url, data, size, new LLSLMAssociateListingsResponder(folder_id,source_folder_id), headers); + setUpdating(folder_id, true); + setUpdating(source_folder_id, true); + LLCoros::instance().launch("associateSLMListingCoro", + boost::bind(&LLMarketplaceData::associateSLMListingCoro, this, folder_id, listing_id, version_id, source_folder_id)); } -void LLMarketplaceData::deleteSLMListing(S32 listing_id) +void LLMarketplaceData::associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId) { - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "application/json"; - headers["Content-Type"] = "application/json"; - - // Send request - std::string url = getSLMConnectURL("/listing/") + llformat("%d",listing_id); - log_SLM_infos("LLHTTPClient::del", url, ""); - LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); - setUpdating(folder_id,true); - LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folder_id), headers); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); + + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + LLSD listing; + listing["id"] = listingId; + listing["inventory_info"] = invInfo; + LLSD postData; + postData["listing"] = listing; + + // Send request + std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d", listingId); + + LLSD result = httpAdapter->putJsonAndSuspend(httpRequest, url, postData, httpHeaders); + + setUpdating(folderId, false); + setUpdating(sourceFolderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + log_SLM_warning("Put /associate_inventory", status.getType(), status.toString(), "", result); + update_marketplace_category(folderId, false); + update_marketplace_category(sourceFolderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Put /associate_inventory", status.getType(), result); + + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int listing_id = listing["id"].asInteger(); + bool is_listed = listing["is_listed"].asBoolean(); + std::string edit_url = listing["edit_url"].asString(); + LLUUID folder_uuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID version_uuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Check that the listing ID is not already associated to some other record + LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id); + if (old_listing.notNull()) + { + // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID) + deleteListing(old_listing); + } + + // Add the new association + addListing(folder_uuid, listing_id, version_uuid, is_listed, edit_url, count); + update_marketplace_category(folder_uuid, false); + gInventory.notifyObservers(); + + // The stock count needs to be updated with the new local count now + updateCountOnHand(folder_uuid, 1); + } + + // Always update the source folder so its widget updates + update_marketplace_category(sourceFolderId, false); +} + +void LLMarketplaceData::deleteSLMListing(S32 listingId) +{ + LLCoros::instance().launch("deleteSLMListingCoro", + boost::bind(&LLMarketplaceData::deleteSLMListingCoro, this, listingId)); +} + +void LLMarketplaceData::deleteSLMListingCoro(S32 listingId) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpHeaders->append("Accept", "application/json"); + httpHeaders->append("Content-Type", "application/json"); + + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + LLUUID folderId = getListingFolder(listingId); + + setUpdating(folderId, true); + + LLSD result = httpAdapter->deleteJsonAndSuspend(httpRequest, url, httpHeaders); + + setUpdating(folderId, false); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + log_SLM_warning("Delete /listing", status.getType(), status.toString(), "", result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Delete /listing", status.getType(), result); + + for (LLSD::array_iterator it = result["listings"].beginArray(); + it != result["listings"].endArray(); ++it) + { + LLSD listing = *it; + + int listing_id = listing["id"].asInteger(); + LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); + deleteListing(folder_id); + } + } std::string LLMarketplaceData::getSLMConnectURL(const std::string& route) { - std::string url(""); + std::string url; LLViewerRegion *regionp = gAgent.getRegion(); if (regionp) { // Get DirectDelivery cap url = regionp->getCapability("DirectDelivery"); - if (url != "") + if (!url.empty()) { url += route; } @@ -1983,5 +1816,3 @@ bool LLMarketplaceData::setListingURL(const LLUUID& folder_id, const std::string return true; } - - diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index f8e7ed4364..9d795c6ced 100755 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -37,8 +37,6 @@ #include "llstring.h" -LLSD getMarketplaceStringSubstitutions(); - namespace MarketplaceErrorCodes { @@ -183,6 +181,8 @@ class LLSLMDeleteListingsResponder; class LLMarketplaceData : public LLSingleton<LLMarketplaceData> { + friend class LLSingleton < LLMarketplaceData > ; + public: friend class LLSLMGetMerchantResponder; friend class LLSLMGetListingsResponder; @@ -192,9 +192,8 @@ public: friend class LLSLMAssociateListingsResponder; friend class LLSLMDeleteListingsResponder; - LLMarketplaceData(); - virtual ~LLMarketplaceData(); - + static LLSD getMarketplaceStringSubstitutions(); + // Public SLM API : Initialization and status typedef boost::signals2::signal<void ()> status_updated_signal_t; void initializeSLM(const status_updated_signal_t::slot_type& cb); @@ -241,8 +240,11 @@ public: // Used to decide when to run a validation on listing folders void setValidationWaiting(const LLUUID& folder_id, S32 count); void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1); - + private: + LLMarketplaceData(); + virtual ~LLMarketplaceData(); + // Modify Marketplace data set : each method returns true if the function succeeds, false if error // Used internally only by SLM Responders when data are received from the SLM Server bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count); @@ -261,6 +263,14 @@ private: void deleteSLMListing(S32 listing_id); std::string getSLMConnectURL(const std::string& route); + void getMerchantStatusCoro(); + void getSLMListingsCoro(LLUUID folderId); + void getSingleListingCoro(S32 listingId, LLUUID folderId); + void createSLMListingCoro(LLUUID folderId, LLUUID versionId, S32 count); + void updateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, bool isListed, S32 count); + void associateSLMListingCoro(LLUUID folderId, S32 listingId, LLUUID versionId, LLUUID sourceFolderId); + void deleteSLMListingCoro(S32 listingId); + // Handling Marketplace connection and inventory connection U32 mMarketPlaceStatus; status_updated_signal_t* mStatusUpdatedSignal; diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index a1f6a01aa0..1045def72e 100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -36,6 +36,9 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llworld.h" +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "llcorehttputil.h" /** * Materials cap parameters @@ -59,56 +62,51 @@ #define MATERIALS_PUT_THROTTLE_SECS 1.f #define MATERIALS_PUT_MAX_ENTRIES 50 -/** - * LLMaterialsResponder helper class - */ -class LLMaterialsResponder : public LLHTTPClient::Responder + +class LLMaterialHttpHandler : public LLHttpSDHandler { -public: - typedef boost::function<void (bool, const LLSD&)> CallbackFunction; +public: + typedef boost::function<void(bool, const LLSD&)> CallbackFunction; + typedef boost::shared_ptr<LLMaterialHttpHandler> ptr_t; + + LLMaterialHttpHandler(const std::string& method, CallbackFunction cback); - LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback); - virtual ~LLMaterialsResponder(); + virtual ~LLMaterialHttpHandler(); - virtual void httpSuccess(); - virtual void httpFailure(); +protected: + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); private: std::string mMethod; - std::string mCapabilityURL; CallbackFunction mCallback; }; -LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback) - : LLHTTPClient::Responder() - , mMethod(pMethod) - , mCapabilityURL(pCapabilityURL) - , mCallback(pCallback) +LLMaterialHttpHandler::LLMaterialHttpHandler(const std::string& method, CallbackFunction cback): + LLHttpSDHandler(), + mMethod(method), + mCallback(cback) { + } -LLMaterialsResponder::~LLMaterialsResponder() +LLMaterialHttpHandler::~LLMaterialHttpHandler() { } -void LLMaterialsResponder::httpSuccess() +void LLMaterialHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) { - const LLSD& pContent = getContent(); - LL_DEBUGS("Materials") << LL_ENDL; - mCallback(true, pContent); + mCallback(true, content); } -void LLMaterialsResponder::httpFailure() +void LLMaterialHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) { - U32 pStatus = (U32) getStatus(); - const std::string& pReason = getReason(); - LL_WARNS("Materials") << "\n--------------------------------------------------------------------------\n" - << mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME - << "'\n with url '" << mCapabilityURL << "' because " << pReason + << mMethod << " Error[" << status.toULong() << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME + << "'\n with url '" << response->getRequestURL() << "' because " << status.toString() << "\n--------------------------------------------------------------------------" << LL_ENDL; @@ -116,12 +114,35 @@ void LLMaterialsResponder::httpFailure() mCallback(false, emptyResult); } + + /** * LLMaterialMgr class */ - -LLMaterialMgr::LLMaterialMgr() +LLMaterialMgr::LLMaterialMgr(): + mGetQueue(), + mGetPending(), + mGetCallbacks(), + mGetTECallbacks(), + mGetAllQueue(), + mGetAllRequested(), + mGetAllPending(), + mGetAllCallbacks(), + mPutQueue(), + mMaterials(), + mHttpRequest(), + mHttpHeaders(), + mHttpOptions(), + mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mHttpPriority(0) { + LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + + mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); + mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_MATERIALS); + mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL))); gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL); LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1)); @@ -554,6 +575,8 @@ void LLMaterialMgr::onIdle(void*) { instancep->processPutQueue(); } + + instancep->mHttpRequest->update(0L); } void LLMaterialMgr::processGetQueue() @@ -629,10 +652,26 @@ void LLMaterialMgr::processGetQueue() LLSD postData = LLSD::emptyMap(); postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary; - LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id)); - LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials." + LLMaterialHttpHandler * handler = + new LLMaterialHttpHandler("POST", + boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id) + ); + + LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials." << "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL; - LLHTTPClient::post(capURL, postData, materialsResponder); + + LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, + mHttpPolicy, mHttpPriority, capURL, + postData, mHttpOptions, mHttpHeaders, handler); + + if (handle == LLCORE_HTTP_HANDLE_INVALID) + { + delete handler; + LLCore::HttpStatus status = mHttpRequest->getStatus(); + LL_ERRS("Meterials") << "Failed to execute material POST. Status = " << + status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; + } + regionp->resetMaterialsCapThrottle(); } } @@ -667,8 +706,22 @@ void LLMaterialMgr::processGetAllQueue() } LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL; - LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)); - LLHTTPClient::get(capURL, materialsResponder); + LLMaterialHttpHandler *handler = + new LLMaterialHttpHandler("GET", + boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion) + ); + + LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL, + mHttpOptions, mHttpHeaders, handler); + + if (handle == LLCORE_HTTP_HANDLE_INVALID) + { + delete handler; + LLCore::HttpStatus status = mHttpRequest->getStatus(); + LL_ERRS("Meterials") << "Failed to execute material GET. Status = " << + status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; + } + regionp->resetMaterialsCapThrottle(); mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds())); mGetAllQueue.erase(itRegion); // Invalidates region_id @@ -755,8 +808,24 @@ void LLMaterialMgr::processPutQueue() putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary; LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL; - LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)); - LLHTTPClient::put(capURL, putData, materialsResponder); + + LLMaterialHttpHandler * handler = + new LLMaterialHttpHandler("PUT", + boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2) + ); + + LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD( + mHttpRequest, mHttpPolicy, mHttpPriority, capURL, + putData, mHttpOptions, mHttpHeaders, handler); + + if (handle == LLCORE_HTTP_HANDLE_INVALID) + { + delete handler; + LLCore::HttpStatus status = mHttpRequest->getStatus(); + LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " << + status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; + } + regionp->resetMaterialsCapThrottle(); } else diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index e83f1f4e01..ef202d24ba 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -30,6 +30,9 @@ #include "llmaterial.h" #include "llmaterialid.h" #include "llsingleton.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h" class LLViewerRegion; @@ -56,7 +59,7 @@ public: void put(const LLUUID& object_id, const U8 te, const LLMaterial& material); void remove(const LLUUID& object_id, const U8 te); -protected: +private: void clearGetQueues(const LLUUID& region_id); bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const; bool isGetAllPending(const LLUUID& region_id) const; @@ -72,16 +75,7 @@ protected: void onPutResponse(bool success, const LLSD& content); void onRegionRemoved(LLViewerRegion* regionp); -protected: - typedef std::set<LLMaterialID> material_queue_t; - typedef std::map<LLUUID, material_queue_t> get_queue_t; - get_queue_t mGetQueue; - typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; - typedef std::map<const pending_material_t, F64> get_pending_map_t; - get_pending_map_t mGetPending; - typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; - get_callback_map_t mGetCallbacks; - +private: // struct for TE-specific material ID query class TEMaterialPair { @@ -108,22 +102,37 @@ protected: bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; } }; - typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t; - get_callback_te_map_t mGetTECallbacks; + typedef std::set<LLMaterialID> material_queue_t; + typedef std::map<LLUUID, material_queue_t> get_queue_t; + typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; + typedef std::map<const pending_material_t, F64> get_pending_map_t; + typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; + + typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t; typedef std::set<LLUUID> getall_queue_t; - getall_queue_t mGetAllQueue; - getall_queue_t mGetAllRequested; typedef std::map<LLUUID, F64> getall_pending_map_t; - getall_pending_map_t mGetAllPending; typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t; - getall_callback_map_t mGetAllCallbacks; - typedef std::map<U8, LLMaterial> facematerial_map_t; typedef std::map<LLUUID, facematerial_map_t> put_queue_t; - put_queue_t mPutQueue; - material_map_t mMaterials; + get_queue_t mGetQueue; + get_pending_map_t mGetPending; + get_callback_map_t mGetCallbacks; + + get_callback_te_map_t mGetTECallbacks; + getall_queue_t mGetAllQueue; + getall_queue_t mGetAllRequested; + getall_pending_map_t mGetAllPending; + getall_callback_map_t mGetAllCallbacks; + put_queue_t mPutQueue; + material_map_t mMaterials; + + 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; U32 getMaxEntries(const LLViewerRegion* regionp); }; diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index 2fb9e60b29..bfd0700a2f 100755 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -33,6 +33,7 @@ #pragma warning (disable:4702) #endif +#include <algorithm> #include <boost/lexical_cast.hpp> #include "llhttpconstants.h" @@ -40,6 +41,7 @@ #include "llmediaentry.h" #include "lltextureentry.h" #include "llviewerregion.h" +#include "llcorehttputil.h" // // When making a request @@ -91,52 +93,74 @@ const U32 LLMediaDataClient::MAX_ROUND_ROBIN_QUEUE_SIZE = 10000; std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q); std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); -template <typename T> -typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type) + +//========================================================================= +/// Uniary Predicate for matching requests in collections by either the request +/// or by UUID +/// +class PredicateMatchRequest { - for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) - { - if(request->isMatch(*iter, match_type)) - { - return iter; - } - } - - return c.end(); +public: + PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY); + PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType = LLMediaDataClient::Request::ANY); + + PredicateMatchRequest(const PredicateMatchRequest &other); + + bool operator()(const LLMediaDataClient::Request::ptr_t &test) const; + +private: + LLMediaDataClient::Request::ptr_t mRequest; + LLMediaDataClient::Request::Type mMatchType; + LLUUID mId; +}; + + +PredicateMatchRequest::PredicateMatchRequest(const LLMediaDataClient::Request::ptr_t &request, LLMediaDataClient::Request::Type matchType) : + mRequest(request), + mMatchType(matchType), + mId() +{} + +PredicateMatchRequest::PredicateMatchRequest(const LLUUID &id, LLMediaDataClient::Request::Type matchType) : + mRequest(), + mMatchType(matchType), + mId(id) +{} + +PredicateMatchRequest::PredicateMatchRequest(const PredicateMatchRequest &other) +{ + mRequest = other.mRequest; + mMatchType = other.mMatchType; + mId = other.mId; } -template <typename T> -typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +bool PredicateMatchRequest::operator()(const LLMediaDataClient::Request::ptr_t &test) const { - for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) - { - if(((*iter)->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == (*iter)->getType()))) - { - return iter; - } - } - - return c.end(); + if (mRequest) + return (mRequest->isMatch(test, mMatchType)); + else if (!mId.isNull()) + return ((test->getID() == mId) && ((mMatchType == LLMediaDataClient::Request::ANY) || (mMatchType == test->getType()))); + return false; } -// NOTE: remove_matching_requests will not work correctly for containers where deleting an element may invalidate iterators -// to other elements in the container (such as std::vector). -// If the implementation is changed to use a container with this property, this will need to be revisited. +//========================================================================= +/// template <typename T> -void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +void mark_dead_and_remove_if(T &c, const PredicateMatchRequest &matchPred) { - for(typename T::iterator iter = c.begin(); iter != c.end();) - { - typename T::value_type i = *iter; - typename T::iterator next = iter; - next++; - if((i->getID() == id) && ((match_type == LLMediaDataClient::Request::ANY) || (match_type == i->getType()))) - { - i->markDead(); - c.erase(iter); - } - iter = next; - } + for (typename T::iterator it = c.begin(); it != c.end();) + { + if (matchPred(*it)) + { + (*it)->markDead(); + // *TDOO: When C++11 is in change the following line to: it = c.erase(it); + c.erase(it++); + } + else + { + ++it; + } + } } ////////////////////////////////////////////////////////////////////////////////////// @@ -145,18 +169,20 @@ void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request // ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, - F32 retry_timer_delay, - U32 max_retries, - U32 max_sorted_queue_size, - U32 max_round_robin_queue_size) - : mQueueTimerDelay(queue_timer_delay), - mRetryTimerDelay(retry_timer_delay), - mMaxNumRetries(max_retries), - mMaxSortedQueueSize(max_sorted_queue_size), - mMaxRoundRobinQueueSize(max_round_robin_queue_size), - mQueueTimerIsRunning(false) +LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay, F32 retry_timer_delay, + U32 max_retries, U32 max_sorted_queue_size, U32 max_round_robin_queue_size): + mQueueTimerDelay(queue_timer_delay), + mRetryTimerDelay(retry_timer_delay), + mMaxNumRetries(max_retries), + mMaxSortedQueueSize(max_sorted_queue_size), + mMaxRoundRobinQueueSize(max_round_robin_queue_size), + mQueueTimerIsRunning(false), + mHttpRequest(new LLCore::HttpRequest()), + mHttpHeaders(new LLCore::HttpHeaders()), + mHttpOpts(new LLCore::HttpOptions()), + mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID) { + // *TODO: Look up real Policy ID } LLMediaDataClient::~LLMediaDataClient() @@ -171,20 +197,23 @@ bool LLMediaDataClient::isEmpty() const bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) { - if(find_matching_request(mQueue, object->getID(), LLMediaDataClient::Request::ANY) != mQueue.end()) - return true; - - if(find_matching_request(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY) != mUnQueuedRequests.end()) - return true; - + PredicateMatchRequest upred(object->getID()); + + if (std::find_if(mQueue.begin(), mQueue.end(), upred) != mQueue.end()) + return true; + if (std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred) != mUnQueuedRequests.end()) + return true; + return false; } void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; - remove_matching_requests(mQueue, object->getID(), LLMediaDataClient::Request::ANY); - remove_matching_requests(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY); + PredicateMatchRequest upred(object->getID()); + + mark_dead_and_remove_if(mQueue, upred); + mark_dead_and_remove_if(mUnQueuedRequests, upred); } void LLMediaDataClient::startQueueTimer() @@ -207,23 +236,24 @@ void LLMediaDataClient::stopQueueTimer() bool LLMediaDataClient::processQueueTimer() { - if(isEmpty()) + if (isDoneProcessing()) return true; LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() started, queue size is: " << mQueue.size() << LL_ENDL; LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() started, SORTED queue is: " << mQueue << LL_ENDL; serviceQueue(); - + serviceHttp(); + LL_DEBUGS("LLMediaDataClient") << "QueueTimer::tick() finished, queue size is: " << mQueue.size() << LL_ENDL; LL_DEBUGS("LLMediaDataClientQueue") << "QueueTimer::tick() finished, SORTED queue is: " << mQueue << LL_ENDL; - return isEmpty(); + return isDoneProcessing(); } -LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue() +LLMediaDataClient::Request::ptr_t LLMediaDataClient::dequeue() { - request_ptr_t request; + Request::ptr_t request; request_queue_t *queue_p = getQueue(); if (queue_p->empty()) @@ -242,20 +272,20 @@ LLMediaDataClient::request_ptr_t LLMediaDataClient::dequeue() else { // Don't return this request -- it's not ready to be serviced. - request = NULL; + request.reset(); } } return request; } -void LLMediaDataClient::pushBack(request_ptr_t request) +void LLMediaDataClient::pushBack(Request::ptr_t request) { request_queue_t *queue_p = getQueue(); queue_p->push_front(request); } -void LLMediaDataClient::trackRequest(request_ptr_t request) +void LLMediaDataClient::trackRequest(Request::ptr_t request) { request_set_t::iterator iter = mUnQueuedRequests.find(request); @@ -269,7 +299,7 @@ void LLMediaDataClient::trackRequest(request_ptr_t request) } } -void LLMediaDataClient::stopTrackingRequest(request_ptr_t request) +void LLMediaDataClient::stopTrackingRequest(Request::ptr_t request) { request_set_t::iterator iter = mUnQueuedRequests.find(request); @@ -283,16 +313,22 @@ void LLMediaDataClient::stopTrackingRequest(request_ptr_t request) } } +bool LLMediaDataClient::isDoneProcessing() const +{ + return (isEmpty() && mUnQueuedRequests.empty()); +} + + void LLMediaDataClient::serviceQueue() { // Peel one off of the items from the queue and execute it - request_ptr_t request; + Request::ptr_t request; do { request = dequeue(); - if(request.isNull()) + if(!request) { // Queue is empty. return; @@ -317,7 +353,18 @@ void LLMediaDataClient::serviceQueue() trackRequest(request); // and make the post - LLHTTPClient::post(url, sd_payload, request->createResponder()); + LLHttpSDHandler *handler = request->createHandler(); + LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, mHttpPolicy, 0, + url, sd_payload, mHttpOpts, mHttpHeaders, handler); + + if (handle == LLCORE_HTTP_HANDLE_INVALID) + { + // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers. Requires change in LLCore::HTTP + delete handler; + LLCore::HttpStatus status = mHttpRequest->getStatus(); + LL_WARNS("LLMediaDataClient") << "'" << url << "' request POST failed. Reason " + << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; + } } else { @@ -332,13 +379,17 @@ void LLMediaDataClient::serviceQueue() } else { - // This request has exceeded its maxumim retry count. It will be dropped. + // This request has exceeded its maximum retry count. It will be dropped. LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << mMaxNumRetries << " tries, dropping request." << LL_ENDL; } } } +void LLMediaDataClient::serviceHttp() +{ + mHttpRequest->update(0); +} // dump the queue std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue_t &q) @@ -395,7 +446,7 @@ BOOL LLMediaDataClient::QueueTimer::tick() // ////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::RetryTimer::RetryTimer(F32 time, request_ptr_t request) +LLMediaDataClient::RetryTimer::RetryTimer(F32 time, Request::ptr_t request) : LLEventTimer(time), mRequest(request) { mRequest->startTracking(); @@ -417,7 +468,7 @@ BOOL LLMediaDataClient::RetryTimer::tick() } // Release the ref to the request. - mRequest = NULL; + mRequest.reset(); // Don't fire again return TRUE; @@ -490,7 +541,7 @@ void LLMediaDataClient::Request::reEnqueue() { if(mMDC) { - mMDC->enqueue(this); + mMDC->enqueue(shared_from_this()); } } @@ -533,13 +584,13 @@ bool LLMediaDataClient::Request::isDead() void LLMediaDataClient::Request::startTracking() { if(mMDC) - mMDC->trackRequest(this); + mMDC->trackRequest(shared_from_this()); } void LLMediaDataClient::Request::stopTracking() { if(mMDC) - mMDC->stopTrackingRequest(this); + mMDC->stopTrackingRequest(shared_from_this()); } std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) @@ -551,79 +602,61 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r) << " #retries=" << r.getRetryCount(); return s; } - -////////////////////////////////////////////////////////////////////////////////////// -// -// LLMediaDataClient::Responder -// -////////////////////////////////////////////////////////////////////////////////////// -LLMediaDataClient::Responder::Responder(const request_ptr_t &request) -: mRequest(request) +//======================================================================== + +LLMediaDataClient::Handler::Handler(const Request::ptr_t &request): + mRequest(request) { } -/*virtual*/ -void LLMediaDataClient::Responder::httpFailure() + +void LLMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) { - mRequest->stopTracking(); + mRequest->stopTracking(); - if(mRequest->isDead()) - { - LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; - return; - } - - if (getStatus() == HTTP_SERVICE_UNAVAILABLE) - { - F32 retry_timeout; -#if 0 - // *TODO: Honor server Retry-After header. - if (!hasResponseHeader(HTTP_IN_HEADER_RETRY_AFTER) - || !getSecondsUntilRetryAfter(getResponseHeader(HTTP_IN_HEADER_RETRY_AFTER), retry_timeout)) -#endif - { - retry_timeout = mRequest->getRetryTimerDelay(); - } - - mRequest->incRetryCount(); - - if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) - { - LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; - - // Start timer (instances are automagically tracked by - // InstanceTracker<> and LLEventTimer) - new RetryTimer(F32(retry_timeout/*secs*/), mRequest); - } - else - { - LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " - << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; - } - } - // *TODO: Redirect on 3xx status codes. - else - { - LL_WARNS("LLMediaDataClient") << *mRequest << " http failure " - << dumpResponse() << LL_ENDL; - } + if (mRequest->isDead()) + { + LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; + return; + } + + LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << LL_ENDL; } -/*virtual*/ -void LLMediaDataClient::Responder::httpSuccess() +void LLMediaDataClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) { - mRequest->stopTracking(); + mRequest->stopTracking(); - if(mRequest->isDead()) - { - LL_WARNS("LLMediaDataClient") << "dead request " << *mRequest << LL_ENDL; - return; - } + if (status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE)) + { + F32 retry_timeout; + + retry_timeout = mRequest->getRetryTimerDelay(); + + mRequest->incRetryCount(); + + if (mRequest->getRetryCount() < mRequest->getMaxNumRetries()) + { + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL; - LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " " << dumpResponse() << LL_ENDL; + // Start timer (instances are automagically tracked by + // InstanceTracker<> and LLEventTimer) + new RetryTimer(F32(retry_timeout/*secs*/), mRequest); + } + else + { + LL_INFOS("LLMediaDataClient") << *mRequest << " got SERVICE_UNAVAILABLE...retry count " + << mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL; + } + } + else + { + LL_WARNS("LLMediaDataClient") << *mRequest << " HTTP failure " << LL_ENDL; + } } + ////////////////////////////////////////////////////////////////////////////////////// // // LLObjectMediaDataClient @@ -634,7 +667,7 @@ void LLMediaDataClient::Responder::httpSuccess() void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object) { // Create a get request and put it in the queue. - enqueue(new RequestGet(object, this)); + enqueue(Request::ptr_t(new RequestGet(object, this))); } const char *LLObjectMediaDataClient::getCapabilityName() const @@ -678,14 +711,14 @@ void LLObjectMediaDataClient::sortQueue() } // static -bool LLObjectMediaDataClient::compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2) +bool LLObjectMediaDataClient::compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2) { - if (o2.isNull()) return true; - if (o1.isNull()) return false; + if (!o2) return true; + if (!o1) return false; return ( o1->getScore() > o2->getScore() ); } -void LLObjectMediaDataClient::enqueue(Request *request) +void LLObjectMediaDataClient::enqueue(Request::ptr_t request) { if(request->isDead()) { @@ -703,9 +736,10 @@ void LLObjectMediaDataClient::enqueue(Request *request) { // For GET requests that are not new, if a matching request is already in the round robin queue, // in flight, or being retried, leave it at its current position. - request_queue_t::iterator iter = find_matching_request(mRoundRobinQueue, request->getID(), Request::GET); - request_set_t::iterator iter2 = find_matching_request(mUnQueuedRequests, request->getID(), Request::GET); - + PredicateMatchRequest upred(request->getID(), Request::GET); + request_queue_t::iterator iter = std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), upred); + request_set_t::iterator iter2 = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); + if( (iter != mRoundRobinQueue.end()) || (iter2 != mUnQueuedRequests.end()) ) { LL_DEBUGS("LLMediaDataClient") << "ALREADY THERE: NOT Queuing request for " << *request << LL_ENDL; @@ -718,9 +752,11 @@ void LLObjectMediaDataClient::enqueue(Request *request) // IF the update will cause an object update message to be sent out at some point in the future, it probably should. // Remove any existing requests of this type for this object - remove_matching_requests(mQueue, request->getID(), request->getType()); - remove_matching_requests(mRoundRobinQueue, request->getID(), request->getType()); - remove_matching_requests(mUnQueuedRequests, request->getID(), request->getType()); + PredicateMatchRequest upred(request->getID(), request->getType()); + + mark_dead_and_remove_if(mQueue, upred); + mark_dead_and_remove_if(mRoundRobinQueue, upred); + mark_dead_and_remove_if(mUnQueuedRequests, upred); if (is_new) { @@ -749,7 +785,7 @@ void LLObjectMediaDataClient::enqueue(Request *request) startQueueTimer(); } -bool LLObjectMediaDataClient::canServiceRequest(request_ptr_t request) +bool LLObjectMediaDataClient::canServiceRequest(Request::ptr_t request) { if(mCurrentQueueIsTheSortedQueue) { @@ -785,9 +821,9 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob if(LLMediaDataClient::isInQueue(object)) return true; - if(find_matching_request(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY) != mRoundRobinQueue.end()) - return true; - + if (std::find_if(mRoundRobinQueue.begin(), mRoundRobinQueue.end(), PredicateMatchRequest(object->getID())) != mRoundRobinQueue.end()) + return true; + return false; } @@ -796,12 +832,12 @@ void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr // First, call parent impl. LLMediaDataClient::removeFromQueue(object); - remove_matching_requests(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY); + mark_dead_and_remove_if(mRoundRobinQueue, PredicateMatchRequest(object->getID())); } bool LLObjectMediaDataClient::processQueueTimer() { - if(isEmpty()) + if (isDoneProcessing()) return true; LL_DEBUGS("LLMediaDataClient") << "started, SORTED queue size is: " << mQueue.size() @@ -816,6 +852,7 @@ bool LLObjectMediaDataClient::processQueueTimer() LL_DEBUGS("LLMediaDataClientQueue") << "after sort, SORTED queue is: " << mQueue << LL_ENDL; serviceQueue(); + serviceHttp(); swapCurrentQueue(); @@ -824,7 +861,7 @@ bool LLObjectMediaDataClient::processQueueTimer() LL_DEBUGS("LLMediaDataClientQueue") << " SORTED queue is: " << mQueue << LL_ENDL; LL_DEBUGS("LLMediaDataClientQueue") << " RR queue is: " << mRoundRobinQueue << LL_ENDL; - return isEmpty(); + return isDoneProcessing(); } LLObjectMediaDataClient::RequestGet::RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): @@ -841,16 +878,16 @@ LLSD LLObjectMediaDataClient::RequestGet::getPayload() const return result; } -LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestGet::createResponder() +LLHttpSDHandler *LLObjectMediaDataClient::RequestGet::createHandler() { - return new LLObjectMediaDataClient::Responder(this); + return new LLObjectMediaDataClient::Handler(shared_from_this()); } void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object) { // Create an update request and put it in the queue. - enqueue(new RequestUpdate(object, this)); + enqueue(Request::ptr_t(new RequestUpdate(object, this))); } LLObjectMediaDataClient::RequestUpdate::RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc): @@ -877,60 +914,58 @@ LLSD LLObjectMediaDataClient::RequestUpdate::getPayload() const return result; } -LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResponder() +LLHttpSDHandler *LLObjectMediaDataClient::RequestUpdate::createHandler() { // This just uses the base class's responder. - return new LLMediaDataClient::Responder(this); + return new LLMediaDataClient::Handler(shared_from_this()); } - -/*virtual*/ -void LLObjectMediaDataClient::Responder::httpSuccess() +void LLObjectMediaDataClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) { - getRequest()->stopTracking(); + LLMediaDataClient::Handler::onSuccess(response, content); + + if (getRequest()->isDead()) + { // warning emitted from base method. + return; + } + + if (!content.isMap()) + { + onFailure(response, LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents")); + return; + } + + // This responder is only used for GET requests, not UPDATE. + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << LL_ENDL; + + // Look for an error + if (content.has("error")) + { + const LLSD &error = content["error"]; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + + // XXX Warn user? + } + else + { + // Check the data + const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; + if (object_id != getRequest()->getObject()->getID()) + { + // NOT good, wrong object id!! + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; + return; + } + + // Otherwise, update with object media data + getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], + content[LLTextureEntry::MEDIA_VERSION_KEY]); + } - if(getRequest()->isDead()) - { - LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; - return; - } - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - - // This responder is only used for GET requests, not UPDATE. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; - - // Look for an error - if (content.has("error")) - { - const LLSD &error = content["error"]; - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << - error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; - - // XXX Warn user? - } - else - { - // Check the data - const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; - if (object_id != getRequest()->getObject()->getID()) - { - // NOT good, wrong object id!! - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " DROPPING response with wrong object id (" << object_id << ")" << LL_ENDL; - return; - } - - // Otherwise, update with object media data - getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], - content[LLTextureEntry::MEDIA_VERSION_KEY]); - } } + ////////////////////////////////////////////////////////////////////////////////////// // // LLObjectMediaNavigateClient @@ -943,16 +978,18 @@ const char *LLObjectMediaNavigateClient::getCapabilityName() const return "ObjectMediaNavigate"; } -void LLObjectMediaNavigateClient::enqueue(Request *request) +void LLObjectMediaNavigateClient::enqueue(Request::ptr_t request) { if(request->isDead()) { - LL_DEBUGS("LLMediaDataClient") << "not queueing dead request " << *request << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "not queuing dead request " << *request << LL_ENDL; return; } + PredicateMatchRequest upred(request); + // If there's already a matching request in the queue, remove it. - request_queue_t::iterator iter = find_matching_request(mQueue, request, LLMediaDataClient::Request::ANY); + request_queue_t::iterator iter = std::find_if(mQueue.begin(), mQueue.end(), upred); if(iter != mQueue.end()) { LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; @@ -960,7 +997,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request) } else { - request_set_t::iterator set_iter = find_matching_request(mUnQueuedRequests, request, LLMediaDataClient::Request::ANY); + request_set_t::iterator set_iter = std::find_if(mUnQueuedRequests.begin(), mUnQueuedRequests.end(), upred); if(set_iter != mUnQueuedRequests.end()) { LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; @@ -979,7 +1016,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request) else #endif { - LL_DEBUGS("LLMediaDataClient") << "queueing new request " << (*request) << LL_ENDL; + LL_DEBUGS("LLMediaDataClient") << "queuing new request " << (*request) << LL_ENDL; mQueue.push_back(request); // Start the timer if not already running @@ -993,7 +1030,7 @@ void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 t // LL_INFOS("LLMediaDataClient") << "navigate() initiated: " << ll_print_sd(sd_payload) << LL_ENDL; // Create a get request and put it in the queue. - enqueue(new RequestNavigate(object, this, texture_index, url)); + enqueue(Request::ptr_t(new RequestNavigate(object, this, texture_index, url))); } LLObjectMediaNavigateClient::RequestNavigate::RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url): @@ -1012,75 +1049,67 @@ LLSD LLObjectMediaNavigateClient::RequestNavigate::getPayload() const return result; } -LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::createResponder() +LLHttpSDHandler *LLObjectMediaNavigateClient::RequestNavigate::createHandler() { - return new LLObjectMediaNavigateClient::Responder(this); + return new LLObjectMediaNavigateClient::Handler(shared_from_this()); } -/*virtual*/ -void LLObjectMediaNavigateClient::Responder::httpFailure() +void LLObjectMediaNavigateClient::Handler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) { - getRequest()->stopTracking(); + LLMediaDataClient::Handler::onSuccess(response, content); - if(getRequest()->isDead()) - { - LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; - return; - } + if (getRequest()->isDead()) + { // already warned. + return; + } + + LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned" << LL_ENDL; + + if (content.has("error")) + { + const LLSD &error = content["error"]; + int error_code = error["code"]; + + if (ERROR_PERMISSION_DENIED_CODE == error_code) + { + mediaNavigateBounceBack(); + } + else + { + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << + error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; + } + + // XXX Warn user? + } + else + { + // No action required. + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << LL_ENDL; + } - // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base - // class - if (getStatus() == HTTP_SERVICE_UNAVAILABLE) - { - LLMediaDataClient::Responder::httpFailure(); - } - else - { - // bounce the face back - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: " << dumpResponse() << LL_ENDL; - const LLSD &payload = getRequest()->getPayload(); - // bounce the face back - getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); - } } -/*virtual*/ -void LLObjectMediaNavigateClient::Responder::httpSuccess() +void LLObjectMediaNavigateClient::Handler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) { - getRequest()->stopTracking(); + LLMediaDataClient::Handler::onFailure(response, status); - if(getRequest()->isDead()) - { - LL_WARNS("LLMediaDataClient") << "dead request " << *(getRequest()) << LL_ENDL; - return; - } + if (getRequest()->isDead()) + { // already warned. + return; + } - LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << dumpResponse() << LL_ENDL; - - const LLSD& content = getContent(); - if (content.has("error")) - { - const LLSD &error = content["error"]; - int error_code = error["code"]; - - if (ERROR_PERMISSION_DENIED_CODE == error_code) - { - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Navigation denied: bounce back" << LL_ENDL; - const LLSD &payload = getRequest()->getPayload(); - // bounce the face back - getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); - } - else - { - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: code=" << - error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; - } + if (status != LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE)) + { + mediaNavigateBounceBack(); + } +} - // XXX Warn user? - } - else - { - // No action required. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " " << dumpResponse() << LL_ENDL; - } +void LLObjectMediaNavigateClient::Handler::mediaNavigateBounceBack() +{ + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating or denied." << LL_ENDL; + const LLSD &payload = getRequest()->getPayload(); + + // bounce the face back + getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 80dd519812..9907897613 100755 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -27,12 +27,15 @@ #ifndef LL_LLMEDIADATACLIENT_H #define LL_LLMEDIADATACLIENT_H -#include "llhttpclient.h" #include <set> #include "llrefcount.h" #include "llpointer.h" #include "lleventtimer.h" - +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "httprequest.h" +#include "httpoptions.h" +#include "httpheaders.h" // Link seam for LLVOVolume class LLMediaDataClientObject : public LLRefCount @@ -74,6 +77,8 @@ public: // Abstracts the Cap URL, the request, and the responder class LLMediaDataClient : public LLRefCount { + friend class PredicateMatchRequest; + protected: LOG_CLASS(LLMediaDataClient); public: @@ -109,26 +114,30 @@ protected: // Destructor virtual ~LLMediaDataClient(); // use unref - class Responder; - // Request (pure virtual base class for requests in the queue) - class Request : public LLRefCount - { - public: - // Subclasses must implement this to build a payload for their request type. - virtual LLSD getPayload() const = 0; - // and must create the correct type of responder. - virtual Responder *createResponder() = 0; + class Request: + public boost::enable_shared_from_this<Request> + { + public: + typedef boost::shared_ptr<Request> ptr_t; - virtual std::string getURL() { return ""; } + // Subclasses must implement this to build a payload for their request type. + virtual LLSD getPayload() const = 0; + // and must create the correct type of responder. + virtual LLHttpSDHandler *createHandler() = 0; + + virtual std::string getURL() { return ""; } enum Type { GET, UPDATE, NAVIGATE, - ANY + ANY }; - + + virtual ~Request() + { } + protected: // The only way to create one of these is through a subclass. Request(Type in_type, LLMediaDataClientObject *obj, LLMediaDataClient *mdc, S32 face = -1); @@ -166,7 +175,7 @@ protected: const LLUUID &getID() const { return mObjectID; } S32 getFace() const { return mFace; } - bool isMatch (const Request* other, Type match_type = ANY) const + bool isMatch (const Request::ptr_t &other, Type match_type = ANY) const { return ((match_type == ANY) || (mType == other->mType)) && (mFace == other->mFace) && @@ -188,61 +197,62 @@ protected: // Back pointer to the MDC...not a ref! LLMediaDataClient *mMDC; }; - typedef LLPointer<Request> request_ptr_t; + //typedef LLPointer<Request> request_ptr_t; - // Responder - class Responder : public LLHTTPClient::Responder - { - LOG_CLASS(Responder); - public: - Responder(const request_ptr_t &request); - request_ptr_t &getRequest() { return mRequest; } + class Handler : public LLHttpSDHandler + { + LOG_CLASS(Handler); + public: + Handler(const Request::ptr_t &request); + Request::ptr_t getRequest() const { return mRequest; } - protected: - //If we get back an error (not found, etc...), handle it here - virtual void httpFailure(); - //If we get back a normal response, handle it here. Default just logs it. - virtual void httpSuccess(); + protected: + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + + private: + Request::ptr_t mRequest; + }; - private: - request_ptr_t mRequest; - }; class RetryTimer : public LLEventTimer { public: - RetryTimer(F32 time, request_ptr_t); + RetryTimer(F32 time, Request::ptr_t); virtual BOOL tick(); private: // back-pointer - request_ptr_t mRequest; + Request::ptr_t mRequest; }; protected: - typedef std::list<request_ptr_t> request_queue_t; - typedef std::set<request_ptr_t> request_set_t; + typedef std::list<Request::ptr_t> request_queue_t; + typedef std::set<Request::ptr_t> request_set_t; // Subclasses must override to return a cap name virtual const char *getCapabilityName() const = 0; // Puts the request into a queue, appropriately handling duplicates, etc. - virtual void enqueue(Request*) = 0; + virtual void enqueue(Request::ptr_t) = 0; virtual void serviceQueue(); + virtual void serviceHttp(); virtual request_queue_t *getQueue() { return &mQueue; }; // Gets the next request, removing it from the queue - virtual request_ptr_t dequeue(); + virtual Request::ptr_t dequeue(); - virtual bool canServiceRequest(request_ptr_t request) { return true; }; + virtual bool canServiceRequest(Request::ptr_t request) { return true; }; // Returns a request to the head of the queue (should only be used for requests that came from dequeue - virtual void pushBack(request_ptr_t request); + virtual void pushBack(Request::ptr_t request); - void trackRequest(request_ptr_t request); - void stopTrackingRequest(request_ptr_t request); + void trackRequest(Request::ptr_t request); + void stopTrackingRequest(Request::ptr_t request); + + bool isDoneProcessing() const; request_queue_t mQueue; @@ -260,6 +270,11 @@ protected: void startQueueTimer(); void stopQueueTimer(); + LLCore::HttpRequest::ptr_t mHttpRequest; + LLCore::HttpHeaders::ptr_t mHttpHeaders; + LLCore::HttpOptions::ptr_t mHttpOpts; + LLCore::HttpRequest::policy_t mHttpPolicy; + private: static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj); @@ -281,9 +296,9 @@ private: bool mQueueTimerIsRunning; - template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); - template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); - template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); +// template <typename T> friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); +// template <typename T> friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); }; // MediaDataClient specific for the ObjectMedia cap @@ -309,7 +324,7 @@ public: public: RequestGet(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); /*virtual*/ LLSD getPayload() const; - /*virtual*/ Responder *createResponder(); + /*virtual*/ LLHttpSDHandler *createHandler(); }; class RequestUpdate: public Request @@ -317,7 +332,7 @@ public: public: RequestUpdate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc); /*virtual*/ LLSD getPayload() const; - /*virtual*/ Responder *createResponder(); + /*virtual*/ LLHttpSDHandler *createHandler(); }; // Returns true iff the queue is empty @@ -331,7 +346,7 @@ public: virtual bool processQueueTimer(); - virtual bool canServiceRequest(request_ptr_t request); + virtual bool canServiceRequest(Request::ptr_t request); protected: // Subclasses must override to return a cap name @@ -340,17 +355,20 @@ protected: virtual request_queue_t *getQueue(); // Puts the request into the appropriate queue - virtual void enqueue(Request*); + virtual void enqueue(Request::ptr_t); - class Responder : public LLMediaDataClient::Responder + class Handler: public LLMediaDataClient::Handler { - LOG_CLASS(Responder); + LOG_CLASS(Handler); public: - Responder(const request_ptr_t &request) - : LLMediaDataClient::Responder(request) {} + Handler(const Request::ptr_t &request): + LLMediaDataClient::Handler(request) + {} + protected: - virtual void httpSuccess(); + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); }; + private: // The Get/Update data client needs a second queue to avoid object updates starving load-ins. void swapCurrentQueue(); @@ -359,7 +377,7 @@ private: bool mCurrentQueueIsTheSortedQueue; // Comparator for sorting - static bool compareRequestScores(const request_ptr_t &o1, const request_ptr_t &o2); + static bool compareRequestScores(const Request::ptr_t &o1, const Request::ptr_t &o2); void sortQueue(); }; @@ -384,14 +402,14 @@ public: void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url); // Puts the request into the appropriate queue - virtual void enqueue(Request*); + virtual void enqueue(Request::ptr_t); class RequestNavigate: public Request { public: RequestNavigate(LLMediaDataClientObject *obj, LLMediaDataClient *mdc, U8 texture_index, const std::string &url); /*virtual*/ LLSD getPayload() const; - /*virtual*/ Responder *createResponder(); + /*virtual*/ LLHttpSDHandler *createHandler(); /*virtual*/ std::string getURL() { return mURL; } private: std::string mURL; @@ -401,15 +419,18 @@ protected: // Subclasses must override to return a cap name virtual const char *getCapabilityName() const; - class Responder : public LLMediaDataClient::Responder + class Handler : public LLMediaDataClient::Handler { - LOG_CLASS(Responder); + LOG_CLASS(Handler); public: - Responder(const request_ptr_t &request) - : LLMediaDataClient::Responder(request) {} + Handler(const Request::ptr_t &request): + LLMediaDataClient::Handler(request) + {} + protected: - virtual void httpFailure(); - virtual void httpSuccess(); + virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); + virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + private: void mediaNavigateBounceBack(); }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9a0bd9d1bc..457053f713 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -36,7 +36,6 @@ #include "llappviewer.h" #include "llbufferstream.h" #include "llcallbacklist.h" -#include "llcurl.h" #include "lldatapacker.h" #include "lldeadmantimer.h" #include "llfloatermodelpreview.h" @@ -73,6 +72,10 @@ #include "llfasttimer.h" #include "llcorehttputil.h" #include "lltrans.h" +#include "llstatusbar.h" +#include "llinventorypanel.h" +#include "lluploaddialog.h" +#include "llfloaterreg.h" #include "boost/lexical_cast.hpp" @@ -413,6 +416,17 @@ static unsigned int metrics_teleport_start_count = 0; boost::signals2::connection metrics_teleport_started_signal; static void teleport_started(); +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price); + + //get the number of bytes resident in memory for given volume U32 get_volume_memory_size(const LLVolume* volume) { @@ -493,6 +507,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, } } +LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material) +{ + LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData); + return ppTex ? (*ppTex).get() : NULL; +} + volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0; volatile S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; @@ -587,16 +607,16 @@ public: LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes) : LLMeshHandlerBase(offset, requested_bytes), mLOD(lod) - { + { mMeshParams = mesh_params; LLMeshRepoThread::incActiveLODRequests(); } virtual ~LLMeshLODHandler(); - + protected: LLMeshLODHandler(const LLMeshLODHandler &); // Not defined void operator=(const LLMeshLODHandler &); // Not defined - + public: virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size); virtual void processFailure(LLCore::HttpStatus status); @@ -768,9 +788,9 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content, LLMeshRepoThread::LLMeshRepoThread() : LLThread("mesh repo"), mHttpRequest(NULL), - mHttpOptions(NULL), - mHttpLargeOptions(NULL), - mHttpHeaders(NULL), + mHttpOptions(), + mHttpLargeOptions(), + mHttpHeaders(), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), @@ -783,20 +803,20 @@ LLMeshRepoThread::LLMeshRepoThread() mHeaderMutex = new LLMutex(NULL); mSignal = new LLCondition(NULL); mHttpRequest = new LLCore::HttpRequest; - mHttpOptions = new LLCore::HttpOptions; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpOptions->setTransferTimeout(SMALL_MESH_XFER_TIMEOUT); mHttpOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter")); - mHttpLargeOptions = new LLCore::HttpOptions; + mHttpLargeOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpLargeOptions->setTransferTimeout(LARGE_MESH_XFER_TIMEOUT); mHttpLargeOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter")); - mHttpHeaders = new LLCore::HttpHeaders; + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_VND_LL_MESH); mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH2); mHttpLegacyPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_MESH1); mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH); } - + LLMeshRepoThread::~LLMeshRepoThread() { LL_INFOS(LOG_MESH) << "Small GETs issued: " << LLMeshRepository::sHTTPRequestCount @@ -811,22 +831,9 @@ LLMeshRepoThread::~LLMeshRepoThread() delete *iter; } mHttpRequestSet.clear(); - if (mHttpHeaders) - { - mHttpHeaders->release(); - mHttpHeaders = NULL; - } - if (mHttpOptions) - { - mHttpOptions->release(); - mHttpOptions = NULL; - } - if (mHttpLargeOptions) - { - mHttpLargeOptions->release(); - mHttpLargeOptions = NULL; - } - delete mHttpRequest; + mHttpHeaders.reset(); + + delete mHttpRequest; mHttpRequest = NULL; delete mMutex; mMutex = NULL; @@ -865,16 +872,16 @@ void LLMeshRepoThread::run() { break; } - + if (! mHttpRequestSet.empty()) { // Dispatch all HttpHandler notifications mHttpRequest->update(0L); } sRequestWaterLevel = mHttpRequestSet.size(); // Stats data update - - // NOTE: order of queue processing intentionally favors LOD requests over header requests + // NOTE: order of queue processing intentionally favors LOD requests over header requests + while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater) { if (! mMutex) @@ -938,7 +945,7 @@ void LLMeshRepoThread::run() mSkinRequests.erase(iter); mMutex->unlock(); - if (!fetchMeshSkinInfo(mesh_id)) + if (! fetchMeshSkinInfo(mesh_id)) { incomplete.insert(mesh_id); } @@ -967,7 +974,7 @@ void LLMeshRepoThread::run() mDecompositionRequests.erase(iter); mMutex->unlock(); - if (!fetchMeshDecomposition(mesh_id)) + if (! fetchMeshDecomposition(mesh_id)) { incomplete.insert(mesh_id); } @@ -993,7 +1000,7 @@ void LLMeshRepoThread::run() mPhysicsShapeRequests.erase(iter); mMutex->unlock(); - if (!fetchMeshPhysicsShape(mesh_id)) + if (! fetchMeshPhysicsShape(mesh_id)) { incomplete.insert(mesh_id); } @@ -1219,7 +1226,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } ++LLMeshRepository::sMeshRequestCount; - bool ret = true ; + bool ret = true; U32 header_size = mMeshHeaderSize[mesh_id]; if (header_size > 0) @@ -1267,7 +1274,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) constructUrl(mesh_id, &http_url, &cap_version); if (!http_url.empty()) - { + { LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size); LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1313,7 +1320,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) ++LLMeshRepository::sMeshRequestCount; U32 header_size = mMeshHeaderSize[mesh_id]; - bool ret = true ; + bool ret = true; if (header_size > 0) { @@ -1359,9 +1366,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) int cap_version(2); std::string http_url; constructUrl(mesh_id, &http_url, &cap_version); - + if (!http_url.empty()) - { + { LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size); LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1407,7 +1414,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) ++LLMeshRepository::sMeshRequestCount; U32 header_size = mMeshHeaderSize[mesh_id]; - bool ret = true ; + bool ret = true; if (header_size > 0) { @@ -1452,9 +1459,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) int cap_version(2); std::string http_url; constructUrl(mesh_id, &http_url, &cap_version); - + if (!http_url.empty()) - { + { LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size); LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1543,11 +1550,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) } //either cache entry doesn't exist or is corrupt, request header from simulator - bool retval = true ; + bool retval = true; int cap_version(2); std::string http_url; constructUrl(mesh_params.getSculptID(), &http_url, &cap_version); - + if (!http_url.empty()) { //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits @@ -1635,9 +1642,9 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) int cap_version(2); std::string http_url; constructUrl(mesh_id, &http_url, &cap_version); - + if (!http_url.empty()) - { + { LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size); LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1909,14 +1916,14 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mOrigin += gAgent.getAtAxis() * scale.magVec(); - mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; + mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut"); mHttpRequest = new LLCore::HttpRequest; - mHttpOptions = new LLCore::HttpOptions; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpOptions->setTransferTimeout(mMeshUploadTimeOut); mHttpOptions->setUseRetryAfter(gSavedSettings.getBOOL("MeshUseHttpRetryAfter")); mHttpOptions->setRetries(UPLOAD_RETRY_LIMIT); - mHttpHeaders = new LLCore::HttpHeaders; + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_UPLOADS); mHttpPriority = 0; @@ -1924,16 +1931,6 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLMeshUploadThread::~LLMeshUploadThread() { - if (mHttpHeaders) - { - mHttpHeaders->release(); - mHttpHeaders = NULL; - } - if (mHttpOptions) - { - mHttpOptions->release(); - mHttpOptions = NULL; - } delete mHttpRequest; mHttpRequest = NULL; } @@ -1977,14 +1974,14 @@ void LLMeshUploadThread::preStart() void LLMeshUploadThread::discard() { - LLMutexLock lock(mMutex) ; + LLMutexLock lock(mMutex); mDiscarded = true; } bool LLMeshUploadThread::isDiscarded() const { - LLMutexLock lock(mMutex) ; - return mDiscarded ; + LLMutexLock lock(mMutex); + return mDiscarded; } void LLMeshUploadThread::run() @@ -2049,6 +2046,14 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { LLMeshUploadData data; data.mBaseModel = iter->first; + + if (data.mBaseModel->mSubmodelID) + { + // These are handled below to insure correct parenting order on creation + // due to map walking being based on model address (aka random) + continue; + } + LLModelInstance& first_instance = *(iter->second.begin()); for (S32 i = 0; i < 5; i++) { @@ -2086,7 +2091,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) data.mModel[LLModel::LOD_IMPOSTOR], decomp, mUploadSkin, - mUploadJoints); + mUploadJoints, + FALSE, + FALSE, + data.mBaseModel->mSubmodelID); data.mAssetData = ostr.str(); std::string str = ostr.str(); @@ -2120,17 +2128,26 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) instance_entry["scale"] = ll_sd_from_vector3(scale); instance_entry["material"] = LL_MCODE_WOOD; - instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); + instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); instance_entry["mesh"] = mesh_index[data.mBaseModel]; instance_entry["face_list"] = LLSD::emptyArray(); - S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ; + // We want to be able to allow more than 8 materials... + // + S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; + for (S32 face_num = 0; face_num < end; face_num++) { LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; LLSD face_entry = LLSD::emptyMap(); - LLViewerFetchedTexture *texture = material.mDiffuseMap.get(); + + LLViewerFetchedTexture *texture = NULL; + + if (material.mDiffuseMapFilename.size()) + { + texture = FindViewerTexture(material); + } if ((texture != NULL) && (textures.find(texture) == textures.end())) @@ -2145,9 +2162,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { LLPointer<LLImageJ2C> upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + + if (!upload_file.isNull() && upload_file->getDataSize()) + { texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); } } + } + + if (texture != NULL && + mUploadTextures && + texture_index.find(texture) == texture_index.end()) + { + texture_index[texture] = texture_num; + std::string str = texture_str.str(); + res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end()); + texture_num++; + } + + // Subset of TextureEntry fields. + if (texture != NULL && mUploadTextures) + { + face_entry["image"] = texture_index[texture]; + face_entry["scales"] = 1.0; + face_entry["scalet"] = 1.0; + face_entry["offsets"] = 0.0; + face_entry["offsett"] = 0.0; + face_entry["imagerot"] = 0.0; + } + face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor); + face_entry["fullbright"] = material.mFullbright; + instance_entry["face_list"][face_num] = face_entry; + } + + res["instance_list"][instance_num] = instance_entry; + instance_num++; + } + } + + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) + { + LLMeshUploadData data; + data.mBaseModel = iter->first; + + if (!data.mBaseModel->mSubmodelID) + { + // These were handled above already... + // + continue; + } + + LLModelInstance& first_instance = *(iter->second.begin()); + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = first_instance.mLOD[i]; + } + + if (mesh_index.find(data.mBaseModel) == mesh_index.end()) + { + // Have not seen this model before - create a new mesh_list entry for it. + if (model_name.empty()) + { + model_name = data.mBaseModel->getName(); + } + + if (model_metric.empty()) + { + model_metric = data.mBaseModel->getMetric(); + } + + std::stringstream ostr; + + LLModel::Decomposition& decomp = + data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mPhysics : + data.mBaseModel->mPhysics; + + decomp.mBaseHull = mHullMap[data.mBaseModel]; + + LLSD mesh_header = LLModel::writeModel( + ostr, + data.mModel[LLModel::LOD_PHYSICS], + data.mModel[LLModel::LOD_HIGH], + data.mModel[LLModel::LOD_MEDIUM], + data.mModel[LLModel::LOD_LOW], + data.mModel[LLModel::LOD_IMPOSTOR], + decomp, + mUploadSkin, + mUploadJoints, + FALSE, + FALSE, + data.mBaseModel->mSubmodelID); + + data.mAssetData = ostr.str(); + std::string str = ostr.str(); + + res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); + mesh_index[data.mBaseModel] = mesh_num; + mesh_num++; + } + + // For all instances that use this model + for (instance_list::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + + LLModelInstance& instance = *instance_iter; + + LLSD instance_entry; + + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = instance.mLOD[i]; + } + + LLVector3 pos, scale; + LLQuaternion rot; + LLMatrix4 transformation = instance.mTransform; + decomposeMeshMatrix(transformation,pos,rot,scale); + instance_entry["position"] = ll_sd_from_vector3(pos); + instance_entry["rotation"] = ll_sd_from_quaternion(rot); + instance_entry["scale"] = ll_sd_from_vector3(scale); + + instance_entry["material"] = LL_MCODE_WOOD; + instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE); + instance_entry["mesh"] = mesh_index[data.mBaseModel]; + + instance_entry["face_list"] = LLSD::emptyArray(); + + // We want to be able to allow more than 8 materials... + // + S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; + + for (S32 face_num = 0; face_num < end; face_num++) + { + LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; + LLSD face_entry = LLSD::emptyMap(); + + LLViewerFetchedTexture *texture = NULL; + + if (material.mDiffuseMapFilename.size()) + { + texture = FindViewerTexture(material); + } + + if ((texture != NULL) && + (textures.find(texture) == textures.end())) + { + textures.insert(texture); + } + + std::stringstream texture_str; + if (texture != NULL && include_textures && mUploadTextures) + { + if(texture->hasSavedRawImage()) + { + LLPointer<LLImageJ2C> upload_file = + LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + + if (!upload_file.isNull() && upload_file->getDataSize()) + { + texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + } + } + } if (texture != NULL && mUploadTextures && @@ -2235,7 +2414,7 @@ void LLMeshUploadThread::generateHulls() } } - if(has_valid_requests) + if (has_valid_requests) { // *NOTE: Interesting livelock condition on shutdown. If there // is an upload request in generateHulls() when shutdown starts, @@ -2340,7 +2519,7 @@ void LLMeshUploadThread::requestWholeModelFee() else { U32 sleep_time(10); - + mHttpRequest->update(0); while (! LLApp::isQuitting() && ! finished() && ! isDiscarded()) { @@ -2435,7 +2614,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp // model fee case LLWholeModelFeeObserver* observer(mFeeObserverHandle.get()); mWholeModelUploadURL.clear(); - + if (! status) { LL_WARNS(LOG_MESH) << "Fee request failed. Reason: " << reason @@ -2465,7 +2644,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp LLCoreHttpUtil::responseToLLSD(response, true, body); } dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num)); - + if (body["state"].asString() == "upload") { mWholeModelUploadURL = body["uploader"].asString(); @@ -2536,7 +2715,7 @@ void LLMeshRepoThread::notifyLoadedMeshes() LODRequest req = mUnavailableQ.front(); mUnavailableQ.pop(); mMutex->unlock(); - + update_metrics = true; gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); } @@ -2672,7 +2851,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header) void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) { mProcessed = true; - + unsigned int retries(0U); response->getRetries(NULL, &retries); LLMeshRepository::sHTTPRetryCount += retries; @@ -2728,7 +2907,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo // 200 case, typically offset = 0; } - + // *DEBUG: To test validation below // offset += 1; @@ -2844,7 +3023,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b const std::string & lod_name = header_lod[i]; lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger()); } - + // just in case skin info or decomposition is at the end of the file (which it shouldn't be) lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger()); lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); @@ -2852,7 +3031,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; S32 bytes = lod_bytes + header_bytes; - + // It's possible for the remote asset to have more data than is needed for the local cache // only allocate as much space in the VFS as is needed for the local cache data_size = llmin(data_size, bytes); @@ -2864,11 +3043,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b ++LLMeshRepository::sCacheWrites; file.write(data, data_size); - + // zero out the rest of the file U8 block[MESH_HEADER_SIZE]; memset(block, 0, sizeof(block)); - + while (bytes-file.tell() > sizeof(block)) { file.write(block, sizeof(block)); @@ -2894,8 +3073,8 @@ LLMeshLODHandler::~LLMeshLODHandler() gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD); } LLMeshRepoThread::decActiveLODRequests(); - } } +} void LLMeshLODHandler::processFailure(LLCore::HttpStatus status) { @@ -2913,7 +3092,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body { if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size)) { - //good fetch from sim, write to VFS for caching + // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE); S32 offset = mOffset; @@ -2958,7 +3137,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* { if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) { - //good fetch from sim, write to VFS for caching + // good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE); S32 offset = mOffset; @@ -3282,7 +3461,7 @@ void LLMeshRepository::notifyLoadedMeshes() REQUEST2_LOW_WATER_MIN, REQUEST2_LOW_WATER_MAX); } - + //clean up completed upload threads for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); ) { @@ -3359,7 +3538,7 @@ void LLMeshRepository::notifyLoadedMeshes() //call completed callbacks on finished decompositions mDecompThread->notifyCompleted(); - + // For major operations, attempt to get the required locks // without blocking and punt if they're not available. The // longest run of holdoffs is kept in sMaxLockHoldoffs just @@ -3378,12 +3557,12 @@ void LLMeshRepository::notifyLoadedMeshes() return; } hold_offs = 0; - + if (gAgent.getRegion()) { // Update capability urls static std::string region_name("never name a region this"); - + if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); @@ -3399,7 +3578,7 @@ void LLMeshRepository::notifyLoadedMeshes() << LL_ENDL; } } - + //popup queued error messages from background threads while (!mUploadErrorQ.empty()) { @@ -3754,7 +3933,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, - bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload, + bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload, LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer) { LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, @@ -3825,37 +4004,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation, result_rot = quat_rotation; } -bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const -{ - if (mDiffuseMap != rhs.mDiffuseMap) - { - return mDiffuseMap < rhs.mDiffuseMap; - } - - if (mDiffuseMapFilename != rhs.mDiffuseMapFilename) - { - return mDiffuseMapFilename < rhs.mDiffuseMapFilename; - } - - if (mDiffuseMapLabel != rhs.mDiffuseMapLabel) - { - return mDiffuseMapLabel < rhs.mDiffuseMapLabel; - } - - if (mDiffuseColor != rhs.mDiffuseColor) - { - return mDiffuseColor < rhs.mDiffuseColor; - } - - if (mBinding != rhs.mBinding) - { - return mBinding < rhs.mBinding; - } - - return mFullbright < rhs.mFullbright; -} - - void LLMeshRepository::updateInventory(inventory_data data) { LLMutexLock lock(mMeshMutex); @@ -4253,7 +4401,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull() setMeshData(mesh, true); LLCDResult ret = decomp->buildSingleHull() ; - if(ret) + if (ret) { LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL; make_box(mCurRequest); @@ -4441,60 +4589,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } -LLModelInstance::LLModelInstance(LLSD& data) -{ - mLocalMeshID = data["mesh_id"].asInteger(); - mLabel = data["label"].asString(); - mTransform.setValue(data["transform"]); - - for (U32 i = 0; i < data["material"].size(); ++i) - { - LLImportMaterial mat(data["material"][i]); - mMaterial[mat.mBinding] = mat; - } -} - - -LLSD LLModelInstance::asLLSD() -{ - LLSD ret; - - ret["mesh_id"] = mModel->mLocalID; - ret["label"] = mLabel; - ret["transform"] = mTransform.getValue(); - - U32 i = 0; - for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter) - { - ret["material"][i++] = iter->second.asLLSD(); - } - - return ret; -} - -LLImportMaterial::LLImportMaterial(LLSD& data) -{ - mDiffuseMapFilename = data["diffuse"]["filename"].asString(); - mDiffuseMapLabel = data["diffuse"]["label"].asString(); - mDiffuseColor.setValue(data["diffuse"]["color"]); - mFullbright = data["fullbright"].asBoolean(); - mBinding = data["binding"].asString(); -} - - -LLSD LLImportMaterial::asLLSD() -{ - LLSD ret; - - ret["diffuse"]["filename"] = mDiffuseMapFilename; - ret["diffuse"]["label"] = mDiffuseMapLabel; - ret["diffuse"]["color"] = mDiffuseColor.getValue(); - ret["fullbright"] = mFullbright; - ret["binding"] = mBinding; - - return ret; -} - void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) { decomp.mMesh.resize(decomp.mHull.size()); @@ -4620,3 +4714,122 @@ void teleport_started() LLMeshRepository::metricsStart(); } + +void on_new_single_inventory_upload_complete( + LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + const std::string inventory_type_string, + const LLUUID& item_folder_id, + const std::string& item_name, + const std::string& item_description, + const LLSD& server_response, + S32 upload_price) +{ + bool success = false; + + if (upload_price > 0) + { + // this upload costed us L$, update our balance + // and display something saying that it cost L$ + LLStatusBar::sendMoneyBalanceRequest(); + + LLSD args; + args["AMOUNT"] = llformat("%d", upload_price); + LLNotificationsUtil::add("UploadPayment", args); + } + + if (item_folder_id.notNull()) + { + U32 everyone_perms = PERM_NONE; + U32 group_perms = PERM_NONE; + U32 next_owner_perms = PERM_ALL; + if (server_response.has("new_next_owner_mask")) + { + // The server provided creation perms so use them. + // Do not assume we got the perms we asked for in + // since the server may not have granted them all. + everyone_perms = server_response["new_everyone_mask"].asInteger(); + group_perms = server_response["new_group_mask"].asInteger(); + next_owner_perms = server_response["new_next_owner_mask"].asInteger(); + } + else + { + // The server doesn't provide creation perms + // so use old assumption-based perms. + if (inventory_type_string != "snapshot") + { + next_owner_perms = PERM_MOVE | PERM_TRANSFER; + } + } + + LLPermissions new_perms; + new_perms.init( + gAgent.getID(), + gAgent.getID(), + LLUUID::null, + LLUUID::null); + + new_perms.initMasks( + PERM_ALL, + PERM_ALL, + everyone_perms, + group_perms, + next_owner_perms); + + U32 inventory_item_flags = 0; + if (server_response.has("inventory_flags")) + { + inventory_item_flags = (U32)server_response["inventory_flags"].asInteger(); + if (inventory_item_flags != 0) + { + LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL; + } + } + S32 creation_date_now = time_corrected(); + LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( + server_response["new_inventory_item"].asUUID(), + item_folder_id, + new_perms, + server_response["new_asset"].asUUID(), + asset_type, + inventory_type, + item_name, + item_description, + LLSaleInfo::DEFAULT, + inventory_item_flags, + creation_date_now); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + success = true; + + // Show the preview panel for textures and sounds to let + // user know that the image (or snapshot) arrived intact. + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + if (panel) + { + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + + panel->setSelection( + server_response["new_inventory_item"].asUUID(), + TAKE_FOCUS_NO); + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); + } + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } + + // remove the "Uploading..." message + LLUploadDialog::modalUploadFinished(); + + // Let the Snapshot floater know we have finished uploading a snapshot to inventory. + LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); + if (asset_type == LLAssetType::AT_TEXTURE && floater_snapshot) + { + floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory"))); + } +} diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 39280bea3a..b33497730e 100755 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -38,6 +38,7 @@ #include "httpoptions.h" #include "httpheaders.h" #include "httphandler.h" +#include "llthread.h" #define LLCONVEXDECOMPINTER_STATIC 1 @@ -90,54 +91,6 @@ public: } }; -class LLImportMaterial -{ -public: - LLPointer<LLViewerFetchedTexture> mDiffuseMap; - std::string mDiffuseMapFilename; - std::string mDiffuseMapLabel; - std::string mBinding; - LLColor4 mDiffuseColor; - bool mFullbright; - - bool operator<(const LLImportMaterial ¶ms) const; - - LLImportMaterial() - : mFullbright(false) - { - mDiffuseColor.set(1,1,1,1); - } - - LLImportMaterial(LLSD& data); - - LLSD asLLSD(); -}; - -class LLModelInstance -{ -public: - LLPointer<LLModel> mModel; - LLPointer<LLModel> mLOD[5]; - - std::string mLabel; - - LLUUID mMeshID; - S32 mLocalMeshID; - - LLMatrix4 mTransform; - std::map<std::string, LLImportMaterial> mMaterial; - - LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials) - : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) - { - mLocalMeshID = -1; - } - - LLModelInstance(LLSD& data); - - LLSD asLLSD(); -}; - class LLPhysicsDecomp : public LLThread { public: @@ -322,9 +275,9 @@ public: // llcorehttp library interface objects. LLCore::HttpStatus mHttpStatus; LLCore::HttpRequest * mHttpRequest; - LLCore::HttpOptions * mHttpOptions; - LLCore::HttpOptions * mHttpLargeOptions; - LLCore::HttpHeaders * mHttpHeaders; + LLCore::HttpOptions::ptr_t mHttpOptions; + LLCore::HttpOptions::ptr_t mHttpLargeOptions; + LLCore::HttpHeaders::ptr_t mHttpHeaders; LLCore::HttpRequest::policy_t mHttpPolicyClass; LLCore::HttpRequest::policy_t mHttpLegacyPolicyClass; LLCore::HttpRequest::policy_t mHttpLargePolicyClass; @@ -483,6 +436,8 @@ public: // Inherited from LLCore::HttpHandler virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material); + private: LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle; LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle; @@ -493,8 +448,8 @@ private: // llcorehttp library interface objects. LLCore::HttpStatus mHttpStatus; LLCore::HttpRequest * mHttpRequest; - LLCore::HttpOptions * mHttpOptions; - LLCore::HttpHeaders * mHttpHeaders; + LLCore::HttpOptions::ptr_t mHttpOptions; + LLCore::HttpHeaders::ptr_t mHttpHeaders; LLCore::HttpRequest::policy_t mHttpPolicyClass; LLCore::HttpRequest::priority_t mHttpPriority; }; diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 3e7f05b5e1..7a183cb298 100755 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -277,22 +277,6 @@ protected: virtual void initChannel() {}; }; -/** - * Handler for outbox notifications - */ -class LLOutboxNotification : public LLSystemNotificationHandler -{ -public: - LLOutboxNotification(); - virtual ~LLOutboxNotification() {}; - virtual void onChange(LLNotificationPtr p) { } - virtual void onDelete(LLNotificationPtr p); - virtual bool processNotification(const LLNotificationPtr& p); - -protected: - virtual void initChannel() {}; -}; - class LLHandlerUtil { public: diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index 152581c5a0..a6f20a9f27 100755 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -61,7 +61,6 @@ void LLNotificationManager::init() mChannels.push_back(new LLOfferHandler()); mChannels.push_back(new LLHintHandler()); mChannels.push_back(new LLBrowserNotification()); - mChannels.push_back(new LLOutboxNotification()); mChannels.push_back(new LLIMHandler()); mChatHandler = boost::shared_ptr<LLFloaterIMNearbyChatHandler>(new LLFloaterIMNearbyChatHandler()); @@ -70,7 +69,7 @@ void LLNotificationManager::init() //-------------------------------------------------------------------------- void LLNotificationManager::onChat(const LLChat& msg, const LLSD &args) { - if(mChatHandler) - mChatHandler->processChat(msg, args); - } + if(mChatHandler) + mChatHandler->processChat(msg, args); +} diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 878f1af9ef..5d1ae4ff10 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -34,14 +34,12 @@ #include "lldispatcher.h" #include "llfloaterreg.h" -#include "llhttpclient.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llparcel.h" #include "llagent.h" #include "llclassifiedflags.h" -#include "llclassifiedstatsresponder.h" #include "llcommandhandler.h" // for classified HTML detail page click tracking #include "lliconctrl.h" #include "lllineeditor.h" @@ -57,6 +55,7 @@ #include "llscrollcontainer.h" #include "llstatusbar.h" #include "llviewertexture.h" +#include "llcorehttputil.h" const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ @@ -91,19 +90,6 @@ public: }; static LLDispatchClassifiedClickThrough sClassifiedClickThrough; -// Just to debug errors. Can be thrown away later. -class LLClassifiedClickMessageResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLClassifiedClickMessageResponder); - -protected: - // If we get back an error (not found, etc...), handle it here - virtual void httpFailure() - { - LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL; - } -}; - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -229,8 +215,10 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key) { LL_INFOS() << "Classified stat request via capability" << LL_ENDL; LLSD body; - body["classified_id"] = getClassifiedId(); - LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(getClassifiedId())); + LLUUID classifiedId = getClassifiedId(); + body["classified_id"] = classifiedId; + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, + boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1)); } // Update classified click stats. @@ -240,6 +228,23 @@ void LLPanelClassifiedInfo::onOpen(const LLSD& key) setInfoLoaded(false); } +/*static*/ +void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ + S32 teleport = result["teleport_clicks"].asInteger(); + S32 map = result["map_clicks"].asInteger(); + S32 profile = result["profile_clicks"].asInteger(); + S32 search_teleport = result["search_teleport_clicks"].asInteger(); + S32 search_map = result["search_map_clicks"].asInteger(); + S32 search_profile = result["search_profile_clicks"].asInteger(); + + LLPanelClassifiedInfo::setClickThrough(classifiedId, + teleport + search_teleport, + map + search_map, + profile + search_profile, + true); +} + void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) { if(APT_CLASSIFIED_INFO == type) @@ -548,7 +553,8 @@ void LLPanelClassifiedInfo::sendClickMessage( std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; LL_INFOS() << "body: [" << body << "]" << LL_ENDL; - LLHTTPClient::post(url, body, new LLClassifiedClickMessageResponder()); + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); } void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index cedd65c405..b292782615 100755 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -37,6 +37,8 @@ #include "llrect.h" #include "lluuid.h" #include "v3dmath.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLScrollContainer; class LLTextureCtrl; @@ -193,6 +195,9 @@ private: S32 mMapClicksNew; S32 mProfileClicksNew; + static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + + typedef std::list<LLPanelClassifiedInfo*> panel_list_t; static panel_list_t sAllPanels; }; diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp index fc4ee9862e..9d52a1906b 100644 --- a/indra/newview/llpanelexperiencelisteditor.cpp +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -183,7 +183,7 @@ void LLPanelExperienceListEditor::onItems() columns[0]["value"] = getString("loading"); mItems->addElement(item); - LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback, + LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback, getDerivedHandle<LLPanelExperienceListEditor>(), _1)); } diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp index df03ef7526..d5979b6e96 100644 --- a/indra/newview/llpanelexperiencelog.cpp +++ b/indra/newview/llpanelexperiencelog.cpp @@ -140,7 +140,7 @@ void LLPanelExperienceLog::refresh() } const LLSD event = dayArray[i]; LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID(); - const LLSD& experience = LLExperienceCache::get(id); + const LLSD& experience = LLExperienceCache::instance().get(id); if(experience.isUndefined()){ waiting = true; waiting_id = id; @@ -168,7 +168,7 @@ void LLPanelExperienceLog::refresh() { mEventList->deleteAllItems(); mEventList->setCommentText(getString("loading")); - LLExperienceCache::get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this)); + LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this)); } else { diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index 70d826a407..dcc5f4f234 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -58,41 +58,6 @@ const static std::string columnSpace = " "; static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker"); -class LLExperienceSearchResponder : public LLHTTPClient::Responder -{ -public: - LLUUID mQueryID; - LLHandle<LLPanelExperiencePicker> mParent; - - LLExperienceSearchResponder(const LLUUID& id, const LLHandle<LLPanelExperiencePicker>& parent) : mQueryID(id), mParent(parent) { } - -protected: - /*virtual*/ void httpSuccess() - { - if(mParent.isDead()) - return; - - LLPanelExperiencePicker* panel =mParent.get(); - if (panel) - { - panel->processResponse(mQueryID, getContent()); - } - } - - /*virtual*/ void httpFailure() - { - if(mParent.isDead()) - return; - - LLPanelExperiencePicker* panel =mParent.get(); - if (panel) - { - panel->processResponse(mQueryID, LLSD()); - } - LL_WARNS() << "experience picker failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL; - } -}; - LLPanelExperiencePicker::LLPanelExperiencePicker() :LLPanel() { @@ -163,17 +128,11 @@ void LLPanelExperiencePicker::find() { std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString(); mQueryID.generate(); - std::ostringstream url; - LLViewerRegion* region = gAgent.getRegion(); - std::string cap = region->getCapability("FindExperienceByName"); - if (!cap.empty()) - { - url << cap << "?page=" << mCurrentPage << "&page_size=30&query=" << LLURI::escape(text); - LLHTTPClient::get(url.str(), new LLExperienceSearchResponder(mQueryID, getDerivedHandle<LLPanelExperiencePicker>())); + LLExperienceCache::instance().findExperienceByName(text, mCurrentPage, + boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle<LLPanelExperiencePicker>(), mQueryID, _1)); - } - getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems(); + getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems(); getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching")); getChildView(BTN_OK)->setEnabled(FALSE); @@ -183,6 +142,19 @@ void LLPanelExperiencePicker::find() getChildView(BTN_LEFT)->setEnabled(FALSE); } +/*static*/ +void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult) +{ + if (hparent.isDead()) + return; + + LLPanelExperiencePicker* panel = hparent.get(); + if (panel) + { + panel->processResponse(queryId, foundResult); + } +} + bool LLPanelExperiencePicker::isSelectButtonEnabled() { @@ -233,13 +205,6 @@ void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLS mResponse = content; - const LLSD& experiences=mResponse["experience_keys"]; - LLSD::array_const_iterator it = experiences.beginArray(); - for ( ; it != experiences.endArray(); ++it) - { - LLExperienceCache::insert(*it); - } - getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url")); getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url")); diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h index e39ffed70b..97aa04cf4c 100644 --- a/indra/newview/llpanelexperiencepicker.h +++ b/indra/newview/llpanelexperiencepicker.h @@ -74,8 +74,9 @@ private: void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids ); void setAllowMultiple(bool allow_multiple); - void find(); + static void findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult); + bool isSelectButtonEnabled(); void processResponse( const LLUUID& query_id, const LLSD& content ); diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp index 76b68122fb..a88a55ab22 100644 --- a/indra/newview/llpanelgroupexperiences.cpp +++ b/indra/newview/llpanelgroupexperiences.cpp @@ -31,45 +31,16 @@ #include "lluictrlfactory.h" #include "roles_constants.h" -#include "llhttpclient.h" #include "llagent.h" #include "llviewerregion.h" #include "llflatlistview.h" #include "llpanelexperiences.h" #include "llsd.h" - +#include "llexperiencecache.h" static LLPanelInjector<LLPanelGroupExperiences> t_panel_group_experiences("panel_group_experiences"); -class LLGroupExperienceResponder : public LLHTTPClient::Responder -{ -public: - LLHandle<LLPanelGroupExperiences> mHandle; - - LLGroupExperienceResponder(LLHandle<LLPanelGroupExperiences> handle) : mHandle(handle) { } - -protected: - /*virtual*/ void httpSuccess() - { - if (mHandle.isDead()) - { - return; - } - - LLPanelGroupExperiences* panel = mHandle.get(); - if (panel) - { - panel->setExperienceList(getContent().get("experience_ids")); - } - } - - /*virtual*/ void httpFailure() - { - LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL; - } -}; - LLPanelGroupExperiences::LLPanelGroupExperiences() : LLPanelGroupTab(), mExperiencesList(NULL) { @@ -101,14 +72,8 @@ void LLPanelGroupExperiences::activate() return; } - // search for experiences owned by the current group - std::string url = gAgent.getRegion()->getCapability("GroupExperiences"); - if (!url.empty()) - { - url += "?" + getGroupID().asString(); - - LLHTTPClient::get(url, new LLGroupExperienceResponder(getDerivedHandle<LLPanelGroupExperiences>())); - } + LLExperienceCache::instance().getGroupExperiences(getGroupID(), + boost::bind(&LLPanelGroupExperiences::groupExperiencesResults, getDerivedHandle<LLPanelGroupExperiences>(), _1)); } void LLPanelGroupExperiences::setGroupID(const LLUUID& id) @@ -141,3 +106,19 @@ void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences) mExperiencesList->addItem(item, public_key); } } + +/*static*/ +void LLPanelGroupExperiences::groupExperiencesResults(LLHandle<LLPanelGroupExperiences> handle, const LLSD &experiences) +{ + if (handle.isDead()) + { + return; + } + + LLPanelGroupExperiences* panel = handle.get(); + if (panel) + { + panel->setExperienceList(experiences); + } + +} diff --git a/indra/newview/llpanelgroupexperiences.h b/indra/newview/llpanelgroupexperiences.h index ae1ecc1ac5..7c79f77332 100644 --- a/indra/newview/llpanelgroupexperiences.h +++ b/indra/newview/llpanelgroupexperiences.h @@ -48,6 +48,9 @@ public: protected: LLFlatListView* mExperiencesList; + +private: + static void groupExperiencesResults(LLHandle<LLPanelGroupExperiences>, const LLSD &); }; #endif diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 1d73d4bd6e..cd1dc0f070 100755 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -1352,17 +1352,8 @@ void LLLandmarksPanel::doCreatePick(LLLandmark* landmark) std::string url = region->getCapability("RemoteParcelRequest"); if (!url.empty()) { - body["location"] = ll_sd_from_vector3(region_pos); - if (!region_id.isNull()) - { - body["region_id"] = region_id; - } - if (!pos_global.isExactlyZero()) - { - U64 region_handle = to_region_handle(pos_global); - body["region_handle"] = ll_sd_from_U64(region_handle); - } - LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); + LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, + region_id, region_pos, pos_global, getObserverHandle()); } else { diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 953f234a53..360b144604 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -40,7 +40,6 @@ #include "llcheckboxctrl.h" #include "llcommandhandler.h" // for secondlife:///app/login/ #include "llcombobox.h" -#include "llcurl.h" #include "llviewercontrol.h" #include "llfloaterpreference.h" #include "llfocusmgr.h" @@ -59,7 +58,6 @@ #include "llviewernetwork.h" #include "llviewerwindow.h" // to link into child list #include "lluictrlfactory.h" -#include "llhttpclient.h" #include "llweb.h" #include "llmediactrl.h" #include "llrootview.h" @@ -436,17 +434,10 @@ void LLPanelLogin::show(const LLRect &rect, void (*callback)(S32 option, void* user_data), void* callback_data) { - // instance management - if (LLPanelLogin::sInstance) - { - LL_WARNS("AppInit") << "Duplicate instance of login view deleted" << LL_ENDL; - // Don't leave bad pointer in gFocusMgr - gFocusMgr.setDefaultKeyboardFocus(NULL); - - delete LLPanelLogin::sInstance; - } - - new LLPanelLogin(rect, callback, callback_data); + if (!LLPanelLogin::sInstance) + { + new LLPanelLogin(rect, callback, callback_data); + } if( !gFocusMgr.getKeyboardFocus() ) { diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp index cedd3025fc..55e4ffff5e 100755 --- a/indra/newview/llpanelme.cpp +++ b/indra/newview/llpanelme.cpp @@ -37,7 +37,6 @@ #include "llfloaterreg.h" #include "llhints.h" #include "llviewercontrol.h" -#include "llviewerdisplayname.h" // Linden libraries #include "llavatarnamecache.h" // IDEVO diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index e62b5a4f1d..cec56a7ae7 100755 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -45,6 +45,7 @@ #include "llpanelpick.h" #include "lltexturectrl.h" #include "llviewerregion.h" +#include "llhttpconstants.h" LLPanelPlaceInfo::LLPanelPlaceInfo() : LLPanel(), @@ -150,17 +151,8 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLUUID& region_id, std::string url = region->getCapability("RemoteParcelRequest"); if (!url.empty()) { - body["location"] = ll_sd_from_vector3(mPosRegion); - if (!region_id.isNull()) - { - body["region_id"] = region_id; - } - if (!pos_global.isExactlyZero()) - { - U64 region_handle = to_region_handle(pos_global); - body["region_handle"] = ll_sd_from_U64(region_handle); - } - LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); + LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, + region_id, mPosRegion, pos_global, getObserverHandle()); } else { diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index 8e37b1418c..e4f39aac04 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -40,6 +40,7 @@ #include "llpostcard.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewerwindow.h" +#include "llviewerregion.h" #include <boost/regex.hpp> @@ -67,7 +68,8 @@ private: /*virtual*/ void updateControls(const LLSD& info); bool missingSubjMsgAlertCallback(const LLSD& notification, const LLSD& response); - void sendPostcard(); + static void sendPostcardFinished(LLSD result); + void sendPostcard(); void onMsgFormFocusRecieved(); void onFormatComboCommit(LLUICtrl* ctrl); @@ -166,24 +168,44 @@ bool LLPanelSnapshotPostcard::missingSubjMsgAlertCallback(const LLSD& notificati } -void LLPanelSnapshotPostcard::sendPostcard() +void LLPanelSnapshotPostcard::sendPostcardFinished(LLSD result) { - std::string to(getChild<LLUICtrl>("to_form")->getValue().asString()); - std::string subject(getChild<LLUICtrl>("subject_form")->getValue().asString()); + LL_WARNS() << result << LL_ENDL; - LLSD postcard = LLSD::emptyMap(); - postcard["pos-global"] = LLFloaterSnapshot::getPosTakenGlobal().getValue(); - postcard["to"] = to; - postcard["from"] = mAgentEmail; - postcard["name"] = getChild<LLUICtrl>("name_form")->getValue().asString(); - postcard["subject"] = subject; - postcard["msg"] = getChild<LLUICtrl>("msg_form")->getValue().asString(); - LLPostCard::send(LLFloaterSnapshot::getImageData(), postcard); + std::string state = result["state"].asString(); - // Give user feedback of the event. - gViewerWindow->playSnapshotAnimAndSound(); + LLPostCard::reportPostResult((state == "complete")); +} - LLFloaterSnapshot::postSave(); + +void LLPanelSnapshotPostcard::sendPostcard() +{ + // upload the image + std::string url = gAgent.getRegion()->getCapability("SendPostcard"); + if (!url.empty()) + { + LLResourceUploadInfo::ptr_t uploadInfo(new LLPostcardUploadInfo( + mAgentEmail, + getChild<LLUICtrl>("name_form")->getValue().asString(), + getChild<LLUICtrl>("to_form")->getValue().asString(), + getChild<LLUICtrl>("subject_form")->getValue().asString(), + getChild<LLUICtrl>("msg_form")->getValue().asString(), + LLFloaterSnapshot::getPosTakenGlobal(), + LLFloaterSnapshot::getImageData(), + boost::bind(&LLPanelSnapshotPostcard::sendPostcardFinished, _4))); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + else + { + LL_WARNS() << "Postcards unavailable in this region." << LL_ENDL; + } + + + // Give user feedback of the event. + gViewerWindow->playSnapshotAnimAndSound(); + + LLFloaterSnapshot::postSave(); } void LLPanelSnapshotPostcard::onMsgFormFocusRecieved() diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 4977a72dc6..711a869e82 100755 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -39,7 +39,6 @@ #include <boost/signals2.hpp> #include "llagent.h" -#include "llhttpclient.h" #include "llhttpnode.h" #include "llnotificationsutil.h" #include "llpathfindingcharacterlist.h" @@ -55,6 +54,8 @@ #include "lluuid.h" #include "llviewerregion.h" #include "llweb.h" +#include "llcorehttputil.h" +#include "llworld.h" #define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc" @@ -98,82 +99,6 @@ public: LLHTTPRegistration<LLAgentStateChangeNode> gHTTPRegistrationAgentStateChangeNode(SIM_MESSAGE_AGENT_STATE_UPDATE); //--------------------------------------------------------------------------- -// NavMeshStatusResponder -//--------------------------------------------------------------------------- - -class NavMeshStatusResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(NavMeshStatusResponder); -public: - NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly); - virtual ~NavMeshStatusResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - LLViewerRegion *mRegion; - LLUUID mRegionUUID; - bool mIsGetStatusOnly; -}; - -//--------------------------------------------------------------------------- -// NavMeshResponder -//--------------------------------------------------------------------------- - -class NavMeshResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(NavMeshResponder); -public: - NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); - virtual ~NavMeshResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - U32 mNavMeshVersion; - LLPathfindingNavMeshPtr mNavMeshPtr; -}; - -//--------------------------------------------------------------------------- -// AgentStateResponder -//--------------------------------------------------------------------------- - -class AgentStateResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(AgentStateResponder); -public: - AgentStateResponder(); - virtual ~AgentStateResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); -}; - - -//--------------------------------------------------------------------------- -// NavMeshRebakeResponder -//--------------------------------------------------------------------------- -class NavMeshRebakeResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(NavMeshRebakeResponder); -public: - NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); - virtual ~NavMeshRebakeResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback; -}; - -//--------------------------------------------------------------------------- // LinksetsResponder //--------------------------------------------------------------------------- @@ -188,6 +113,8 @@ public: void handleTerrainLinksetsResult(const LLSD &pContent); void handleTerrainLinksetsError(); + typedef boost::shared_ptr<LinksetsResponder> ptr_t; + protected: private: @@ -214,64 +141,6 @@ private: typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr; //--------------------------------------------------------------------------- -// ObjectLinksetsResponder -//--------------------------------------------------------------------------- - -class ObjectLinksetsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(ObjectLinksetsResponder); -public: - ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); - virtual ~ObjectLinksetsResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - LinksetsResponderPtr mLinksetsResponsderPtr; -}; - -//--------------------------------------------------------------------------- -// TerrainLinksetsResponder -//--------------------------------------------------------------------------- - -class TerrainLinksetsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(TerrainLinksetsResponder); -public: - TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); - virtual ~TerrainLinksetsResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - LinksetsResponderPtr mLinksetsResponsderPtr; -}; - -//--------------------------------------------------------------------------- -// CharactersResponder -//--------------------------------------------------------------------------- - -class CharactersResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(TerrainLinksetsResponder); -public: - CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); - virtual ~CharactersResponder(); - -protected: - virtual void httpSuccess(); - virtual void httpFailure(); - -private: - LLPathfindingManager::request_id_t mRequestId; - LLPathfindingManager::object_request_callback_t mCharactersCallback; -}; - -//--------------------------------------------------------------------------- // LLPathfindingManager //--------------------------------------------------------------------------- @@ -350,11 +219,13 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b } else { - std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); - llassert(!navMeshStatusURL.empty()); - navMeshPtr->handleNavMeshCheckVersion(); - LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly); - LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); + std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); + llassert(!navMeshStatusURL.empty()); + navMeshPtr->handleNavMeshCheckVersion(); + + U64 regionHandle = pRegion->getHandle(); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshStatusRequestCoro", + boost::bind(&LLPathfindingManager::navMeshStatusRequestCoro, this, navMeshStatusURL, regionHandle, pIsGetStatusOnly)); } } @@ -385,15 +256,15 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr); bool doRequestTerrain = isAllowViewTerrainProperties(); - LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); + LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); - LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro", + boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, LLSD())); - if (doRequestTerrain) + if (doRequestTerrain) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); - LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro", + boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, LLSD())); } } } @@ -432,18 +303,18 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP { pLinksetsCallback(pRequestId, kRequestStarted, emptyLinksetListPtr); - LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined())); + LinksetsResponder::ptr_t linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined())); if (!objectPostData.isUndefined()) { - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); - LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetObjectsCoro", + boost::bind(&LLPathfindingManager::linksetObjectsCoro, this, objectLinksetsURL, linksetsResponderPtr, objectPostData)); } if (!terrainPostData.isUndefined()) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); - LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::linksetTerrainCoro", + boost::bind(&LLPathfindingManager::linksetTerrainCoro, this, terrainLinksetsURL, linksetsResponderPtr, terrainPostData)); } } } @@ -475,8 +346,8 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ { pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); - LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback); - LLHTTPClient::get(charactersURL, charactersResponder); + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::charactersCoro", + boost::bind(&LLPathfindingManager::charactersCoro, this, charactersURL, pRequestId, pCharactersCallback)); } } } @@ -508,8 +379,9 @@ void LLPathfindingManager::requestGetAgentState() { std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); - LLHTTPClient::ResponderPtr responder = new AgentStateResponder(); - LLHTTPClient::get(agentStateURL, responder); + + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navAgentStateRequestCoro", + boost::bind(&LLPathfindingManager::navAgentStateRequestCoro, this, agentStateURL)); } } } @@ -530,35 +402,9 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak { std::string navMeshStatusURL = getNavMeshStatusURLForCurrentRegion(); llassert(!navMeshStatusURL.empty()); - LLSD postData; - postData["command"] = "rebuild"; - LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback); - LLHTTPClient::post(navMeshStatusURL, postData, responder); - } -} - -void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus) -{ - if ((pRegion == NULL) || !pRegion->isAlive()) - { - navMeshPtr->handleNavMeshNotEnabled(); - } - else - { - std::string navMeshURL = getRetrieveNavMeshURLForRegion(pRegion); - - if (navMeshURL.empty()) - { - navMeshPtr->handleNavMeshNotEnabled(); - } - else - { - navMeshPtr->handleNavMeshStart(pNavMeshStatus); - LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr); - LLSD postData; - LLHTTPClient::post(navMeshURL, postData, responder); - } + std::string coroname = LLCoros::instance().launch("LLPathfindingManager::navMeshRebakeCoro", + boost::bind(&LLPathfindingManager::navMeshRebakeCoro, this, navMeshStatusURL, pRebakeNavMeshCallback)); } } @@ -602,29 +448,250 @@ void LLPathfindingManager::handleDeferredGetCharactersForRegion(const LLUUID &pR } } -void LLPathfindingManager::handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly) +void LLPathfindingManager::navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly) { - LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(pNavMeshStatus.getRegionUUID()); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshStatusRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLViewerRegion *region = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!region) + { + LL_WARNS("PathfindingManager") << "Attempting to retrieve navmesh status for region that has gone away." << LL_ENDL; + return; + } + LLUUID regionUUID = region->getRegionID(); + + region = NULL; + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + region = LLWorld::getInstance()->getRegionFromHandle(regionHandle); - if (!pNavMeshStatus.isValid()) - { - navMeshPtr->handleNavMeshError(); - } - else - { - if (navMeshPtr->hasNavMeshVersion(pNavMeshStatus)) - { - navMeshPtr->handleRefresh(pNavMeshStatus); - } - else if (pIsGetStatusOnly) - { - navMeshPtr->handleNavMeshNewVersion(pNavMeshStatus); - } - else - { - sendRequestGetNavMeshForRegion(navMeshPtr, pRegion, pNavMeshStatus); - } - } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLPathfindingNavMeshStatus navMeshStatus(regionUUID); + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". Building using empty status." << LL_ENDL; + } + else + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + navMeshStatus = LLPathfindingNavMeshStatus(regionUUID, result); + } + + LLPathfindingNavMeshPtr navMeshPtr = getNavMeshForRegion(regionUUID); + + if (!navMeshStatus.isValid()) + { + navMeshPtr->handleNavMeshError(); + return; + } + else if (navMeshPtr->hasNavMeshVersion(navMeshStatus)) + { + navMeshPtr->handleRefresh(navMeshStatus); + return; + } + else if (isGetStatusOnly) + { + navMeshPtr->handleNavMeshNewVersion(navMeshStatus); + return; + } + + if ((!region) || !region->isAlive()) + { + LL_WARNS("PathfindingManager") << "About to update navmesh status for region that has gone away." << LL_ENDL; + navMeshPtr->handleNavMeshNotEnabled(); + return; + } + + std::string navMeshURL = getRetrieveNavMeshURLForRegion(region); + + if (navMeshURL.empty()) + { + navMeshPtr->handleNavMeshNotEnabled(); + return; + } + + navMeshPtr->handleNavMeshStart(navMeshStatus); + + LLSD postData; + result = httpAdapter->postAndSuspend(httpRequest, navMeshURL, postData); + + U32 navMeshVersion = navMeshStatus.getVersion(); + + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". reporting error." << LL_ENDL; + navMeshPtr->handleNavMeshError(navMeshVersion); + } + else + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + navMeshPtr->handleNavMeshResult(result, navMeshVersion); + + } + +} + +void LLPathfindingManager::navAgentStateRequestCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavAgentStateRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + bool canRebake = false; + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". Building using empty status." << LL_ENDL; + } + else + { + llassert(result.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); + llassert(result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); + canRebake = result.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); + } + + handleAgentState(canRebake); +} + +void LLPathfindingManager::navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("NavMeshRebake", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + + LLSD postData = LLSD::emptyMap(); + postData["command"] = "rebuild"; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + bool success = true; + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". Rebake failed." << LL_ENDL; + success = false; + } + + rebakeNavMeshCallback(success); +} + +// If called with putData undefined this coroutine will issue a get. If there +// is data in putData it will be PUT to the URL. +void LLPathfindingManager::linksetObjectsCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetObjects", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result; + + if (putData.isUndefined()) + { + result = httpAdapter->getAndSuspend(httpRequest, url); + } + else + { + result = httpAdapter->putAndSuspend(httpRequest, url, putData); + } + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". linksetObjects failed." << LL_ENDL; + linksetsResponsderPtr->handleObjectLinksetsError(); + } + else + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + linksetsResponsderPtr->handleObjectLinksetsResult(result); + } +} + +// If called with putData undefined this coroutine will issue a GET. If there +// is data in putData it will be PUT to the URL. +void LLPathfindingManager::linksetTerrainCoro(std::string url, LinksetsResponder::ptr_t linksetsResponsderPtr, LLSD putData) const +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result; + + if (putData.isUndefined()) + { + result = httpAdapter->getAndSuspend(httpRequest, url); + } + else + { + result = httpAdapter->putAndSuspend(httpRequest, url, putData); + } + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". linksetTerrain failed." << LL_ENDL; + linksetsResponsderPtr->handleTerrainLinksetsError(); + } + else + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + linksetsResponsderPtr->handleTerrainLinksetsResult(result); + } + +} + +void LLPathfindingManager::charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("LinksetTerrain", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("PathfindingManager") << "HTTP status, " << status.toTerseString() << + ". characters failed." << LL_ENDL; + + LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); + callback(requestId, LLPathfindingManager::kRequestError, characterListPtr); + } + else + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(result)); + callback(requestId, LLPathfindingManager::kRequestCompleted, characterListPtr); + } } void LLPathfindingManager::handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus) @@ -765,121 +832,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c } //--------------------------------------------------------------------------- -// NavMeshStatusResponder -//--------------------------------------------------------------------------- - -NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly) - : LLHTTPClient::Responder(), - mRegion(pRegion), - mRegionUUID(), - mIsGetStatusOnly(pIsGetStatusOnly) -{ - if (mRegion != NULL) - { - mRegionUUID = mRegion->getRegionID(); - } -} - -NavMeshStatusResponder::~NavMeshStatusResponder() -{ -} - -void NavMeshStatusResponder::httpSuccess() -{ - LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent()); - LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); -} - -void NavMeshStatusResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID); - LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); -} - -//--------------------------------------------------------------------------- -// NavMeshResponder -//--------------------------------------------------------------------------- - -NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) - : LLHTTPClient::Responder(), - mNavMeshVersion(pNavMeshVersion), - mNavMeshPtr(pNavMeshPtr) -{ -} - -NavMeshResponder::~NavMeshResponder() -{ -} - -void NavMeshResponder::httpSuccess() -{ - mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion); -} - -void NavMeshResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - mNavMeshPtr->handleNavMeshError(mNavMeshVersion); -} - -//--------------------------------------------------------------------------- -// AgentStateResponder -//--------------------------------------------------------------------------- - -AgentStateResponder::AgentStateResponder() -: LLHTTPClient::Responder() -{ -} - -AgentStateResponder::~AgentStateResponder() -{ -} - -void AgentStateResponder::httpSuccess() -{ - const LLSD& pContent = getContent(); - llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); - llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); - BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); - LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion); -} - -void AgentStateResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - LLPathfindingManager::getInstance()->handleAgentState(FALSE); -} - - -//--------------------------------------------------------------------------- -// navmesh rebake responder -//--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) - : LLHTTPClient::Responder(), - mRebakeNavMeshCallback(pRebakeNavMeshCallback) -{ -} - -NavMeshRebakeResponder::~NavMeshRebakeResponder() -{ -} - -void NavMeshRebakeResponder::httpSuccess() -{ - mRebakeNavMeshCallback(true); -} - -void NavMeshRebakeResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - mRebakeNavMeshCallback(false); -} - -//--------------------------------------------------------------------------- // LinksetsResponder //--------------------------------------------------------------------------- - LinksetsResponder::LinksetsResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested) : mRequestId(pRequestId), mLinksetsCallback(pLinksetsCallback), @@ -957,82 +911,3 @@ void LinksetsResponder::sendCallback() mLinksetsCallback(mRequestId, requestStatus, mObjectLinksetListPtr); } - -//--------------------------------------------------------------------------- -// ObjectLinksetsResponder -//--------------------------------------------------------------------------- - -ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) - : LLHTTPClient::Responder(), - mLinksetsResponsderPtr(pLinksetsResponsderPtr) -{ -} - -ObjectLinksetsResponder::~ObjectLinksetsResponder() -{ -} - -void ObjectLinksetsResponder::httpSuccess() -{ - mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent()); -} - -void ObjectLinksetsResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - mLinksetsResponsderPtr->handleObjectLinksetsError(); -} - -//--------------------------------------------------------------------------- -// TerrainLinksetsResponder -//--------------------------------------------------------------------------- - -TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) - : LLHTTPClient::Responder(), - mLinksetsResponsderPtr(pLinksetsResponsderPtr) -{ -} - -TerrainLinksetsResponder::~TerrainLinksetsResponder() -{ -} - -void TerrainLinksetsResponder::httpSuccess() -{ - mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent()); -} - -void TerrainLinksetsResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - mLinksetsResponsderPtr->handleTerrainLinksetsError(); -} - -//--------------------------------------------------------------------------- -// CharactersResponder -//--------------------------------------------------------------------------- - -CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) - : LLHTTPClient::Responder(), - mRequestId(pRequestId), - mCharactersCallback(pCharactersCallback) -{ -} - -CharactersResponder::~CharactersResponder() -{ -} - -void CharactersResponder::httpSuccess() -{ - LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent())); - mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr); -} - -void CharactersResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - - LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); - mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); -} diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h index c61ff244fc..e8fad590ba 100755 --- a/indra/newview/llpathfindingmanager.h +++ b/indra/newview/llpathfindingmanager.h @@ -37,11 +37,15 @@ #include "llpathfindingobjectlist.h" #include "llpathfindingnavmesh.h" #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLPathfindingNavMeshStatus; class LLUUID; class LLViewerRegion; +class LinksetsResponder; + class LLPathfindingManager : public LLSingleton<LLPathfindingManager> { friend class LLNavMeshSimStateChangeNode; @@ -92,16 +96,22 @@ public: protected: private: - typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap; - void sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPtr navMeshPtr, LLViewerRegion *pRegion, const LLPathfindingNavMeshStatus &pNavMeshStatus); + typedef std::map<LLUUID, LLPathfindingNavMeshPtr> NavMeshMap; void handleDeferredGetAgentStateForRegion(const LLUUID &pRegionUUID); void handleDeferredGetNavMeshForRegion(const LLUUID &pRegionUUID, bool pIsGetStatusOnly); void handleDeferredGetLinksetsForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pLinksetsCallback) const; void handleDeferredGetCharactersForRegion(const LLUUID &pRegionUUID, request_id_t pRequestId, object_request_callback_t pCharactersCallback) const; - void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly); + void navMeshStatusRequestCoro(std::string url, U64 regionHandle, bool isGetStatusOnly); + void navAgentStateRequestCoro(std::string url); + void navMeshRebakeCoro(std::string url, rebake_navmesh_callback_t rebakeNavMeshCallback); + void linksetObjectsCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const; + void linksetTerrainCoro(std::string url, boost::shared_ptr<LinksetsResponder> linksetsResponsderPtr, LLSD putData) const; + void charactersCoro(std::string url, request_id_t requestId, object_request_callback_t callback) const; + + //void handleNavMeshStatusRequest(const LLPathfindingNavMeshStatus &pNavMeshStatus, LLViewerRegion *pRegion, bool pIsGetStatusOnly); void handleNavMeshStatusUpdate(const LLPathfindingNavMeshStatus &pNavMeshStatus); void handleAgentState(BOOL pCanRebakeRegion); diff --git a/indra/newview/llpostcard.cpp b/indra/newview/llpostcard.cpp index 5987044bff..2e639b56eb 100755 --- a/indra/newview/llpostcard.cpp +++ b/indra/newview/llpostcard.cpp @@ -36,84 +36,36 @@ #include "llagent.h" #include "llassetstorage.h" -#include "llassetuploadresponders.h" +#include "llviewerassetupload.h" /////////////////////////////////////////////////////////////////////////////// -// misc -static void postcard_upload_callback(const LLUUID& asset_id, void *user_data, S32 result, LLExtStat ext_status) +LLPostcardUploadInfo::LLPostcardUploadInfo(std::string emailFrom, std::string nameFrom, std::string emailTo, + std::string subject, std::string message, LLVector3d globalPosition, + LLPointer<LLImageFormatted> image, invnUploadFinish_f finish) : + LLBufferedAssetUploadInfo(LLUUID::null, image, finish), + mEmailFrom(emailFrom), + mNameFrom(nameFrom), + mEmailTo(emailTo), + mSubject(subject), + mMessage(message), + mGlobalPosition(globalPosition) { - LLSD* postcard_data = (LLSD*)user_data; - - if (result) - { - // TODO: display the error messages in UI - LL_WARNS() << "Failed to send postcard: " << LLAssetStorage::getErrorString(result) << LL_ENDL; - LLPostCard::reportPostResult(false); - } - else - { - // only create the postcard once the upload succeeds - - // request the postcard - const LLSD& data = *postcard_data; - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("SendPostcard"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUID("AssetID", data["asset-id"].asUUID()); - msg->addVector3d("PosGlobal", LLVector3d(data["pos-global"])); - msg->addString("To", data["to"]); - msg->addString("From", data["from"]); - msg->addString("Name", data["name"]); - msg->addString("Subject", data["subject"]); - msg->addString("Msg", data["msg"]); - msg->addBOOL("AllowPublish", FALSE); - msg->addBOOL("MaturePublish", FALSE); - gAgent.sendReliableMessage(); - - LLPostCard::reportPostResult(true); - } - - delete postcard_data; } - -/////////////////////////////////////////////////////////////////////////////// -// LLPostcardSendResponder - -class LLPostcardSendResponder : public LLAssetUploadResponder +LLSD LLPostcardUploadInfo::generatePostBody() { - LOG_CLASS(LLPostcardSendResponder); - -public: - LLPostcardSendResponder(const LLSD &post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type): - LLAssetUploadResponder(post_data, vfile_id, asset_type) - { - } - - /*virtual*/ void httpFailure() - { - LL_WARNS() << "Sending postcard failed, status: " << getStatus() << LL_ENDL; - LLPostCard::reportPostResult(false); - } - - /*virtual*/ void uploadComplete(const LLSD& content) - { - LL_INFOS() << "Postcard sent" << LL_ENDL; - LL_DEBUGS("Snapshots") << "content: " << content << LL_ENDL; - LLPostCard::reportPostResult(true); - } + LLSD postcard = LLSD::emptyMap(); + postcard["pos-global"] = mGlobalPosition.getValue(); + postcard["to"] = mEmailTo; + postcard["from"] = mEmailFrom; + postcard["name"] = mNameFrom; + postcard["subject"] = mSubject; + postcard["msg"] = mMessage; + + return postcard; +} - /*virtual*/ void uploadFailure(const LLSD& content) - { - LL_WARNS() << "Sending postcard failed: " << content << LL_ENDL; - LLPostCard::reportPostResult(false); - } -}; /////////////////////////////////////////////////////////////////////////////// // LLPostCard @@ -121,38 +73,6 @@ public: LLPostCard::result_callback_t LLPostCard::mResultCallback; // static -void LLPostCard::send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data) -{ - LLTransactionID transaction_id; - LLAssetID asset_id; - - transaction_id.generate(); - asset_id = transaction_id.makeAssetID(gAgent.getSecureSessionID()); - LLVFile::writeFile(image->getData(), image->getDataSize(), gVFS, asset_id, LLAssetType::AT_IMAGE_JPEG); - - // upload the image - std::string url = gAgent.getRegion()->getCapability("SendPostcard"); - if (!url.empty()) - { - LL_INFOS() << "Sending postcard via capability" << LL_ENDL; - // the capability already encodes: agent ID, region ID - LL_DEBUGS("Snapshots") << "url: " << url << LL_ENDL; - LL_DEBUGS("Snapshots") << "body: " << postcard_data << LL_ENDL; - LL_DEBUGS("Snapshots") << "data size: " << image->getDataSize() << LL_ENDL; - LLHTTPClient::post(url, postcard_data, - new LLPostcardSendResponder(postcard_data, asset_id, LLAssetType::AT_IMAGE_JPEG)); - } - else - { - LL_INFOS() << "Sending postcard" << LL_ENDL; - LLSD* data = new LLSD(postcard_data); - (*data)["asset-id"] = asset_id; - gAssetStorage->storeAssetData(transaction_id, LLAssetType::AT_IMAGE_JPEG, - &postcard_upload_callback, (void *)data, FALSE); - } -} - -// static void LLPostCard::reportPostResult(bool ok) { if (mResultCallback) diff --git a/indra/newview/llpostcard.h b/indra/newview/llpostcard.h index 0eb118b906..24157be636 100755 --- a/indra/newview/llpostcard.h +++ b/indra/newview/llpostcard.h @@ -29,7 +29,12 @@ #include "llimage.h" #include "lluuid.h" +#include "llviewerassetupload.h" +/// *TODO$: this LLPostCard class is a hold over and should be removed. Right now +/// all it does is hold a pointer to a call back function which is invoked by +/// llpanelsnapshotpostcard's finish function. (and all that call back does is +/// set the status in the floater. class LLPostCard { LOG_CLASS(LLPostCard); @@ -37,7 +42,6 @@ class LLPostCard public: typedef boost::function<void(bool ok)> result_callback_t; - static void send(LLPointer<LLImageFormatted> image, const LLSD& postcard_data); static void setPostResultCallback(result_callback_t cb) { mResultCallback = cb; } static void reportPostResult(bool ok); @@ -45,4 +49,24 @@ private: static result_callback_t mResultCallback; }; + +class LLPostcardUploadInfo : public LLBufferedAssetUploadInfo +{ +public: + LLPostcardUploadInfo(std::string emailFrom, std::string nameFrom, std::string emailTo, + std::string subject, std::string message, LLVector3d globalPosition, + LLPointer<LLImageFormatted> image, invnUploadFinish_f finish); + + virtual LLSD generatePostBody(); +private: + std::string mEmailFrom; + std::string mNameFrom; + std::string mEmailTo; + std::string mSubject; + std::string mMessage; + LLVector3d mGlobalPosition; + +}; + + #endif // LL_LLPOSTCARD_H diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index c378738b05..ff9a70d05c 100755 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -31,7 +31,6 @@ #include "llanimstatelabels.h" #include "llanimationstates.h" #include "llappviewer.h" // gVFS -#include "llassetuploadresponders.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldatapacker.h" @@ -52,6 +51,7 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerassetupload.h" std::string NONE_LABEL; std::string SHIFT_LABEL; @@ -1015,6 +1015,27 @@ struct LLSaveInfo }; +void LLPreviewGesture::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId) +{ + // If this gesture is active, then we need to update the in-memory + // active map with the new pointer. + if (LLGestureMgr::instance().isGestureActive(itemId)) + { + //*TODO: This is crashing for some reason. Fix it. + // Active gesture edited from menu. + LLGestureMgr::instance().replaceGesture(itemId, newAssetId); + gInventory.notifyObservers(); + } + + //gesture will have a new asset_id + LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance<LLPreviewGesture>("preview_gesture", LLSD(itemId)); + if (previewp) + { + previewp->onUpdateSucceeded(); + } +} + + void LLPreviewGesture::saveIfNeeded() { if (!gAssetStorage) @@ -1028,116 +1049,127 @@ void LLPreviewGesture::saveIfNeeded() return; } - // Copy the UI into a gesture - LLMultiGesture* gesture = createGesture(); - - // Serialize the gesture - S32 max_size = gesture->getMaxSerialSize(); - char* buffer = new char[max_size]; - - LLDataPackerAsciiBuffer dp(buffer, max_size); - - BOOL ok = gesture->serialize(dp); - - if (dp.getCurrentSize() > 1000) - { - LLNotificationsUtil::add("GestureSaveFailedTooManySteps"); - - delete gesture; - gesture = NULL; - } - else if (!ok) - { - LLNotificationsUtil::add("GestureSaveFailedTryAgain"); - delete gesture; - gesture = NULL; - } - else - { - LLPreview::onCommit(); - - // Every save gets a new UUID. Yup. - LLTransactionID tid; - LLAssetID asset_id; - tid.generate(); - asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - LLVFile file(gVFS, asset_id, LLAssetType::AT_GESTURE, LLVFile::APPEND); - - S32 size = dp.getCurrentSize(); - file.setMaxSize(size); - file.write((U8*)buffer, size); - - BOOL delayedUpload = FALSE; - - // Upload that asset to the database - LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem(); - if (item) - { - std::string agent_url = gAgent.getRegion()->getCapability("UpdateGestureAgentInventory"); - std::string task_url = gAgent.getRegion()->getCapability("UpdateGestureTaskInventory"); - if (mObjectUUID.isNull() && !agent_url.empty()) - { - //need to disable the preview floater so item - //isn't re-saved before new asset arrives - //fake out refresh. - item->setComplete(FALSE); - refresh(); - item->setComplete(TRUE); - - // Saving into agent inventory - LLSD body; - body["item_id"] = mItemUUID; - LLHTTPClient::post(agent_url, body, - new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); - delayedUpload = TRUE; - } - else if (!mObjectUUID.isNull() && !task_url.empty()) - { - // Saving into task inventory - LLSD body; - body["task_id"] = mObjectUUID; - body["item_id"] = mItemUUID; - LLHTTPClient::post(task_url, body, - new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_GESTURE)); - } - else if (gAssetStorage) - { - LLLineEditor* descEditor = getChild<LLLineEditor>("desc"); - LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid); - gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE); - } - } - - // If this gesture is active, then we need to update the in-memory - // active map with the new pointer. - if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID)) - { - // gesture manager now owns the pointer - LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, asset_id); - - // replaceGesture may deactivate other gestures so let the - // inventory know. - gInventory.notifyObservers(); - } - else - { - // we're done with this gesture - delete gesture; - gesture = NULL; - } - - mDirty = FALSE; - // refresh will be called when callback - // if triggered when delayedUpload - if(!delayedUpload) - { - refresh(); - } - } + // Copy the UI into a gesture + LLMultiGesture* gesture = createGesture(); + + // Serialize the gesture + S32 maxSize = gesture->getMaxSerialSize(); + char* buffer = new char[maxSize]; + + LLDataPackerAsciiBuffer dp(buffer, maxSize); + + bool ok = gesture->serialize(dp); + + if (dp.getCurrentSize() > 1000) + { + LLNotificationsUtil::add("GestureSaveFailedTooManySteps"); + + delete gesture; + gesture = NULL; + return; + } + else if (!ok) + { + LLNotificationsUtil::add("GestureSaveFailedTryAgain"); + delete gesture; + gesture = NULL; + return; + } + + LLAssetID assetId; + LLPreview::onCommit(); + bool delayedUpload(false); + + LLViewerInventoryItem* item = (LLViewerInventoryItem*) getItem(); + if (item) + { + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL; + return; + } + std::string agent_url = region->getCapability("UpdateGestureAgentInventory"); + std::string task_url = region->getCapability("UpdateGestureTaskInventory"); + + if (!agent_url.empty() && !task_url.empty()) + { + std::string url; + LLResourceUploadInfo::ptr_t uploadInfo; + + if (mObjectUUID.isNull() && !agent_url.empty()) + { + //need to disable the preview floater so item + //isn't re-saved before new asset arrives + //fake out refresh. + item->setComplete(false); + refresh(); + item->setComplete(true); + + uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_GESTURE, buffer, + boost::bind(&LLPreviewGesture::finishInventoryUpload, _1, _2))); + url = agent_url; + } + else if (!mObjectUUID.isNull() && !task_url.empty()) + { + uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_GESTURE, buffer, NULL)); + url = task_url; + } + + if (!url.empty() && uploadInfo) + { + delayedUpload = true; + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + + } + else if (gAssetStorage) + { + // Every save gets a new UUID. Yup. + LLTransactionID tid; + tid.generate(); + assetId = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLVFile file(gVFS, assetId, LLAssetType::AT_GESTURE, LLVFile::APPEND); + + S32 size = dp.getCurrentSize(); + file.setMaxSize(size); + file.write((U8*)buffer, size); + + LLLineEditor* descEditor = getChild<LLLineEditor>("desc"); + LLSaveInfo* info = new LLSaveInfo(mItemUUID, mObjectUUID, descEditor->getText(), tid); + gAssetStorage->storeAssetData(tid, LLAssetType::AT_GESTURE, onSaveComplete, info, FALSE); + } + + } + + // If this gesture is active, then we need to update the in-memory + // active map with the new pointer. + if (!delayedUpload && LLGestureMgr::instance().isGestureActive(mItemUUID)) + { + // gesture manager now owns the pointer + LLGestureMgr::instance().replaceGesture(mItemUUID, gesture, assetId); + + // replaceGesture may deactivate other gestures so let the + // inventory know. + gInventory.notifyObservers(); + } + else + { + // we're done with this gesture + delete gesture; + gesture = NULL; + } + + mDirty = false; + // refresh will be called when callback + // if triggered when delayedUpload + if(!delayedUpload) + { + refresh(); + } - delete [] buffer; - buffer = NULL; } diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index 7ce5706a0d..3ba4f56295 100755 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -132,6 +132,7 @@ protected: static void onDonePreview(LLMultiGesture* gesture, void* data); + static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId); private: // LLPreview contains mDescEditor LLLineEditor* mTriggerEditor; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 9f88b0db5f..af56fe367e 100755 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -31,7 +31,6 @@ #include "llinventory.h" #include "llagent.h" -#include "llassetuploadresponders.h" #include "lldraghandle.h" #include "llviewerwindow.h" #include "llbutton.h" @@ -56,6 +55,7 @@ #include "llappviewer.h" // app_abort_quit() #include "lllineeditor.h" #include "lluictrlfactory.h" +#include "llviewerassetupload.h" ///---------------------------------------------------------------------------- /// Class LLPreviewNotecard @@ -232,7 +232,7 @@ void LLPreviewNotecard::loadAsset() } else { - LLHost source_sim = LLHost::invalid; + LLHost source_sim = LLHost(); if (mObjectUUID.notNull()) { LLViewerObject *objectp = gObjectList.findObject(mObjectUUID); @@ -401,6 +401,35 @@ struct LLSaveNotecardInfo } }; +void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId) +{ + // Update the UI with the new asset. + LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", LLSD(itemId)); + if (nc) + { + // *HACK: we have to delete the asset in the VFS so + // that the viewer will redownload it. This is only + // really necessary if the asset had to be modified by + // the uploader, so this can be optimized away in some + // cases. A better design is to have a new uuid if the + // script actually changed the asset. + if (nc->hasEmbeddedInventory()) + { + gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); + } + if (newItemId.isNull()) + { + nc->setAssetId(newAssetId); + nc->refreshFromInventory(); + } + else + { + nc->refreshFromInventory(newItemId); + } + } +} + + bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) { LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("Notecard Editor"); @@ -413,14 +442,6 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) if(!editor->isPristine()) { - // We need to update the asset information - LLTransactionID tid; - LLAssetID asset_id; - tid.generate(); - asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND); - std::string buffer; if (!editor->exportBuffer(buffer)) { @@ -429,52 +450,64 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) editor->makePristine(); - S32 size = buffer.length() + 1; - file.setMaxSize(size); - file.write((U8*)buffer.c_str(), size); - const LLInventoryItem* item = getItem(); // save it out to database - if (item) - { - const LLViewerRegion* region = gAgent.getRegion(); - if (!region) - { - LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL; - return false; - } - std::string agent_url = region->getCapability("UpdateNotecardAgentInventory"); - std::string task_url = region->getCapability("UpdateNotecardTaskInventory"); - - if (mObjectUUID.isNull() && !agent_url.empty()) - { - // Saving into agent inventory - mAssetStatus = PREVIEW_ASSET_LOADING; - setEnabled(FALSE); - LLSD body; - body["item_id"] = mItemUUID; - LL_INFOS() << "Saving notecard " << mItemUUID - << " into agent inventory via " << agent_url << LL_ENDL; - LLHTTPClient::post(agent_url, body, - new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); - } - else if (!mObjectUUID.isNull() && !task_url.empty()) - { - // Saving into task inventory - mAssetStatus = PREVIEW_ASSET_LOADING; - setEnabled(FALSE); - LLSD body; - body["task_id"] = mObjectUUID; - body["item_id"] = mItemUUID; - LL_INFOS() << "Saving notecard " << mItemUUID << " into task " - << mObjectUUID << " via " << task_url << LL_ENDL; - LLHTTPClient::post(task_url, body, - new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); - } + if (item) + { + const LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + LL_WARNS() << "Not connected to a region, cannot save notecard." << LL_ENDL; + return false; + } + std::string agent_url = region->getCapability("UpdateNotecardAgentInventory"); + std::string task_url = region->getCapability("UpdateNotecardTaskInventory"); + + if (!agent_url.empty() && !task_url.empty()) + { + std::string url; + LLResourceUploadInfo::ptr_t uploadInfo; + + if (mObjectUUID.isNull() && !agent_url.empty()) + { + uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mItemUUID, LLAssetType::AT_NOTECARD, buffer, + boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _2, _3))); + url = agent_url; + } + else if (!mObjectUUID.isNull() && !task_url.empty()) + { + uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer, + boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _3, LLUUID::null))); + url = task_url; + } + + if (!url.empty() && uploadInfo) + { + mAssetStatus = PREVIEW_ASSET_LOADING; + setEnabled(false); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + + } else if (gAssetStorage) { + // We need to update the asset information + LLTransactionID tid; + LLAssetID asset_id; + tid.generate(); + asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLVFile file(gVFS, asset_id, LLAssetType::AT_NOTECARD, LLVFile::APPEND); + + LLSaveNotecardInfo* info = new LLSaveNotecardInfo(this, mItemUUID, mObjectUUID, tid, copyitem); + + S32 size = buffer.length() + 1; + file.setMaxSize(size); + file.write((U8*)buffer.c_str(), size); + gAssetStorage->storeAssetData(tid, LLAssetType::AT_NOTECARD, &onSaveComplete, (void*)info, diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index 1cf08dedd6..ba571995f6 100755 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -95,6 +95,8 @@ protected: bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); bool handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response); + static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId); + protected: LLViewerTextEditor* mEditor; LLButton* mSaveBtn; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 1bbb22416d..5f029ca6a2 100755 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -29,7 +29,6 @@ #include "llpreviewscript.h" #include "llassetstorage.h" -#include "llassetuploadresponders.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -88,7 +87,7 @@ #include "llfloatergotoline.h" #include "llexperiencecache.h" #include "llfloaterexperienceprofile.h" -#include "llexperienceassociationresponder.h" +#include "llviewerassetupload.h" const std::string HELLO_LSL = "default\n" @@ -118,26 +117,6 @@ static bool have_script_upload_cap(LLUUID& object_id) return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty()); } - -class ExperienceResponder : public LLHTTPClient::Responder -{ -public: - ExperienceResponder(const LLHandle<LLLiveLSLEditor>& parent):mParent(parent) - { - } - - LLHandle<LLLiveLSLEditor> mParent; - - /*virtual*/ void httpSuccess() - { - LLLiveLSLEditor* parent = mParent.get(); - if(!parent) - return; - - parent->setExperienceIds(getContent()["experience_ids"]); - } -}; - /// --------------------------------------------------------------------------- /// LLLiveLSLFile /// --------------------------------------------------------------------------- @@ -1346,7 +1325,7 @@ void LLLiveLSLEditor::buildExperienceList() position = ADD_TOP; } - const LLSD& experience = LLExperienceCache::get(id); + const LLSD& experience = LLExperienceCache::instance().get(id); if(experience.isUndefined()) { mExperiences->add(getString("loading"), id, position); @@ -1365,7 +1344,7 @@ void LLLiveLSLEditor::buildExperienceList() if(!foundAssociated ) { - const LLSD& experience = LLExperienceCache::get(associated); + const LLSD& experience = LLExperienceCache::instance().get(associated); if(experience.isDefined()) { std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); @@ -1386,7 +1365,7 @@ void LLLiveLSLEditor::buildExperienceList() if(last.notNull()) { mExperiences->setEnabled(FALSE); - LLExperienceCache::get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this)); + LLExperienceCache::instance().get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this)); } else { @@ -1416,11 +1395,23 @@ void LLLiveLSLEditor::requestExperiences() std::string lookup_url=region->getCapability("GetCreatorExperiences"); if(!lookup_url.empty()) { - LLHTTPClient::get(lookup_url, new ExperienceResponder(getDerivedHandle<LLLiveLSLEditor>())); + LLCoreHttpUtil::HttpCoroutineAdapter::completionCallback_t success = + boost::bind(&LLLiveLSLEditor::receiveExperienceIds, _1, getDerivedHandle<LLLiveLSLEditor>()); + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet(lookup_url, success); } } } +/*static*/ +void LLLiveLSLEditor::receiveExperienceIds(LLSD result, LLHandle<LLLiveLSLEditor> hparent) +{ + LLLiveLSLEditor* parent = hparent.get(); + if (!parent) + return; + + parent->setExperienceIds(result["experience_ids"]); +} /// --------------------------------------------------------------------------- @@ -1571,7 +1562,7 @@ void LLPreviewLSL::loadAsset() if (gAgent.isGodlike() || (is_copyable && (is_modifiable || is_library))) { LLUUID* new_uuid = new LLUUID(mItemUUID); - gAssetStorage->getInvItemAsset(LLHost::invalid, + gAssetStorage->getInvItemAsset(LLHost(), gAgent.getID(), gAgent.getSessionID(), item->getPermissions().getOwner(), @@ -1641,62 +1632,74 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) self->saveIfNeeded(); } +/*static*/ +void LLPreviewLSL::finishedLSLUpload(LLUUID itemId, LLSD response) +{ + // Find our window and close it if requested. + LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", LLSD(itemId)); + if (preview) + { + // Bytecode save completed + if (response["compiled"]) + { + preview->callbackLSLCompileSucceeded(); + } + else + { + preview->callbackLSLCompileFailed(response["errors"]); + } + } +} + // Save needs to compile the text in the buffer. If the compile // succeeds, then save both assets out to the database. If the compile // fails, go ahead and save the text anyway. void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) { - // LL_INFOS() << "LLPreviewLSL::saveIfNeeded()" << LL_ENDL; - if(!mScriptEd->hasChanged()) - { - return; - } - - mPendingUploads = 0; - mScriptEd->mErrorList->deleteAllItems(); - mScriptEd->mEditor->makePristine(); - - // save off asset into file - LLTransactionID tid; - tid.generate(); - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string filename = filepath + ".lsl"; - - mScriptEd->writeToFile(filename); - - if (sync) - { - mScriptEd->sync(); - } - - const LLInventoryItem *inv_item = getItem(); - // save it out to asset server - std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); - if(inv_item) - { - getWindow()->incBusyCount(); - mPendingUploads++; - if (!url.empty()) - { - uploadAssetViaCaps(url, filename, mItemUUID); - } - else if (gAssetStorage) - { - uploadAssetLegacy(filename, mItemUUID, tid); - } - } -} - -void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, - const std::string& filename, - const LLUUID& item_id) -{ - LL_INFOS() << "Update Agent Inventory via capability" << LL_ENDL; - LLSD body; - body["item_id"] = item_id; - body["target"] = "lsl2"; - LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); + if (!mScriptEd->hasChanged()) + { + return; + } + + mPendingUploads = 0; + mScriptEd->mErrorList->deleteAllItems(); + mScriptEd->mEditor->makePristine(); + + if (sync) + { + mScriptEd->sync(); + } + + const LLInventoryItem *inv_item = getItem(); + // save it out to asset server + std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); + if(inv_item) + { + getWindow()->incBusyCount(); + mPendingUploads++; + if (!url.empty()) + { + std::string buffer(mScriptEd->mEditor->getText()); + LLBufferedAssetUploadInfo::invnUploadFinish_f proc = boost::bind(&LLPreviewLSL::finishedLSLUpload, _1, _4); + + LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mItemUUID, buffer, proc)); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + else if (gAssetStorage) + { + // save off asset into file + LLTransactionID tid; + tid.generate(); + LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, asset_id.asString()); + std::string filename = filepath + ".lsl"; + + mScriptEd->writeToFile(filename); + + uploadAssetLegacy(filename, mItemUUID, tid); + } + } } void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, @@ -2035,8 +2038,9 @@ void LLLiveLSLEditor::loadAsset() if(item) { - ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1)); - + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), + boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1)); + bool isGodlike = gAgent.isGodlike(); bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); @@ -2321,6 +2325,33 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, mItem = new LLViewerInventoryItem(item); } + +/*static*/ +void LLLiveLSLEditor::finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, bool isRunning) +{ + LLSD floater_key; + floater_key["taskid"] = taskId; + floater_key["itemid"] = itemId; + + LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance<LLLiveLSLEditor>("preview_scriptedit", floater_key); + if (preview) + { + preview->mItem->setAssetUUID(newAssetId); + + // Bytecode save completed + if (response["compiled"]) + { + preview->callbackLSLCompileSucceeded(taskId, itemId, isRunning); + } + else + { + preview->callbackLSLCompileFailed(response["errors"]); + } + } + +} + + // virtual void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) { @@ -2331,7 +2362,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) return; } - if(mItem.isNull() || !mItem->isFinished()) + if (mItem.isNull() || !mItem->isFinished()) { // $NOTE: While the error message may not be exactly correct, // it's pretty close. @@ -2339,78 +2370,68 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) return; } - // get the latest info about it. We used to be losing the script - // name on save, because the viewer object version of the item, - // and the editor version would get out of synch. Here's a good - // place to synch them back up. - LLInventoryItem* inv_item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mItemUUID)); - if(inv_item) - { - mItem->copyItem(inv_item); - } - - // Don't need to save if we're pristine - if(!mScriptEd->hasChanged()) - { - return; - } - - mPendingUploads = 0; - - // save the script - mScriptEd->enableSave(FALSE); - mScriptEd->mEditor->makePristine(); - mScriptEd->mErrorList->deleteAllItems(); - - // set up the save on the local machine. - mScriptEd->mEditor->makePristine(); - LLTransactionID tid; - tid.generate(); - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string filename = llformat("%s.lsl", filepath.c_str()); - - mItem->setAssetUUID(asset_id); - mItem->setTransactionID(tid); + // get the latest info about it. We used to be losing the script + // name on save, because the viewer object version of the item, + // and the editor version would get out of synch. Here's a good + // place to synch them back up. + LLInventoryItem* inv_item = dynamic_cast<LLInventoryItem*>(object->getInventoryObject(mItemUUID)); + if (inv_item) + { + mItem->copyItem(inv_item); + } + + // Don't need to save if we're pristine + if(!mScriptEd->hasChanged()) + { + return; + } + + mPendingUploads = 0; + + // save the script + mScriptEd->enableSave(FALSE); + mScriptEd->mEditor->makePristine(); + mScriptEd->mErrorList->deleteAllItems(); + mScriptEd->mEditor->makePristine(); + + if (sync) + { + mScriptEd->sync(); + } + bool isRunning = getChild<LLCheckBoxCtrl>("running")->get(); + getWindow()->incBusyCount(); + mPendingUploads++; + + std::string url = object->getRegion()->getCapability("UpdateScriptTask"); + + if (!url.empty()) + { + std::string buffer(mScriptEd->mEditor->getText()); + LLBufferedAssetUploadInfo::taskUploadFinish_f proc = boost::bind(&LLLiveLSLEditor::finishLSLUpload, _1, _2, _3, _4, isRunning); + + LLResourceUploadInfo::ptr_t uploadInfo(new LLScriptAssetUpload(mObjectUUID, mItemUUID, + monoChecked() ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, + isRunning, mScriptEd->getAssociatedExperience(), buffer, proc)); + + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); + } + else if (gAssetStorage) + { + // set up the save on the local machine. + LLTransactionID tid; + tid.generate(); + LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, asset_id.asString()); + std::string filename = llformat("%s.lsl", filepath.c_str()); + + mItem->setAssetUUID(asset_id); + mItem->setTransactionID(tid); + + mScriptEd->writeToFile(filename); + + uploadAssetLegacy(filename, object, tid, isRunning); + } - mScriptEd->writeToFile(filename); - - if (sync) - { - mScriptEd->sync(); - } - - // save it out to asset server - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - getWindow()->incBusyCount(); - mPendingUploads++; - BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get(); - if (!url.empty()) - { - uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running, mScriptEd->getAssociatedExperience()); - } - else if (gAssetStorage) - { - uploadAssetLegacy(filename, object, tid, is_running); - } -} - -void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, - const std::string& filename, - const LLUUID& task_id, - const LLUUID& item_id, - BOOL is_running, - const LLUUID& experience_public_id ) -{ - LL_INFOS() << "Update Task Inventory via capability " << url << LL_ENDL; - LLSD body; - body["task_id"] = task_id; - body["item_id"] = item_id; - body["is_script_running"] = is_running; - body["target"] = monoChecked() ? "mono" : "lsl2"; - body["experience"] = experience_public_id; - LLHTTPClient::post(url, body, - new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 5f65be7383..02f236a089 100755 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -203,9 +203,7 @@ protected: virtual void loadAsset(); /*virtual*/ void saveIfNeeded(bool sync = true); - void uploadAssetViaCaps(const std::string& url, - const std::string& filename, - const LLUUID& item_id); + void uploadAssetLegacy(const std::string& filename, const LLUUID& item_id, const LLTransactionID& tid); @@ -223,7 +221,7 @@ protected: protected: static void* createScriptEdPanel(void* userdata); - + static void finishedLSLUpload(LLUUID itemId, LLSD response); protected: // Can safely close only after both text and bytecode are uploaded @@ -270,12 +268,6 @@ private: virtual void loadAsset(); void loadAsset(BOOL is_new); /*virtual*/ void saveIfNeeded(bool sync = true); - void uploadAssetViaCaps(const std::string& url, - const std::string& filename, - const LLUUID& task_id, - const LLUUID& item_id, - BOOL is_running, - const LLUUID& experience_public_id); void uploadAssetLegacy(const std::string& filename, LLViewerObject* object, const LLTransactionID& tid, @@ -303,6 +295,9 @@ private: static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); + static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, bool isRunning); + static void receiveExperienceIds(LLSD result, LLHandle<LLLiveLSLEditor> parent); + private: bool mIsNew; //LLUUID mTransmitID; diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index e92bf4590d..b663df4aae 100755 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -32,31 +32,10 @@ #include "llagent.h" // for gAgent #include "lltrans.h" #include "llviewerregion.h" +#include "llcorehttputil.h" -class LLProductInfoRequestResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLProductInfoRequestResponder); -private: - //If we get back a normal response, handle it here - /* virtual */ void httpSuccess() - { - const LLSD& content = getContent(); - if (!content.isArray()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLProductInfoRequestManager::instance().setSkuDescriptions(getContent()); - } - - //If we get back an error (not found, etc...), handle it here - /* virtual */ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - } -}; - -LLProductInfoRequestManager::LLProductInfoRequestManager() : mSkuDescriptions() +LLProductInfoRequestManager::LLProductInfoRequestManager(): + mSkuDescriptions() { } @@ -65,15 +44,11 @@ void LLProductInfoRequestManager::initSingleton() std::string url = gAgent.getRegion()->getCapability("ProductInfoRequest"); if (!url.empty()) { - LLHTTPClient::get(url, new LLProductInfoRequestResponder()); + LLCoros::instance().launch("LLProductInfoRequestManager::getLandDescriptionsCoro", + boost::bind(&LLProductInfoRequestManager::getLandDescriptionsCoro, this, url)); } } -void LLProductInfoRequestManager::setSkuDescriptions(const LLSD& content) -{ - mSkuDescriptions = content; -} - std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string& sku) { // The description LLSD is an array of maps; each array entry @@ -90,3 +65,31 @@ std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string& } return LLTrans::getString("land_type_unknown"); } + +void LLProductInfoRequestManager::getLandDescriptionsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + return; + } + + if (result.has(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT) && + result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT].isArray()) + { + mSkuDescriptions = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; + } + else + { + LL_WARNS() << "Land SKU description response is malformed" << LL_ENDL; + } +} diff --git a/indra/newview/llproductinforequest.h b/indra/newview/llproductinforequest.h index fe8f7093b0..75dbf220d1 100755 --- a/indra/newview/llproductinforequest.h +++ b/indra/newview/llproductinforequest.h @@ -28,27 +28,29 @@ #ifndef LL_LLPRODUCTINFOREQUEST_H #define LL_LLPRODUCTINFOREQUEST_H -#include "llhttpclient.h" #include "llmemory.h" +#include "lleventcoro.h" +#include "llcoros.h" -/* - This is a singleton to manage a cache of information about land types. - The land system provides a capability to get information about the - set of possible land sku, name, and description information. - We use description in the UI, but the sku is provided in the various - messages; this tool provides translation between the systems. +/** + * This is a singleton to manage a cache of information about land types. + * The land system provides a capability to get information about the + * set of possible land sku, name, and description information. + * We use description in the UI, but the sku is provided in the various + * messages; this tool provides translation between the systems. */ - class LLProductInfoRequestManager : public LLSingleton<LLProductInfoRequestManager> { public: LLProductInfoRequestManager(); - void setSkuDescriptions(const LLSD& content); std::string getDescriptionForSku(const std::string& sku); + private: friend class LLSingleton<LLProductInfoRequestManager>; /* virtual */ void initSingleton(); - LLSD mSkuDescriptions; + + void getLandDescriptionsCoro(std::string url); + LLSD mSkuDescriptions; }; #endif // LL_LLPRODUCTINFOREQUEST_H diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 1257ee7f94..c17b86783d 100755 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -175,6 +175,10 @@ void LLProgressView::setStartupComplete() void LLProgressView::setVisible(BOOL visible) { + if (!visible && mFadeFromLoginTimer.getStarted()) + { + mFadeFromLoginTimer.stop(); + } // hiding progress view if (getVisible() && !visible) { diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 29dcc12f9e..055ccd5818 100755 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -31,55 +31,16 @@ #include "message.h" #include "llpanel.h" -#include "llhttpclient.h" #include "llsdserialize.h" #include "llurlentry.h" #include "llviewerregion.h" #include "llview.h" - +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llregionhandle.h" #include "llagent.h" #include "llremoteparcelrequest.h" - - -LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle) - : mObserverHandle(observer_handle) -{} - -//If we get back a normal response, handle it here -//virtual -void LLRemoteParcelRequestResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap() || !content.has("parcel_id")) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLUUID parcel_id = getContent()["parcel_id"]; - - // Panel inspecting the information may be closed and destroyed - // before this response is received. - LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); - if (observer) - { - observer->setParcelID(parcel_id); - } -} - -//If we get back an error (not found, etc...), handle it here -//virtual -void LLRemoteParcelRequestResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - - // Panel inspecting the information may be closed and destroyed - // before this response is received. - LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); - if (observer) - { - observer->setErrorStatus(getStatus(), getReason()); - } -} +#include "llcorehttputil.h" void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer) { @@ -200,3 +161,64 @@ void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id) msg->addUUID("ParcelID", parcel_id); gAgent.sendReliableMessage(); } + +bool LLRemoteParcelInfoProcessor::requestRegionParcelInfo(const std::string &url, + const LLUUID ®ionId, const LLVector3 ®ionPos, const LLVector3d&globalPos, + LLHandle<LLRemoteParcelInfoObserver> observerHandle) +{ + + if (!url.empty()) + { + LLCoros::instance().launch("LLRemoteParcelInfoProcessor::regionParcelInfoCoro", + boost::bind(&LLRemoteParcelInfoProcessor::regionParcelInfoCoro, this, url, + regionId, regionPos, globalPos, observerHandle)); + return true; + } + + return false; +} + +void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url, + LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal, + LLHandle<LLRemoteParcelInfoObserver> observerHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("RemoteParcelRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD bodyData; + + bodyData["location"] = ll_sd_from_vector3(posRegion); + if (!regionId.isNull()) + { + bodyData["region_id"] = regionId; + } + if (!posGlobal.isExactlyZero()) + { + U64 regionHandle = to_region_handle(posGlobal); + bodyData["region_handle"] = ll_sd_from_U64(regionHandle); + } + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, bodyData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLRemoteParcelInfoObserver* observer = observerHandle.get(); + // Panel inspecting the information may be closed and destroyed + // before this response is received. + if (!observer) + return; + + if (!status) + { + observer->setErrorStatus(status.getStatus(), status.getMessage()); + } + else + { + LLUUID parcel_id = result["parcel_id"]; + observer->setParcelID(parcel_id); + } + +} diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 35348b69ff..cb5af50c5f 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -29,29 +29,14 @@ #ifndef LL_LLREMOTEPARCELREQUEST_H #define LL_LLREMOTEPARCELREQUEST_H -#include "llhttpclient.h" #include "llhandle.h" #include "llsingleton.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLMessageSystem; class LLRemoteParcelInfoObserver; -class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLRemoteParcelRequestResponder); -public: - LLRemoteParcelRequestResponder(LLHandle<LLRemoteParcelInfoObserver> observer_handle); - -private: - //If we get back a normal response, handle it here - /*virtual*/ void httpSuccess(); - - //If we get back an error (not found, etc...), handle it here - /*virtual*/ void httpFailure(); - - LLHandle<LLRemoteParcelInfoObserver> mObserverHandle; -}; - struct LLParcelData { LLUUID parcel_id; @@ -99,9 +84,14 @@ public: static void processParcelInfoReply(LLMessageSystem* msg, void**); + bool requestRegionParcelInfo(const std::string &url, const LLUUID ®ionId, + const LLVector3 ®ionPos, const LLVector3d& globalPos, LLHandle<LLRemoteParcelInfoObserver> observerHandle); + private: typedef std::multimap<LLUUID, LLHandle<LLRemoteParcelInfoObserver> > observer_multimap_t; observer_multimap_t mObservers; + + void regionParcelInfoCoro(std::string url, LLUUID regionId, LLVector3 posRegion, LLVector3d posGlobal, LLHandle<LLRemoteParcelInfoObserver> observerHandle); }; #endif // LL_LLREMOTEPARCELREQUEST_H diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 43bb7b1596..4f9f83b6f2 100755 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -32,7 +32,6 @@ #include <openssl/evp.h> #include <openssl/err.h> #include <map> -#include "llhttpclient.h" @@ -99,46 +98,6 @@ std::ostream& operator <<(std::ostream& s, const LLCredential& cred) return s << (std::string)cred; } - -// secapiSSLCertVerifyCallback -// basic callback called when a cert verification is requested. -// calls SECAPI to validate the context -// not initialized in the above initialization function, due to unit tests -// see llappviewer - -int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) -{ - LLURLRequest *req = (LLURLRequest *)param; - LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(""); - LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); - LLSD validation_params = LLSD::emptyMap(); - LLURI uri(req->getURL()); - validation_params[CERT_HOSTNAME] = uri.hostName(); - try - { - // we rely on libcurl to validate the hostname, as libcurl does more extensive validation - // leaving our hostname validation call mechanism for future additions with respect to - // OS native (Mac keyring, windows CAPI) validation. - store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); - } - catch (LLCertValidationTrustException& cert_exception) - { - LL_WARNS("AppInit") << "Cert not trusted: " << cert_exception.getMessage() << LL_ENDL; - return 0; - } - catch (LLCertException& cert_exception) - { - LL_WARNS("AppInit") << "cert error " << cert_exception.getMessage() << LL_ENDL; - return 0; - } - catch (...) - { - LL_WARNS("AppInit") << "cert error " << LL_ENDL; - return 0; - } - return 1; -} - LLSD LLCredential::getLoginParams() { LLSD result = LLSD::emptyMap(); diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index c01d318f56..6fe3ee31cf 100755 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -489,7 +489,4 @@ void registerSecHandler(const std::string& handler_type, extern LLPointer<LLSecAPIHandler> gSecAPIHandler; -int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param); - - #endif // LL_SECAPI_H diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 0e23e2ad10..67ac875428 100755 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -37,7 +37,6 @@ #include "llfloatersidepanelcontainer.h" #include "llfoldertype.h" #include "llfolderview.h" -#include "llhttpclient.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index a7cfc173af..12cbff888d 100755 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -44,7 +44,6 @@ #include "llviewercontrol.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" -#include "llexperienceassociationresponder.h" #include "llexperiencecache.h" #include "lltrans.h" @@ -328,7 +327,9 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience"); tb->setText(getString("loading_experience")); tb->setVisible(TRUE); - ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1)); + + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), + boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1)); } ////////////////////// diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 0ae8a338e0..8fb3340db0 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -1004,21 +1004,18 @@ void LLSnapshotLivePreview::saveTexture() LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); std::string who_took_it; LLAgentUI::buildFullname(who_took_it); - LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - upload_new_resource(tid, // tid - LLAssetType::AT_TEXTURE, - "Snapshot : " + pos_string, - "Taken by " + who_took_it + " at " + pos_string, - 0, - LLFolderType::FT_SNAPSHOT_CATEGORY, - LLInventoryType::IT_SNAPSHOT, - PERM_ALL, // Note: Snapshots to inventory is a special case of content upload - LLFloaterPerms::getGroupPerms("Uploads"), // that is more permissive than other uploads - LLFloaterPerms::getEveryonePerms("Uploads"), - "Snapshot : " + pos_string, - callback, expected_upload_cost, userdata); + std::string name = "Snapshot: " + pos_string; + std::string desc = "Taken by " + who_took_it + " at " + pos_string; + + LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo( + tid, LLAssetType::AT_TEXTURE, name, desc, 0, + LLFolderType::FT_SNAPSHOT_CATEGORY, LLInventoryType::IT_SNAPSHOT, + PERM_ALL, LLFloaterPerms::getGroupPerms("Uploads"), LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost)); + + upload_new_resource(assetUploadInfo); + gViewerWindow->playSnapshotAnimAndSound(); } else diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 7867e1573c..974029254f 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -34,11 +34,11 @@ #include "llgroupmgr.h" #include "llsdutil.h" #include "lluicolortable.h" -#include "llhttpclient.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llvoavatar.h" #include "llworld.h" +#include "llcorehttputil.h" extern LLControlGroup gSavedSettings; @@ -265,49 +265,6 @@ bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) } // -// ModerationResponder -// - -class ModerationResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(ModerationResponder); -public: - ModerationResponder(const LLUUID& session_id) - { - mSessionID = session_id; - } - -protected: - virtual void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - - if ( gIMMgr ) - { - //403 == you're not a mod - //should be disabled if you're not a moderator - if ( HTTP_FORBIDDEN == getStatus() ) - { - gIMMgr->showSessionEventError( - "mute", - "not_a_mod_error", - mSessionID); - } - else - { - gIMMgr->showSessionEventError( - "mute", - "generic_request_error", - mSessionID); - } - } - } - -private: - LLUUID mSessionID; -}; - -// // LLSpeakerMgr // @@ -883,7 +840,8 @@ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) //current value represents ability to type, so invert data["params"]["mute_info"]["text"] = !speakerp->mModeratorMutedText; - LLHTTPClient::post(url, data, new ModerationResponder(getSessionID())); + LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", + boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); } void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute) @@ -907,10 +865,50 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu data["params"]["mute_info"] = LLSD::emptyMap(); data["params"]["mute_info"]["voice"] = !unmute; - LLHTTPClient::post( - url, - data, - new ModerationResponder(getSessionID())); + LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", + boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); +} + +void LLIMSpeakerMgr::moderationActionCoro(std::string url, LLSD action) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("moderationActionCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + + LLUUID sessionId = action["session-id"]; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, action, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if (gIMMgr) + { + //403 == you're not a mod + //should be disabled if you're not a moderator + if (status == LLCore::HttpStatus(HTTP_FORBIDDEN)) + { + gIMMgr->showSessionEventError( + "mute", + "not_a_mod_error", + sessionId); + } + else + { + gIMMgr->showSessionEventError( + "mute", + "generic_request_error", + sessionId); + } + } + return; + } } void LLIMSpeakerMgr::moderateVoiceAllParticipants( bool unmute_everyone ) @@ -949,7 +947,8 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo data["params"]["update_info"]["moderated_mode"] = LLSD::emptyMap(); data["params"]["update_info"]["moderated_mode"]["voice"] = disallow_voice; - LLHTTPClient::post(url, data, new ModerationResponder(session_id)); + LLCoros::instance().launch("LLIMSpeakerMgr::moderationActionCoro", + boost::bind(&LLIMSpeakerMgr::moderationActionCoro, this, url, data)); } void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 0e69184125..5cff70f377 100755 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -30,6 +30,8 @@ #include "llevent.h" #include "lleventtimer.h" #include "llvoicechannel.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLSpeakerMgr; @@ -333,6 +335,8 @@ protected: */ void forceVoiceModeratedMode(bool should_be_muted); + void moderationActionCoro(std::string url, LLSD action); + }; class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index d2050aec3e..2c6b9d14bf 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -46,7 +46,6 @@ #include "llaudioengine_openal.h" #endif -#include "llares.h" #include "llavatarnamecache.h" #include "llexperiencecache.h" #include "lllandmark.h" @@ -56,7 +55,6 @@ #include "llerrorcontrol.h" #include "llfloaterreg.h" #include "llfocusmgr.h" -#include "llhttpsender.h" #include "llfloaterimsession.h" #include "lllocationhistory.h" #include "llimageworker.h" @@ -113,7 +111,6 @@ #include "llgroupmgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llhttpclient.h" #include "llimagebmp.h" #include "llinventorybridge.h" #include "llinventorymodel.h" @@ -292,20 +289,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is // local classes // -namespace -{ - class LLNullHTTPSender : public LLHTTPSender - { - virtual void send(const LLHost& host, - const std::string& message, const LLSD& body, - LLHTTPClient::ResponderPtr response) const - { - LL_WARNS("AppInit") << " attemped to send " << message << " to " << host - << " with null sender" << LL_ENDL; - } - }; -} - void update_texture_fetch() { LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread @@ -460,13 +443,6 @@ bool idle_startup() // Load the throttle settings gViewerThrottle.load(); - if (ll_init_ares() == NULL || !gAres->isInitialized()) - { - std::string diagnostic = "Could not start address resolution system"; - LL_WARNS("AppInit") << diagnostic << LL_ENDL; - LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); - } - // // Initialize messaging system // @@ -511,8 +487,6 @@ bool idle_startup() port = gSavedSettings.getU32("ConnectionPort"); } - LLHTTPSender::setDefaultSender(new LLNullHTTPSender()); - // TODO parameterize const F32 circuit_heartbeat_interval = 5; const F32 circuit_timeout = 100; @@ -754,12 +728,9 @@ bool idle_startup() if (gLoginMenuBarView == NULL) { LL_DEBUGS("AppInit") << "initializing menu bar" << LL_ENDL; - display_startup(); initialize_edit_menu(); initialize_spellcheck_menu(); - display_startup(); init_menus(); - display_startup(); } if (show_connect_box) @@ -771,23 +742,17 @@ bool idle_startup() if (gUserCredential.isNull()) { LL_DEBUGS("AppInit") << "loading credentials from gLoginHandler" << LL_ENDL; - display_startup(); gUserCredential = gLoginHandler.initializeLoginInfo(); - display_startup(); } // Make sure the process dialog doesn't hide things - display_startup(); gViewerWindow->setShowProgress(FALSE); - display_startup(); // Show the login dialog login_show(); - display_startup(); // connect dialog is already shown, so fill in the names if (gUserCredential.notNull()) { LLPanelLogin::setFields( gUserCredential, gRememberPassword); } - display_startup(); LLPanelLogin::giveFocus(); // MAINT-3231 Show first run dialog only for Desura viewer @@ -813,22 +778,15 @@ bool idle_startup() LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); } - display_startup(); gViewerWindow->setNormalControlsVisible( FALSE ); - display_startup(); gLoginMenuBarView->setVisible( TRUE ); - display_startup(); gLoginMenuBarView->setEnabled( TRUE ); - display_startup(); show_debug_menus(); - display_startup(); // Hide the splash screen LLSplashScreen::hide(); - display_startup(); // Push our window frontmost gViewerWindow->getWindow()->show(); - display_startup(); // DEV-16927. The following code removes errant keystrokes that happen while the window is being // first made visible. @@ -836,9 +794,9 @@ bool idle_startup() MSG msg; while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ) { } - display_startup(); #endif - timeout.reset(); + display_startup(); + timeout.reset(); return FALSE; } @@ -2777,8 +2735,6 @@ void reset_login() gAgent.cleanup(); LLWorld::getInstance()->destroyClass(); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - if ( gViewerWindow ) { // Hide menus and normal buttons gViewerWindow->setNormalControlsVisible( FALSE ); @@ -2788,6 +2744,7 @@ void reset_login() // Hide any other stuff LLFloaterReg::hideVisibleInstances(); + LLStartUp::setStartupState( STATE_BROWSER_INIT ); } //--------------------------------------------------------------------------- @@ -2837,9 +2794,11 @@ void LLStartUp::initNameCache() void LLStartUp::initExperiences() -{ - LLAppViewer::instance()->loadExperienceCache(); - LLExperienceCache::initClass(); +{ + // Should trigger loading the cache. + LLExperienceCache::instance().setCapabilityQuery( + boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); + LLExperienceLog::instance().initialize(); } diff --git a/indra/newview/llsyntaxid.cpp b/indra/newview/llsyntaxid.cpp index 802dff1ead..9e54c521b5 100644 --- a/indra/newview/llsyntaxid.cpp +++ b/indra/newview/llsyntaxid.cpp @@ -31,70 +31,11 @@ #include "llsyntaxid.h" #include "llagent.h" #include "llappviewer.h" -#include "llhttpclient.h" #include "llsdserialize.h" #include "llviewerregion.h" +#include "llcorehttputil.h" //----------------------------------------------------------------------------- -// fetchKeywordsFileResponder -//----------------------------------------------------------------------------- -class fetchKeywordsFileResponder : public LLHTTPClient::Responder -{ -public: - fetchKeywordsFileResponder(const std::string& filespec) - : mFileSpec(filespec) - { - LL_DEBUGS("SyntaxLSL") << "Instantiating with file saving to: '" << filespec << "'" << LL_ENDL; - } - - /* virtual */ void httpFailure() - { - LL_WARNS("SyntaxLSL") << "failed to fetch syntax file [status:" << getStatus() << "]: " << getContent() << LL_ENDL; - } - - /* virtual */ void httpSuccess() - { - // Continue only if a valid LLSD object was returned. - const LLSD& content = getContent(); - if (content.isMap()) - { - if (LLSyntaxIdLSL::getInstance()->isSupportedVersion(content)) - { - LLSyntaxIdLSL::getInstance()->setKeywordsXml(content); - - cacheFile(content); - LLSyntaxIdLSL::getInstance()->handleFileFetched(mFileSpec); - } - else - { - LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL; - } - } - else - { - LL_WARNS("SyntaxLSL") << "Syntax file '" << mFileSpec << "' contains invalid LLSD." << LL_ENDL; - } - } - - void cacheFile(const LLSD& content_ref) - { - std::stringstream str; - LLSDSerialize::toXML(content_ref, str); - const std::string xml = str.str(); - - // save the str to disk, usually to the cache. - llofstream file(mFileSpec.c_str(), std::ios_base::out); - file.write(xml.c_str(), str.str().size()); - file.close(); - - LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << mFileSpec << "'" << LL_ENDL; - } - -private: - std::string mFileSpec; -}; - -//----------------------------------------------------------------------------- // LLSyntaxIdLSL //----------------------------------------------------------------------------- const std::string SYNTAX_ID_CAPABILITY_NAME = "LSLSyntax"; @@ -166,13 +107,72 @@ bool LLSyntaxIdLSL::syntaxIdChanged() //----------------------------------------------------------------------------- void LLSyntaxIdLSL::fetchKeywordsFile(const std::string& filespec) { - mInflightFetches.push_back(filespec); - LLHTTPClient::get(mCapabilityURL, - new fetchKeywordsFileResponder(filespec), - LLSD(), 30.f); + LLCoros::instance().launch("LLSyntaxIdLSL::fetchKeywordsFileCoro", + boost::bind(&LLSyntaxIdLSL::fetchKeywordsFileCoro, this, mCapabilityURL, filespec)); LL_DEBUGS("SyntaxLSL") << "LSLSyntaxId capability URL is: " << mCapabilityURL << ". Filename to use is: '" << filespec << "'." << LL_ENDL; } +//----------------------------------------------------------------------------- +// fetchKeywordsFileCoro +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::fetchKeywordsFileCoro(std::string url, std::string fileSpec) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::pair<std::set<std::string>::iterator, bool> insrt = mInflightFetches.insert(fileSpec); + if (!insrt.second) + { + LL_WARNS("SyntaxLSL") << "Already downloading keyword file called \"" << fileSpec << "\"." << LL_ENDL; + return; + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + mInflightFetches.erase(fileSpec); + + if (!status) + { + LL_WARNS("SyntaxLSL") << "Failed to fetch syntax file \"" << fileSpec << "\"" << LL_ENDL; + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + + if (isSupportedVersion(result)) + { + setKeywordsXml(result); + cacheFile(fileSpec, result); + loadKeywordsIntoLLSD(); + } + else + { + LL_WARNS("SyntaxLSL") << "Unknown or unsupported version of syntax file." << LL_ENDL; + } + +} + +//----------------------------------------------------------------------------- +// cacheFile +//----------------------------------------------------------------------------- +void LLSyntaxIdLSL::cacheFile(const std::string &fileSpec, const LLSD& content_ref) +{ + std::stringstream str; + LLSDSerialize::toXML(content_ref, str); + const std::string xml = str.str(); + + // save the str to disk, usually to the cache. + llofstream file(fileSpec.c_str(), std::ios_base::out); + file.write(xml.c_str(), str.str().size()); + file.close(); + + LL_DEBUGS("SyntaxLSL") << "Syntax file received, saving as: '" << fileSpec << "'" << LL_ENDL; +} //----------------------------------------------------------------------------- // initialize @@ -260,8 +260,8 @@ void LLSyntaxIdLSL::loadDefaultKeywordsIntoLLSD() // loadKeywordsFileIntoLLSD //----------------------------------------------------------------------------- /** - * @brief Load xml serialised LLSD - * @desc Opens the specified filespec and attempts to deserialise the + * @brief Load xml serialized LLSD + * @desc Opens the specified filespec and attempts to deserializes the * contained data to the specified LLSD object. indicate success/failure with * sLoaded/sLoadFailed members. */ @@ -276,7 +276,7 @@ void LLSyntaxIdLSL::loadKeywordsIntoLLSD() { if (isSupportedVersion(content)) { - LL_DEBUGS("SyntaxLSL") << "Deserialised: " << mFullFileSpec << LL_ENDL; + LL_DEBUGS("SyntaxLSL") << "Deserialized: " << mFullFileSpec << LL_ENDL; } else { @@ -317,12 +317,6 @@ void LLSyntaxIdLSL::handleCapsReceived(const LLUUID& region_uuid) } } -void LLSyntaxIdLSL::handleFileFetched(const std::string& filepath) -{ - mInflightFetches.remove(filepath); - loadKeywordsIntoLLSD(); -} - boost::signals2::connection LLSyntaxIdLSL::addSyntaxIDCallback(const syntax_id_changed_signal_t::slot_type& cb) { return mSyntaxIDChangedSignal.connect(cb); diff --git a/indra/newview/llsyntaxid.h b/indra/newview/llsyntaxid.h index 504fb0997e..0afa6dc04b 100644 --- a/indra/newview/llsyntaxid.h +++ b/indra/newview/llsyntaxid.h @@ -31,6 +31,8 @@ #include "llviewerprecompiledheaders.h" #include "llsingleton.h" +#include "lleventcoro.h" +#include "llcoros.h" class fetchKeywordsFileResponder; @@ -40,7 +42,7 @@ class LLSyntaxIdLSL : public LLSingleton<LLSyntaxIdLSL> friend class fetchKeywordsFileResponder; private: - std::list<std::string> mInflightFetches; + std::set<std::string> mInflightFetches; typedef boost::signals2::signal<void()> syntax_id_changed_signal_t; syntax_id_changed_signal_t mSyntaxIDChangedSignal; boost::signals2::connection mRegionChangedCallback; @@ -49,13 +51,15 @@ private: bool isSupportedVersion(const LLSD& content); void handleRegionChanged(); void handleCapsReceived(const LLUUID& region_uuid); - void handleFileFetched(const std::string& filepath); void setKeywordsXml(const LLSD& content) { mKeywordsXml = content; }; void buildFullFileSpec(); void fetchKeywordsFile(const std::string& filespec); void loadDefaultKeywordsIntoLLSD(); void loadKeywordsIntoLLSD(); - + + void fetchKeywordsFileCoro(std::string url, std::string fileSpec); + void cacheFile(const std::string &fileSpec, const LLSD& content_ref); + std::string mCapabilityURL; std::string mFullFileSpec; ELLPath mFilePath; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index fab4203ec3..30d90431ea 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -35,7 +35,6 @@ #include "lltexturefetch.h" #include "lldir.h" -#include "llhttpclient.h" #include "llhttpconstants.h" #include "llimage.h" #include "llimagej2c.h" @@ -1329,11 +1328,11 @@ bool LLTextureFetchWorker::doWork(S32 param) static LLCachedControl<bool> use_http(gSavedSettings, "ImagePipelineUseHTTP", true); -// if (mHost != LLHost::invalid) get_url = false; +// if (mHost.isInvalid()) get_url = false; if ( use_http && mCanUseHTTP && mUrl.empty())//get http url. { LLViewerRegion* region = NULL; - if (mHost == LLHost::invalid) + if (mHost.isInvalid()) region = gAgent.getRegion(); else region = LLWorld::getInstance()->getRegion(mHost); @@ -1558,7 +1557,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // Will call callbackHttpGet when curl request completes // Only server bake images use the returned headers currently, for getting retry-after field. - LLCore::HttpOptions *options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions; + LLCore::HttpOptions::ptr_t options = (mFTType == FTT_SERVER_BAKE) ? mFetcher->mHttpOptionsWithHeaders: mFetcher->mHttpOptions; if (disable_range_req) { // 'Range:' requests may be disabled in which case all HTTP @@ -2510,11 +2509,11 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mTotalHTTPRequests(0), mQAMode(qa_mode), mHttpRequest(NULL), - mHttpOptions(NULL), - mHttpOptionsWithHeaders(NULL), - mHttpHeaders(NULL), + mHttpOptions(), + mHttpOptionsWithHeaders(), + mHttpHeaders(), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mHttpMetricsHeaders(NULL), + mHttpMetricsHeaders(), mHttpMetricsPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), mTotalCacheReadCount(0U), mTotalCacheWriteCount(0U), @@ -2529,13 +2528,13 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); mHttpRequest = new LLCore::HttpRequest; - mHttpOptions = new LLCore::HttpOptions; - mHttpOptionsWithHeaders = new LLCore::HttpOptions; + mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + mHttpOptionsWithHeaders = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpOptionsWithHeaders->setWantHeaders(true); - mHttpHeaders = new LLCore::HttpHeaders; + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C); mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_TEXTURE); - mHttpMetricsHeaders = new LLCore::HttpHeaders; + mHttpMetricsHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpMetricsHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML); mHttpMetricsPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_REPORTING); mHttpHighWater = HTTP_NONPIPE_REQUESTS_HIGH_WATER; @@ -2569,30 +2568,6 @@ LLTextureFetch::~LLTextureFetch() delete req; } - if (mHttpOptions) - { - mHttpOptions->release(); - mHttpOptions = NULL; - } - - if (mHttpOptionsWithHeaders) - { - mHttpOptionsWithHeaders->release(); - mHttpOptionsWithHeaders = NULL; - } - - if (mHttpHeaders) - { - mHttpHeaders->release(); - mHttpHeaders = NULL; - } - - if (mHttpMetricsHeaders) - { - mHttpMetricsHeaders->release(); - mHttpMetricsHeaders = NULL; - } - mHttpWaitResource.clear(); delete mHttpRequest; @@ -3249,7 +3224,7 @@ void LLTextureFetch::sendRequestListToSimulators() { LLHost host = iter1->first; // invalid host = use agent host - if (host == LLHost::invalid) + if (host.isInvalid()) { host = gAgent.getRegionHost(); } @@ -3329,7 +3304,7 @@ void LLTextureFetch::sendRequestListToSimulators() iter1 != mCancelQueue.end(); ++iter1) { LLHost host = iter1->first; - if (host == LLHost::invalid) + if (host.isInvalid()) { host = gAgent.getRegionHost(); } @@ -4044,7 +4019,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher) report_priority, mCapsURL, sd, - NULL, + LLCore::HttpOptions::ptr_t(), fetcher->getMetricsHeaders(), handler); LLTextureFetch::svMetricsDataBreak = false; @@ -4163,7 +4138,7 @@ LLTextureFetchDebugger::LLTextureFetchDebugger(LLTextureFetch* fetcher, LLTextur mFetcher(fetcher), mTextureCache(cache), mImageDecodeThread(imagedecodethread), - mHttpHeaders(NULL), + mHttpHeaders(), mHttpPolicyClass(fetcher->getPolicyClass()), mNbCurlCompleted(0), mTempIndex(0), @@ -4177,11 +4152,6 @@ LLTextureFetchDebugger::~LLTextureFetchDebugger() mFetchingHistory.clear(); mStopDebug = TRUE; tryToStopDebug(); - if (mHttpHeaders) - { - mHttpHeaders->release(); - mHttpHeaders = NULL; - } } void LLTextureFetchDebugger::init() @@ -4226,7 +4196,7 @@ void LLTextureFetchDebugger::init() if (! mHttpHeaders) { - mHttpHeaders = new LLCore::HttpHeaders; + mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders); mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_IMAGE_X_J2C); } } @@ -4626,7 +4596,7 @@ S32 LLTextureFetchDebugger::fillCurlQueue() texture_url, 0, requestedSize, - NULL, + LLCore::HttpOptions::ptr_t(), mHttpHeaders, this); if (LLCORE_HTTP_HANDLE_INVALID != handle) diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 27779a31e0..50233eee5e 100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -37,7 +37,6 @@ #include "lltextureinfo.h" #include "llapr.h" #include "llimageworker.h" -#include "llcurl.h" #include "httprequest.h" #include "httpoptions.h" #include "httpheaders.h" @@ -177,7 +176,7 @@ public: // to do that to hold a reference for any length of time. // // Threads: T* - LLCore::HttpHeaders * getMetricsHeaders() const { return mHttpMetricsHeaders; } + LLCore::HttpHeaders::ptr_t getMetricsHeaders() const { return mHttpMetricsHeaders; } // Threads: T* LLCore::HttpRequest::policy_t getMetricsPolicyClass() const { return mHttpMetricsPolicyClass; } @@ -354,11 +353,11 @@ private: // to make our HTTP requests. These replace the various // LLCurl interfaces used in the past. LLCore::HttpRequest * mHttpRequest; // Ttf - LLCore::HttpOptions * mHttpOptions; // Ttf - LLCore::HttpOptions * mHttpOptionsWithHeaders; // Ttf - LLCore::HttpHeaders * mHttpHeaders; // Ttf + LLCore::HttpOptions::ptr_t mHttpOptions; // Ttf + LLCore::HttpOptions::ptr_t mHttpOptionsWithHeaders; // Ttf + LLCore::HttpHeaders::ptr_t mHttpHeaders; // Ttf LLCore::HttpRequest::policy_t mHttpPolicyClass; // T* - LLCore::HttpHeaders * mHttpMetricsHeaders; // Ttf + LLCore::HttpHeaders::ptr_t mHttpMetricsHeaders; // Ttf LLCore::HttpRequest::policy_t mHttpMetricsPolicyClass; // T* S32 mHttpHighWater; // Ttf S32 mHttpLowWater; // Ttf @@ -510,7 +509,7 @@ private: LLTextureFetch* mFetcher; LLTextureCache* mTextureCache; LLImageDecodeThread* mImageDecodeThread; - LLCore::HttpHeaders* mHttpHeaders; + LLCore::HttpHeaders::ptr_t mHttpHeaders; LLCore::HttpRequest::policy_t mHttpPolicyClass; S32 mNumFetchedTextures; diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index ca42d710f8..8ded148e17 100755 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -30,8 +30,8 @@ #include "llagent.h" #include "lltexturefetch.h" #include "lltexturestats.h" -#include "lltexturestatsuploader.h" #include "llviewerregion.h" +#include "llcorehttputil.h" void send_texture_stats_to_sim(const LLSD &texture_stats) { @@ -49,6 +49,16 @@ void send_texture_stats_to_sim(const LLSD &texture_stats) std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats"); LL_INFOS() << "uploading texture stats data to simulator" << LL_ENDL; - LLTextureStatsUploader::uploadStatsToSimulator(texture_cap_url, texture_stats); + + if (texture_cap_url != "") + { + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(texture_cap_url, texture_stats, + "Texture statistics posted to sim.", "Error posting texture statistics to sim"); + } + else + { + LL_INFOS() << "Not sending texture stats: " << texture_stats + << " as there is no cap url." << LL_ENDL; + } } diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp deleted file mode 100755 index c4809bc8e7..0000000000 --- a/indra/newview/lltexturestatsuploader.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file lltexturerstats.cpp - * @brief texture stats upload class - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lltexturestatsuploader.h" - -#include "llhttpclient.h" - - -// static -void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats) -{ - if ( texture_cap_url != "" ) - { - LLHTTPClient::post(texture_cap_url, texture_stats, NULL); - } - else - { - LL_INFOS() << "Not sending texture stats: " - << texture_stats - << " as there is no cap url." - << LL_ENDL; - } -} - diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/lltexturestatsuploader.h deleted file mode 100755 index ac268c2516..0000000000 --- a/indra/newview/lltexturestatsuploader.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file lltexturestatsuploader.h - * @brief Class to send the texture stats to the simulatore - * - * $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$ - */ - -#ifndef LL_LLTEXTURESTATSUPLOADER_H -#define LL_LLTEXTURESTATSUPLOADER_H - -#include "llappviewer.h" - -// utility functions to capture data on texture download speeds and send to simulator periodically - -class LLTextureStatsUploader -{ -public: - static void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats); -}; - -#endif // LL_LLTEXTURESTATSUPLOADER_H diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 81fbc471b3..8f482c5dca 100755 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -821,21 +821,6 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, if (!handled) { - // *TODO: Suppress the "outbox" case once "marketplace" is used everywhere for everyone - // Disallow drag and drop to 3D from the outbox - const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - if (outbox_id.notNull()) - { - for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++) - { - if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id)) - { - *acceptance = ACCEPT_NO; - mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld"); - return; - } - } - } // Disallow drag and drop to 3D from the marketplace const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); if (marketplacelistings_id.notNull()) diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index c0ba0a1f39..76fba82ef6 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -35,31 +35,254 @@ #include "llui.h" #include "llversioninfo.h" #include "llviewercontrol.h" - +#include "llcoros.h" #include "reader.h" +#include "llcorehttputil.h" + + +/** +* Handler of an HTTP machine translation service. +* +* Derived classes know the service URL +* and how to parse the translation result. +*/ +class LLTranslationAPIHandler +{ +public: + typedef std::pair<std::string, std::string> LanguagePair_t; + + /** + * Get URL for translation of the given string. + * + * Sending HTTP GET request to the URL will initiate translation. + * + * @param[out] url Place holder for the result. + * @param from_lang Source language. Leave empty for auto-detection. + * @param to_lang Target language. + * @param text Text to translate. + */ + virtual std::string getTranslateURL( + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const = 0; + + /** + * Get URL to verify the given API key. + * + * Sending request to the URL verifies the key. + * Positive HTTP response (code 200) means that the key is valid. + * + * @param[out] url Place holder for the URL. + * @param[in] key Key to verify. + */ + virtual std::string getKeyVerificationURL( + const std::string &key) const = 0; + + /** + * Parse translation response. + * + * @param[in,out] status HTTP status. May be modified while parsing. + * @param body Response text. + * @param[out] translation Translated text. + * @param[out] detected_lang Detected source language. May be empty. + * @param[out] err_msg Error message (in case of error). + */ + virtual bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const = 0; + + /** + * @return if the handler is configured to function properly + */ + virtual bool isConfigured() const = 0; + + virtual void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) = 0; + virtual void translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); + + + virtual ~LLTranslationAPIHandler() {} + + void verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc); + void translateMessageCoro(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure); +}; + +void LLTranslationAPIHandler::translateMessage(LanguagePair_t fromTo, std::string msg, LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure) +{ + LLCoros::instance().launch("Translation", boost::bind(&LLTranslationAPIHandler::translateMessageCoro, + this, fromTo, msg, success, failure)); + +} + + +void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std::string key, LLTranslate::KeyVerificationResult_fn fnc) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + + std::string user_agent = llformat("%s %d.%d.%d (%d)", + LLVersionInfo::getChannel().c_str(), + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), + LLVersionInfo::getBuild()); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + + httpOpts->setFollowRedirects(true); + + std::string url = this->getKeyVerificationURL(key); + if (url.empty()) + { + LL_INFOS("Translate") << "No translation URL" << LL_ENDL; + return; + } + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + bool bOk = true; + if (!status) + bOk = false; + + if (!fnc.empty()) + fnc(service, bOk); +} + +void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::string msg, + LLTranslate::TranslationSuccess_fn success, LLTranslate::TranslationFailure_fn failure) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getMerchantStatusCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + + std::string user_agent = llformat("%s %d.%d.%d (%d)", + LLVersionInfo::getChannel().c_str(), + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), + LLVersionInfo::getBuild()); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + + std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg); + if (url.empty()) + { + LL_INFOS("Translate") << "No translation URL" << LL_ENDL; + return; + } + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + std::string translation, detected_lang, err_msg; + + int parseResult = status.getType(); + if (this->parseResponse(parseResult, result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asString(), + translation, detected_lang, err_msg)) + { + // Fix up the response + LLStringUtil::replaceString(translation, "<", "<"); + LLStringUtil::replaceString(translation, ">", ">"); + LLStringUtil::replaceString(translation, """, "\""); + LLStringUtil::replaceString(translation, "'", "'"); + LLStringUtil::replaceString(translation, "&", "&"); + LLStringUtil::replaceString(translation, "'", "'"); + + if (!success.empty()) + success(translation, detected_lang); + } + else + { + if (err_msg.empty()) + { + err_msg = LLTrans::getString("TranslationResponseParseError"); + } + + LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL; + if (!failure.empty()) + failure(status, err_msg); + } + + +} + +//========================================================================= +/// Google Translate v2 API handler. +class LLGoogleTranslationHandler : public LLTranslationAPIHandler +{ + LOG_CLASS(LLGoogleTranslationHandler); + +public: + /*virtual*/ std::string getTranslateURL( + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const; + /*virtual*/ std::string getKeyVerificationURL( + const std::string &key) const; + /*virtual*/ bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; + + /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc); + +private: + static void parseErrorResponse( + const Json::Value& root, + int& status, + std::string& err_msg); + static bool parseTranslation( + const Json::Value& root, + std::string& translation, + std::string& detected_lang); + static std::string getAPIKey(); + +}; + +//------------------------------------------------------------------------- // virtual -void LLGoogleTranslationHandler::getTranslateURL( - std::string &url, +std::string LLGoogleTranslationHandler::getTranslateURL( const std::string &from_lang, const std::string &to_lang, const std::string &text) const { - url = std::string("https://www.googleapis.com/language/translate/v2?key=") + std::string url = std::string("https://www.googleapis.com/language/translate/v2?key=") + getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang; if (!from_lang.empty()) { url += "&source=" + from_lang; } + return url; } // virtual -void LLGoogleTranslationHandler::getKeyVerificationURL( - std::string& url, +std::string LLGoogleTranslationHandler::getKeyVerificationURL( const std::string& key) const { - url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") + std::string url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=") + key + "&target=en"; + return url; } // virtual @@ -154,28 +377,66 @@ std::string LLGoogleTranslationHandler::getAPIKey() return gSavedSettings.getString("GoogleTranslateAPIKey"); } +/*virtual*/ +void LLGoogleTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) +{ + LLCoros::instance().launch("Google /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, + this, LLTranslate::SERVICE_GOOGLE, key, fnc)); +} + + +//========================================================================= +/// Microsoft Translator v2 API handler. +class LLBingTranslationHandler : public LLTranslationAPIHandler +{ + LOG_CLASS(LLBingTranslationHandler); + +public: + /*virtual*/ std::string getTranslateURL( + const std::string &from_lang, + const std::string &to_lang, + const std::string &text) const; + /*virtual*/ std::string getKeyVerificationURL( + const std::string &key) const; + /*virtual*/ bool parseResponse( + int& status, + const std::string& body, + std::string& translation, + std::string& detected_lang, + std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; + + /*virtual*/ void verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc); +private: + static std::string getAPIKey(); + static std::string getAPILanguageCode(const std::string& lang); + +}; + +//------------------------------------------------------------------------- // virtual -void LLBingTranslationHandler::getTranslateURL( - std::string &url, +std::string LLBingTranslationHandler::getTranslateURL( const std::string &from_lang, const std::string &to_lang, const std::string &text) const { - url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=") + std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=") + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + getAPILanguageCode(to_lang); if (!from_lang.empty()) { url += "&from=" + getAPILanguageCode(from_lang); } + return url; } + // virtual -void LLBingTranslationHandler::getKeyVerificationURL( - std::string& url, +std::string LLBingTranslationHandler::getKeyVerificationURL( const std::string& key) const { - url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") + std::string url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=") + key; + return url; } // virtual @@ -242,96 +503,31 @@ std::string LLBingTranslationHandler::getAPILanguageCode(const std::string& lang return lang == "zh" ? "zh-CHT" : lang; // treat Chinese as Traditional Chinese } -LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang) -: mFromLang(from_lang) -, mToLang(to_lang) -, mHandler(LLTranslate::getPreferredHandler()) +/*virtual*/ +void LLBingTranslationHandler::verifyKey(const std::string &key, LLTranslate::KeyVerificationResult_fn fnc) { + LLCoros::instance().launch("Bing /Verify Key", boost::bind(&LLTranslationAPIHandler::verifyKeyCoro, + this, LLTranslate::SERVICE_BING, key, fnc)); } -// virtual -void LLTranslate::TranslationReceiver::completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +//========================================================================= +/*static*/ +void LLTranslate::translateMessage(const std::string &from_lang, const std::string &to_lang, + const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure) { - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - - const std::string body = strstrm.str(); - std::string translation, detected_lang, err_msg; - int status = getStatus(); - LL_DEBUGS("Translate") << "HTTP status: " << status << " " << getReason() << LL_ENDL; - LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL; - if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg)) - { - // Fix up the response - LLStringUtil::replaceString(translation, "<", "<"); - LLStringUtil::replaceString(translation, ">",">"); - LLStringUtil::replaceString(translation, ""","\""); - LLStringUtil::replaceString(translation, "'","'"); - LLStringUtil::replaceString(translation, "&","&"); - LLStringUtil::replaceString(translation, "'","'"); - - handleResponse(translation, detected_lang); - } - else - { - if (err_msg.empty()) - { - err_msg = LLTrans::getString("TranslationResponseParseError"); - } + LLTranslationAPIHandler& handler = getPreferredHandler(); - LL_WARNS() << "Translation request failed: " << err_msg << LL_ENDL; - handleFailure(status, err_msg); - } + handler.translateMessage(LLTranslationAPIHandler::LanguagePair_t(from_lang, to_lang), mesg, success, failure); } -LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service) -: mService(service) +/*static*/ +void LLTranslate::verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc) { -} + LLTranslationAPIHandler& handler = getHandler(service); -LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const -{ - return mService; + handler.verifyKey(key, fnc); } -// virtual -void LLTranslate::KeyVerificationReceiver::completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) -{ - bool ok = (getStatus() == HTTP_OK); - setVerificationStatus(ok); -} - -//static -void LLTranslate::translateMessage( - TranslationReceiverPtr &receiver, - const std::string &from_lang, - const std::string &to_lang, - const std::string &mesg) -{ - std::string url; - receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg); - - LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL; - sendRequest(url, receiver); -} - -// static -void LLTranslate::verifyKey( - KeyVerificationReceiverPtr& receiver, - const std::string& key) -{ - std::string url; - const LLTranslationAPIHandler& handler = getHandler(receiver->getService()); - handler.getKeyVerificationURL(url, key); - - LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL; - sendRequest(url, receiver); -} //static std::string LLTranslate::getTranslateLanguage() @@ -352,7 +548,7 @@ bool LLTranslate::isTranslationConfigured() } // static -const LLTranslationAPIHandler& LLTranslate::getPreferredHandler() +LLTranslationAPIHandler& LLTranslate::getPreferredHandler() { EService service = SERVICE_BING; @@ -366,7 +562,7 @@ const LLTranslationAPIHandler& LLTranslate::getPreferredHandler() } // static -const LLTranslationAPIHandler& LLTranslate::getHandler(EService service) +LLTranslationAPIHandler& LLTranslate::getHandler(EService service) { static LLGoogleTranslationHandler google; static LLBingTranslationHandler bing; @@ -378,25 +574,3 @@ const LLTranslationAPIHandler& LLTranslate::getHandler(EService service) return bing; } - -// static -void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder) -{ - static const float REQUEST_TIMEOUT = 5; - static LLSD sHeader; - - if (!sHeader.size()) - { - std::string user_agent = llformat("%s %d.%d.%d (%d)", - LLVersionInfo::getChannel().c_str(), - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), - LLVersionInfo::getBuild()); - - sHeader.insert(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); - sHeader.insert(HTTP_OUT_HEADER_USER_AGENT, user_agent); - } - - LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT); -} diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 972274714a..bf431cdfbb 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -27,136 +27,15 @@ #ifndef LL_LLTRANSLATE_H #define LL_LLTRANSLATE_H -#include "llhttpclient.h" #include "llbufferstream.h" +#include <boost/function.hpp> namespace Json { class Value; } -/** - * Handler of an HTTP machine translation service. - * - * Derived classes know the service URL - * and how to parse the translation result. - */ -class LLTranslationAPIHandler -{ -public: - /** - * Get URL for translation of the given string. - * - * Sending HTTP GET request to the URL will initiate translation. - * - * @param[out] url Place holder for the result. - * @param from_lang Source language. Leave empty for auto-detection. - * @param to_lang Target language. - * @param text Text to translate. - */ - virtual void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const = 0; - - /** - * Get URL to verify the given API key. - * - * Sending request to the URL verifies the key. - * Positive HTTP response (code 200) means that the key is valid. - * - * @param[out] url Place holder for the URL. - * @param[in] key Key to verify. - */ - virtual void getKeyVerificationURL( - std::string &url, - const std::string &key) const = 0; - - /** - * Parse translation response. - * - * @param[in,out] status HTTP status. May be modified while parsing. - * @param body Response text. - * @param[out] translation Translated text. - * @param[out] detected_lang Detected source language. May be empty. - * @param[out] err_msg Error message (in case of error). - */ - virtual bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const = 0; - - /** - * @return if the handler is configured to function properly - */ - virtual bool isConfigured() const = 0; - - virtual ~LLTranslationAPIHandler() {} -}; - -/// Google Translate v2 API handler. -class LLGoogleTranslationHandler : public LLTranslationAPIHandler -{ - LOG_CLASS(LLGoogleTranslationHandler); - -public: - /*virtual*/ void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const; - /*virtual*/ void getKeyVerificationURL( - std::string &url, - const std::string &key) const; - /*virtual*/ bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; - -private: - static void parseErrorResponse( - const Json::Value& root, - int& status, - std::string& err_msg); - static bool parseTranslation( - const Json::Value& root, - std::string& translation, - std::string& detected_lang); - static std::string getAPIKey(); -}; - -/// Microsoft Translator v2 API handler. -class LLBingTranslationHandler : public LLTranslationAPIHandler -{ - LOG_CLASS(LLBingTranslationHandler); - -public: - /*virtual*/ void getTranslateURL( - std::string &url, - const std::string &from_lang, - const std::string &to_lang, - const std::string &text) const; - /*virtual*/ void getKeyVerificationURL( - std::string &url, - const std::string &key) const; - /*virtual*/ bool parseResponse( - int& status, - const std::string& body, - std::string& translation, - std::string& detected_lang, - std::string& err_msg) const; - /*virtual*/ bool isConfigured() const; -private: - static std::string getAPIKey(); - static std::string getAPILanguageCode(const std::string& lang); -}; - +class LLTranslationAPIHandler; /** * Entry point for machine translation services. * @@ -180,84 +59,9 @@ public : SERVICE_GOOGLE, } EService; - /** - * Subclasses are supposed to handle translation results (e.g. show them in chat) - */ - class TranslationReceiver: public LLHTTPClient::Responder - { - public: - - /** - * Using mHandler, parse incoming response. - * - * Calls either handleResponse() or handleFailure() - * depending on the HTTP status code and parsing success. - * - * @see handleResponse() - * @see handleFailure() - * @see mHandler - */ - /*virtual*/ void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); - - protected: - friend class LLTranslate; - - /// Remember source and target languages for subclasses to be able to filter inappropriate results. - TranslationReceiver(const std::string& from_lang, const std::string& to_lang); - - /// Override point to handle successful translation. - virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0; - - /// Override point to handle unsuccessful translation. - virtual void handleFailure(int status, const std::string& err_msg) = 0; - - std::string mFromLang; - std::string mToLang; - const LLTranslationAPIHandler& mHandler; - }; - - /** - * Subclasses are supposed to handle API key verification result. - */ - class KeyVerificationReceiver: public LLHTTPClient::Responder - { - public: - EService getService() const; - - protected: - /** - * Save the translation service the key belongs to. - * - * Subclasses need to know it. - * - * @see getService() - */ - KeyVerificationReceiver(EService service); - - /** - * Parse verification response. - * - * Calls setVerificationStatus() with the verification status, - * which is true if HTTP status code is 200. - * - * @see setVerificationStatus() - */ - /*virtual*/ void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); - - /** - * Override point for subclasses to handle key verification status. - */ - virtual void setVerificationStatus(bool ok) = 0; - - EService mService; - }; - - typedef LLPointer<TranslationReceiver> TranslationReceiverPtr; - typedef LLPointer<KeyVerificationReceiver> KeyVerificationReceiverPtr; + typedef boost::function<void(EService, bool)> KeyVerificationResult_fn; + typedef boost::function<void(std::string , std::string )> TranslationSuccess_fn; + typedef boost::function<void(int, std::string)> TranslationFailure_fn; /** * Translate given text. @@ -267,15 +71,15 @@ public : * @param to_lang Target language. * @param mesg Text to translate. */ - static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg); + static void translateMessage(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, TranslationSuccess_fn success, TranslationFailure_fn failure); - /** + /** * Verify given API key of a translation service. * * @param receiver Object to pass verification result to. * @param key Key to verify. */ - static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key); + static void verifyKey(EService service, const std::string &key, KeyVerificationResult_fn fnc); /** * @return translation target language @@ -288,9 +92,8 @@ public : static bool isTranslationConfigured(); private: - static const LLTranslationAPIHandler& getPreferredHandler(); - static const LLTranslationAPIHandler& getHandler(EService service); - static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder); + static LLTranslationAPIHandler& getPreferredHandler(); + static LLTranslationAPIHandler& getHandler(EService service); }; #endif diff --git a/indra/newview/lltwitterconnect.cpp b/indra/newview/lltwitterconnect.cpp index e983bc883f..9b7c13b57d 100644 --- a/indra/newview/lltwitterconnect.cpp +++ b/indra/newview/lltwitterconnect.cpp @@ -32,7 +32,6 @@ #include "llagent.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llcommandhandler.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llurlaction.h" #include "llimagepng.h" @@ -43,6 +42,7 @@ #include "llfloaterwebcontent.h" #include "llfloaterreg.h" +#include "llcorehttputil.h" boost::scoped_ptr<LLEventPump> LLTwitterConnect::sStateWatcher(new LLEventStream("TwitterConnectState")); boost::scoped_ptr<LLEventPump> LLTwitterConnect::sInfoWatcher(new LLEventStream("TwitterConnectInfo")); @@ -67,228 +67,305 @@ void toast_user_for_twitter_success() /////////////////////////////////////////////////////////////////////////////// // -class LLTwitterConnectResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterConnectCoro(std::string requestToken, std::string oauthVerifier) { - LOG_CLASS(LLTwitterConnectResponder); -public: - - LLTwitterConnectResponder() + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD body; + if (!requestToken.empty()) + body["request_token"] = requestToken; + if (!oauthVerifier.empty()) + body["oauth_verifier"] = oauthVerifier; + + LLSD result = httpAdapter->putAndSuspend(httpRequest, getTwitterConnectURL("/connection"), body, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + if ( status == LLCore::HttpStatus(HTTP_FOUND) ) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("FlickrConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openTwitterWeb(location); + } + } + else + { + LL_WARNS("TwitterConnect") << "Connection failed " << status.toString() << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); + log_twitter_connect_error("Connect", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } } - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLTwitterConnect::instance().openTwitterWeb(location); - } - } - else - { - LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); - const LLSD& content = getContent(); - log_twitter_connect_error("Connect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + else + { + LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLTwitterShareResponder : public LLHTTPClient::Responder +bool LLTwitterConnect::testShareStatus(LLSD &result) { - LOG_CLASS(LLTwitterShareResponder); -public: - - LLTwitterShareResponder() - { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTING); - } - - /* virtual */ void httpSuccess() - { + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status) + return true; + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openTwitterWeb(location); + } + } + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; + connectToTwitter(); + } + else + { + LL_WARNS("TwitterConnect") << "HTTP Status error " << status.toString() << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); + log_twitter_connect_error("Share", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + return false; +} + +void LLTwitterConnect::twitterShareCoro(std::string route, LLSD share) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL(route, true), share, httpOpts); + + if (testShareStatus(result)) + { toast_user_for_twitter_success(); - LL_DEBUGS("TwitterConnect") << "Post successful. " << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POSTED); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLTwitterConnect::instance().openTwitterWeb(location); - } - } - else if ( HTTP_NOT_FOUND == getStatus() ) - { - LLTwitterConnect::instance().connectToTwitter(); - } - else - { - LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_POST_FAILED); - const LLSD& content = getContent(); - log_twitter_connect_error("Share", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_POSTED); + } +} + +void LLTwitterConnect::twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("FlickrConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + std::string imageFormat; + if (dynamic_cast<LLImagePNG*>(image.get())) + { + imageFormat = "png"; + } + else if (dynamic_cast<LLImageJPEG*>(image.get())) + { + imageFormat = "jpg"; + } + else + { + LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; + return; + } + + // All this code is mostly copied from LLWebProfile::post() + const std::string boundary = "----------------------------0123abcdefab"; + + std::string contentType = "multipart/form-data; boundary=" + boundary; + httpHeaders->append("Content-Type", contentType.c_str()); + + LLCore::BufferArray::ptr_t raw = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); // + LLCore::BufferArrayStream body(raw.get()); + + // *NOTE: The order seems to matter. + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"status\"\r\n\r\n" + << status << "\r\n"; + + body << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" + << "Content-Type: image/" << imageFormat << "\r\n\r\n"; + + // Insert the image data. + // *FIX: Treating this as a string will probably screw it up ... + U8* image_data = image->getData(); + for (S32 i = 0; i < image->getDataSize(); ++i) + { + body << image_data[i]; + } + + body << "\r\n--" << boundary << "--\r\n"; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, getTwitterConnectURL("/share/photo", true), raw, httpOpts, httpHeaders); + + if (testShareStatus(result)) + { + toast_user_for_twitter_success(); + LL_DEBUGS("TwitterConnect") << "Post successful. " << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_POSTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLTwitterDisconnectResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterDisconnectCoro() { - LOG_CLASS(LLTwitterDisconnectResponder); -public: - - LLTwitterDisconnectResponder() - { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); - } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - void setUserDisconnected() - { - // Clear data - LLTwitterConnect::instance().clearInfo(); + httpOpts->setFollowRedirects(false); - //Notify state change - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); - } + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, getTwitterConnectURL("/connection"), httpOpts); - /* virtual */ void httpSuccess() - { - LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } - - /* virtual */ void httpFailure() - { - //User not found so already disconnected - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("TwitterConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL; - setUserDisconnected(); - } - else - { - LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); - const LLSD& content = getContent(); - log_twitter_connect_error("Disconnect", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status && (status != LLCore::HttpStatus(HTTP_NOT_FOUND))) + { + LL_WARNS("TwitterConnect") << "Disconnect failed!" << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_DISCONNECT_FAILED); + + log_twitter_connect_error("Disconnect", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_DEBUGS("TwitterConnect") << "Disconnect successful. " << LL_ENDL; + clearInfo(); + setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); + } +} /////////////////////////////////////////////////////////////////////////////// // -class LLTwitterConnectedResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterConnectedCoro(bool autoConnect) { - LOG_CLASS(LLTwitterConnectedResponder); -public: - - LLTwitterConnectedResponder(bool auto_connect) : mAutoConnect(auto_connect) + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + httpOpts->setFollowRedirects(false); + setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/connection", true), httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + if (status == LLCore::HttpStatus(HTTP_NOT_FOUND)) + { + LL_DEBUGS("TwitterConnect") << "Not connected. " << LL_ENDL; + if (autoConnect) + { + connectToTwitter(); + } + else + { + setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); + } + } + else + { + LL_WARNS("TwitterConnect") << "Failed to test connection:" << status.toTerseString() << LL_ENDL; + + setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); + log_twitter_connect_error("Connected", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + } + else { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + LL_DEBUGS("TwitterConnect") << "Connect successful. " << LL_ENDL; + setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); } - - /* virtual */ void httpSuccess() - { - LL_DEBUGS("TwitterConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTED); - } - - /* virtual */ void httpFailure() - { - // show the facebook login page if not connected yet - if ( HTTP_NOT_FOUND == getStatus() ) - { - LL_DEBUGS("TwitterConnect") << "Not connected. " << dumpResponse() << LL_ENDL; - if (mAutoConnect) - { - LLTwitterConnect::instance().connectToTwitter(); - } - else - { - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_NOT_CONNECTED); - } - } - else - { - LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_FAILED); - const LLSD& content = getContent(); - log_twitter_connect_error("Connected", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } - -private: - bool mAutoConnect; -}; + +} /////////////////////////////////////////////////////////////////////////////// // -class LLTwitterInfoResponder : public LLHTTPClient::Responder +void LLTwitterConnect::twitterInfoCoro() { - LOG_CLASS(LLTwitterInfoResponder); -public: + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); - /* virtual */ void httpSuccess() - { - LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL; - LL_DEBUGS("TwitterConnect") << "Getting Twitter info successful. " << dumpResponse() << LL_ENDL; - LLTwitterConnect::instance().storeInfo(getContent()); - } - - /* virtual */ void httpFailure() - { - if ( HTTP_FOUND == getStatus() ) - { - const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (location.empty()) - { - LL_WARNS("TwitterConnect") << "Missing Location header " << dumpResponse() - << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - else - { - LLTwitterConnect::instance().openTwitterWeb(location); - } - } - else - { - LL_WARNS("TwitterConnect") << dumpResponse() << LL_ENDL; - const LLSD& content = getContent(); - log_twitter_connect_error("Info", getStatus(), getReason(), - content.get("error_code"), content.get("error_description")); - } - } -}; + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, getTwitterConnectURL("/info", true), httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status == LLCore::HttpStatus(HTTP_FOUND)) + { + std::string location = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS][HTTP_IN_HEADER_LOCATION]; + if (location.empty()) + { + LL_WARNS("TwitterConnect") << "Missing Location header " << LL_ENDL; + } + else + { + openTwitterWeb(location); + } + } + else if (!status) + { + LL_WARNS("TwitterConnect") << "Twitter Info failed: " << status.toString() << LL_ENDL; + log_twitter_connect_error("Info", status.getStatus(), status.toString(), + result.get("error_code"), result.get("error_description")); + } + else + { + LL_INFOS("TwitterConnect") << "Twitter: Info received" << LL_ENDL; + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + storeInfo(result); + } +} /////////////////////////////////////////////////////////////////////////////// // @@ -341,36 +418,32 @@ std::string LLTwitterConnect::getTwitterConnectURL(const std::string& route, boo void LLTwitterConnect::connectToTwitter(const std::string& request_token, const std::string& oauth_verifier) { - LLSD body; - if (!request_token.empty()) - body["request_token"] = request_token; - if (!oauth_verifier.empty()) - body["oauth_verifier"] = oauth_verifier; - - LLHTTPClient::put(getTwitterConnectURL("/connection"), body, new LLTwitterConnectResponder()); + setConnectionState(LLTwitterConnect::TWITTER_CONNECTION_IN_PROGRESS); + + LLCoros::instance().launch("LLTwitterConnect::twitterConnectCoro", + boost::bind(&LLTwitterConnect::twitterConnectCoro, this, request_token, oauth_verifier)); } void LLTwitterConnect::disconnectFromTwitter() { - LLHTTPClient::del(getTwitterConnectURL("/connection"), new LLTwitterDisconnectResponder()); + setConnectionState(LLTwitterConnect::TWITTER_DISCONNECTING); + + LLCoros::instance().launch("LLTwitterConnect::twitterDisconnectCoro", + boost::bind(&LLTwitterConnect::twitterDisconnectCoro, this)); } void LLTwitterConnect::checkConnectionToTwitter(bool auto_connect) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getTwitterConnectURL("/connection", true), new LLTwitterConnectedResponder(auto_connect), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLTwitterConnect::twitterConnectedCoro", + boost::bind(&LLTwitterConnect::twitterConnectedCoro, this, auto_connect)); } void LLTwitterConnect::loadTwitterInfo() { if(mRefreshInfo) { - const bool follow_redirects = false; - const F32 timeout = HTTP_REQUEST_EXPIRY_SECS; - LLHTTPClient::get(getTwitterConnectURL("/info", true), new LLTwitterInfoResponder(), - LLSD(), timeout, follow_redirects); + LLCoros::instance().launch("LLTwitterConnect::twitterInfoCoro", + boost::bind(&LLTwitterConnect::twitterInfoCoro, this)); } } @@ -379,62 +452,19 @@ void LLTwitterConnect::uploadPhoto(const std::string& image_url, const std::stri LLSD body; body["image"] = image_url; body["status"] = status; - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getTwitterConnectURL("/share/photo", true), body, new LLTwitterShareResponder()); + + setConnectionState(LLTwitterConnect::TWITTER_POSTING); + + LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", + boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/photo", body)); } void LLTwitterConnect::uploadPhoto(LLPointer<LLImageFormatted> image, const std::string& status) { - std::string imageFormat; - if (dynamic_cast<LLImagePNG*>(image.get())) - { - imageFormat = "png"; - } - else if (dynamic_cast<LLImageJPEG*>(image.get())) - { - imageFormat = "jpg"; - } - else - { - LL_WARNS() << "Image to upload is not a PNG or JPEG" << LL_ENDL; - return; - } - - // All this code is mostly copied from LLWebProfile::post() - const std::string boundary = "----------------------------0123abcdefab"; - - LLSD headers; - headers["Content-Type"] = "multipart/form-data; boundary=" + boundary; + setConnectionState(LLTwitterConnect::TWITTER_POSTING); - std::ostringstream body; - - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"status\"\r\n\r\n" - << status << "\r\n"; - - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"image\"; filename=\"Untitled." << imageFormat << "\"\r\n" - << "Content-Type: image/" << imageFormat << "\r\n\r\n"; - - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << boundary << "--\r\n"; - - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); - - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::postRaw(getTwitterConnectURL("/share/photo", true), data, size, new LLTwitterShareResponder(), headers); + LLCoros::instance().launch("LLTwitterConnect::twitterShareImageCoro", + boost::bind(&LLTwitterConnect::twitterShareImageCoro, this, image, status)); } void LLTwitterConnect::updateStatus(const std::string& status) @@ -442,8 +472,10 @@ void LLTwitterConnect::updateStatus(const std::string& status) LLSD body; body["status"] = status; - // Note: we can use that route for different publish action. We should be able to use the same responder. - LLHTTPClient::post(getTwitterConnectURL("/share/status", true), body, new LLTwitterShareResponder()); + setConnectionState(LLTwitterConnect::TWITTER_POSTING); + + LLCoros::instance().launch("LLTwitterConnect::twitterShareCoro", + boost::bind(&LLTwitterConnect::twitterShareCoro, this, "/share/status", body)); } void LLTwitterConnect::storeInfo(const LLSD& info) diff --git a/indra/newview/lltwitterconnect.h b/indra/newview/lltwitterconnect.h index c1df13f18c..be481a17c1 100644 --- a/indra/newview/lltwitterconnect.h +++ b/indra/newview/lltwitterconnect.h @@ -30,6 +30,8 @@ #include "llsingleton.h" #include "llimage.h" +#include "llcoros.h" +#include "lleventcoro.h" class LLEventPump; @@ -94,6 +96,14 @@ private: static boost::scoped_ptr<LLEventPump> sStateWatcher; static boost::scoped_ptr<LLEventPump> sInfoWatcher; static boost::scoped_ptr<LLEventPump> sContentWatcher; + + bool testShareStatus(LLSD &result); + void twitterConnectCoro(std::string requestToken, std::string oauthVerifier); + void twitterDisconnectCoro(); + void twitterConnectedCoro(bool autoConnect); + void twitterInfoCoro(); + void twitterShareCoro(std::string route, LLSD share); + void twitterShareImageCoro(LLPointer<LLImageFormatted> image, std::string status); }; #endif // LL_LLTWITTERCONNECT_H diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp deleted file mode 100755 index 69b9b1f9f1..0000000000 --- a/indra/newview/lluploadfloaterobservers.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file lluploadfloaterobservers.cpp - * @brief LLUploadModelPermissionsResponder definition - * - * $LicenseInfo:firstyear=2011&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 "lluploadfloaterobservers.h" - -LLUploadModelPermissionsResponder::LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer) -:mObserverHandle(observer) -{ -} - -void LLUploadModelPermissionsResponder::httpFailure() -{ - LL_WARNS() << dumpResponse() << LL_ENDL; - - LLUploadPermissionsObserver* observer = mObserverHandle.get(); - - if (observer) - { - observer->setPermissonsErrorStatus(getStatus(), getReason()); - } -} - -void LLUploadModelPermissionsResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLUploadPermissionsObserver* observer = mObserverHandle.get(); - - if (observer) - { - observer->onPermissionsReceived(content); - } -} - diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 4ff4a827a5..15c3dad38e 100755 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -28,7 +28,6 @@ #define LL_LLUPLOADFLOATEROBSERVERS_H #include "llfloater.h" -#include "llhttpclient.h" #include "llhandle.h" class LLUploadPermissionsObserver @@ -79,18 +78,4 @@ protected: LLRootHandle<LLWholeModelUploadObserver> mWholeModelUploadObserverHandle; }; - -class LLUploadModelPermissionsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLUploadModelPermissionsResponder); -public: - LLUploadModelPermissionsResponder(const LLHandle<LLUploadPermissionsObserver>& observer); - -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); - - LLHandle<LLUploadPermissionsObserver> mObserverHandle; -}; - #endif /* LL_LLUPLOADFLOATEROBSERVERS_H */ diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp new file mode 100644 index 0000000000..ea3d81c2f6 --- /dev/null +++ b/indra/newview/llviewerassetupload.cpp @@ -0,0 +1,839 @@ +/** +* @file llviewerassetupload.cpp +* @author optional +* @brief brief description of the file +* +* $LicenseInfo:firstyear=2011&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 "linden_common.h" +#include "llviewertexturelist.h" +#include "llimage.h" +#include "lltrans.h" +#include "lluuid.h" +#include "llvorbisencode.h" +#include "lluploaddialog.h" +#include "llpreviewscript.h" +#include "llnotificationsutil.h" +#include "lleconomy.h" +#include "llagent.h" +#include "llfloaterreg.h" +#include "llstatusbar.h" +#include "llinventorypanel.h" +#include "llsdutil.h" +#include "llviewerassetupload.h" +#include "llappviewer.h" +#include "llviewerstats.h" +#include "llvfile.h" +#include "llgesturemgr.h" +#include "llpreviewnotecard.h" +#include "llpreviewgesture.h" +#include "llcoproceduremanager.h" + +void dialog_refresh_all(); + +LLResourceUploadInfo::LLResourceUploadInfo(LLTransactionID transactId, + LLAssetType::EType assetType, std::string name, std::string description, + S32 compressionInfo, LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, U32 nextOWnerPerms, + U32 groupPerms, U32 everyonePerms, S32 expectedCost) : + mTransactionId(transactId), + mAssetType(assetType), + mName(name), + mDescription(description), + mCompressionInfo(compressionInfo), + mDestinationFolderType(destinationType), + mInventoryType(inventoryType), + mNextOwnerPerms(nextOWnerPerms), + mGroupPerms(groupPerms), + mEveryonePerms(everyonePerms), + mExpectedUploadCost(expectedCost), + mFolderId(LLUUID::null), + mItemId(LLUUID::null), + mAssetId(LLAssetID::null) +{ } + + +LLResourceUploadInfo::LLResourceUploadInfo(std::string name, + std::string description, S32 compressionInfo, + LLFolderType::EType destinationType, LLInventoryType::EType inventoryType, + U32 nextOWnerPerms, U32 groupPerms, U32 everyonePerms, S32 expectedCost): + mName(name), + mDescription(description), + mCompressionInfo(compressionInfo), + mDestinationFolderType(destinationType), + mInventoryType(inventoryType), + mNextOwnerPerms(nextOWnerPerms), + mGroupPerms(groupPerms), + mEveryonePerms(everyonePerms), + mExpectedUploadCost(expectedCost), + mTransactionId(), + mAssetType(LLAssetType::AT_NONE), + mFolderId(LLUUID::null), + mItemId(LLUUID::null), + mAssetId(LLAssetID::null) +{ + mTransactionId.generate(); +} + +LLResourceUploadInfo::LLResourceUploadInfo(LLAssetID assetId, LLAssetType::EType assetType, std::string name) : + mAssetId(assetId), + mAssetType(assetType), + mName(name), + mDescription(), + mCompressionInfo(0), + mDestinationFolderType(LLFolderType::FT_NONE), + mInventoryType(LLInventoryType::IT_NONE), + mNextOwnerPerms(0), + mGroupPerms(0), + mEveryonePerms(0), + mExpectedUploadCost(0), + mTransactionId(), + mFolderId(LLUUID::null), + mItemId(LLUUID::null) +{ +} + +LLSD LLResourceUploadInfo::prepareUpload() +{ + if (mAssetId.isNull()) + generateNewAssetId(); + + incrementUploadStats(); + assignDefaults(); + + return LLSD().with("success", LLSD::Boolean(true)); +} + +std::string LLResourceUploadInfo::getAssetTypeString() const +{ + return LLAssetType::lookup(mAssetType); +} + +std::string LLResourceUploadInfo::getInventoryTypeString() const +{ + return LLInventoryType::lookup(mInventoryType); +} + +LLSD LLResourceUploadInfo::generatePostBody() +{ + LLSD body; + + body["folder_id"] = mFolderId; + body["asset_type"] = getAssetTypeString(); + body["inventory_type"] = getInventoryTypeString(); + body["name"] = mName; + body["description"] = mDescription; + body["next_owner_mask"] = LLSD::Integer(mNextOwnerPerms); + body["group_mask"] = LLSD::Integer(mGroupPerms); + body["everyone_mask"] = LLSD::Integer(mEveryonePerms); + + return body; + +} + +void LLResourceUploadInfo::logPreparedUpload() +{ + LL_INFOS() << "*** Uploading: " << std::endl << + "Type: " << LLAssetType::lookup(mAssetType) << std::endl << + "UUID: " << mAssetId.asString() << std::endl << + "Name: " << mName << std::endl << + "Desc: " << mDescription << std::endl << + "Expected Upload Cost: " << mExpectedUploadCost << std::endl << + "Folder: " << mFolderId << std::endl << + "Asset Type: " << LLAssetType::lookup(mAssetType) << LL_ENDL; +} + +S32 LLResourceUploadInfo::getEconomyUploadCost() +{ + // Update L$ and ownership credit information + // since it probably changed on the server + if (getAssetType() == LLAssetType::AT_TEXTURE || + getAssetType() == LLAssetType::AT_SOUND || + getAssetType() == LLAssetType::AT_ANIMATION || + getAssetType() == LLAssetType::AT_MESH) + { + return LLGlobalEconomy::Singleton::instance().getPriceUpload(); + } + + return 0; +} + + +LLUUID LLResourceUploadInfo::finishUpload(LLSD &result) +{ + if (getFolderId().isNull()) + { + return LLUUID::null; + } + + U32 permsEveryone = PERM_NONE; + U32 permsGroup = PERM_NONE; + U32 permsNextOwner = PERM_ALL; + + if (result.has("new_next_owner_mask")) + { + // The server provided creation perms so use them. + // Do not assume we got the perms we asked for in + // since the server may not have granted them all. + permsEveryone = result["new_everyone_mask"].asInteger(); + permsGroup = result["new_group_mask"].asInteger(); + permsNextOwner = result["new_next_owner_mask"].asInteger(); + } + else + { + // The server doesn't provide creation perms + // so use old assumption-based perms. + if (getAssetTypeString() != "snapshot") + { + permsNextOwner = PERM_MOVE | PERM_TRANSFER; + } + } + + LLPermissions new_perms; + new_perms.init( + gAgent.getID(), + gAgent.getID(), + LLUUID::null, + LLUUID::null); + + new_perms.initMasks( + PERM_ALL, + PERM_ALL, + permsEveryone, + permsGroup, + permsNextOwner); + + U32 flagsInventoryItem = 0; + if (result.has("inventory_flags")) + { + flagsInventoryItem = static_cast<U32>(result["inventory_flags"].asInteger()); + if (flagsInventoryItem != 0) + { + LL_INFOS() << "inventory_item_flags " << flagsInventoryItem << LL_ENDL; + } + } + S32 creationDate = time_corrected(); + + LLUUID serverInventoryItem = result["new_inventory_item"].asUUID(); + LLUUID serverAssetId = result["new_asset"].asUUID(); + + LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( + serverInventoryItem, + getFolderId(), + new_perms, + serverAssetId, + getAssetType(), + getInventoryType(), + getName(), + getDescription(), + LLSaleInfo::DEFAULT, + flagsInventoryItem, + creationDate); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + + return serverInventoryItem; +} + + +LLAssetID LLResourceUploadInfo::generateNewAssetId() +{ + if (gDisconnected) + { + LLAssetID rv; + + rv.setNull(); + return rv; + } + mAssetId = mTransactionId.makeAssetID(gAgent.getSecureSessionID()); + + return mAssetId; +} + +void LLResourceUploadInfo::incrementUploadStats() const +{ + if (LLAssetType::AT_SOUND == mAssetType) + { + add(LLStatViewer::UPLOAD_SOUND, 1); + } + else if (LLAssetType::AT_TEXTURE == mAssetType) + { + add(LLStatViewer::UPLOAD_TEXTURE, 1); + } + else if (LLAssetType::AT_ANIMATION == mAssetType) + { + add(LLStatViewer::ANIMATION_UPLOADS, 1); + } +} + +void LLResourceUploadInfo::assignDefaults() +{ + if (LLInventoryType::IT_NONE == mInventoryType) + { + mInventoryType = LLInventoryType::defaultForAssetType(mAssetType); + } + LLStringUtil::stripNonprintable(mName); + LLStringUtil::stripNonprintable(mDescription); + + if (mName.empty()) + { + mName = "(No Name)"; + } + if (mDescription.empty()) + { + mDescription = "(No Description)"; + } + + mFolderId = gInventory.findCategoryUUIDForType( + (mDestinationFolderType == LLFolderType::FT_NONE) ? + (LLFolderType::EType)mAssetType : mDestinationFolderType); + +} + +std::string LLResourceUploadInfo::getDisplayName() const +{ + return (mName.empty()) ? mAssetId.asString() : mName; +}; + +//========================================================================= +LLNewFileResourceUploadInfo::LLNewFileResourceUploadInfo( + std::string fileName, + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost) : + LLResourceUploadInfo(name, description, compressionInfo, + destinationType, inventoryType, + nextOWnerPerms, groupPerms, everyonePerms, expectedCost), + mFileName(fileName) +{ +} + +LLSD LLNewFileResourceUploadInfo::prepareUpload() +{ + if (getAssetId().isNull()) + generateNewAssetId(); + + LLSD result = exportTempFile(); + if (result.has("error")) + return result; + + return LLResourceUploadInfo::prepareUpload(); +} + +LLSD LLNewFileResourceUploadInfo::exportTempFile() +{ + std::string filename = gDirUtilp->getTempFilename(); + + std::string exten = gDirUtilp->getExtension(getFileName()); + U32 codec = LLImageBase::getCodecFromExtension(exten); + + LLAssetType::EType assetType = LLAssetType::AT_NONE; + std::string errorMessage; + std::string errorLabel; + + bool error = false; + + if (exten.empty()) + { + std::string shortName = gDirUtilp->getBaseFileName(filename); + + // No extension + errorMessage = llformat( + "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", + shortName.c_str()); + errorLabel = "NoFileExtension"; + error = true; + } + else if (codec != IMG_CODEC_INVALID) + { + // It's an image file, the upload procedure is the same for all + assetType = LLAssetType::AT_TEXTURE; + if (!LLViewerTextureList::createUploadFile(getFileName(), filename, codec)) + { + errorMessage = llformat("Problem with file %s:\n\n%s\n", + getFileName().c_str(), LLImage::getLastError().c_str()); + errorLabel = "ProblemWithFile"; + error = true; + } + } + else if (exten == "wav") + { + assetType = LLAssetType::AT_SOUND; // tag it as audio + S32 encodeResult = 0; + + LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL; + + encodeResult = encode_vorbis_file(getFileName(), filename); + + if (LLVORBISENC_NOERR != encodeResult) + { + switch (encodeResult) + { + case LLVORBISENC_DEST_OPEN_ERR: + errorMessage = llformat("Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); + errorLabel = "CannotOpenTemporarySoundFile"; + break; + + default: + errorMessage = llformat("Unknown vorbis encode failure on: %s\n", getFileName().c_str()); + errorLabel = "UnknownVorbisEncodeFailure"; + break; + } + error = true; + } + } + else if (exten == "bvh") + { + errorMessage = llformat("We do not currently support bulk upload of animation files\n"); + errorLabel = "DoNotSupportBulkAnimationUpload"; + error = true; + } + else if (exten == "anim") + { + assetType = LLAssetType::AT_ANIMATION; + filename = getFileName(); + } + else + { + // Unknown extension + errorMessage = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); + errorLabel = "ErrorMessage"; + error = TRUE;; + } + + if (error) + { + LLSD errorResult(LLSD::emptyMap()); + + errorResult["error"] = LLSD::Binary(true); + errorResult["message"] = errorMessage; + errorResult["label"] = errorLabel; + return errorResult; + } + + setAssetType(assetType); + + // copy this file into the vfs for upload + S32 file_size; + LLAPRFile infile; + infile.open(filename, LL_APR_RB, NULL, &file_size); + if (infile.getFileHandle()) + { + LLVFile file(gVFS, getAssetId(), assetType, LLVFile::WRITE); + + file.setMaxSize(file_size); + + const S32 buf_size = 65536; + U8 copy_buf[buf_size]; + while ((file_size = infile.read(copy_buf, buf_size))) + { + file.write(copy_buf, file_size); + } + } + else + { + errorMessage = llformat("Unable to access output file: %s", filename.c_str()); + LLSD errorResult(LLSD::emptyMap()); + + errorResult["error"] = LLSD::Binary(true); + errorResult["message"] = errorMessage; + return errorResult; + } + + return LLSD(); + +} + +//========================================================================= +LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish) : + LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + 0, 0, 0, 0), + mTaskUpload(false), + mTaskId(LLUUID::null), + mContents(buffer), + mInvnFinishFn(finish), + mTaskFinishFn(NULL), + mStoredToVFS(false) +{ + setItemId(itemId); + setAssetType(assetType); +} + +LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish) : + LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + 0, 0, 0, 0), + mTaskUpload(false), + mTaskId(LLUUID::null), + mContents(), + mInvnFinishFn(finish), + mTaskFinishFn(NULL), + mStoredToVFS(false) +{ + setItemId(itemId); + + EImageCodec codec = static_cast<EImageCodec>(image->getCodec()); + + switch (codec) + { + case IMG_CODEC_JPEG: + setAssetType(LLAssetType::AT_IMAGE_JPEG); + LL_INFOS() << "Upload Asset type set to JPEG." << LL_ENDL; + break; + case IMG_CODEC_TGA: + setAssetType(LLAssetType::AT_IMAGE_TGA); + LL_INFOS() << "Upload Asset type set to TGA." << LL_ENDL; + break; + default: + LL_WARNS() << "Unknown codec to asset type transition. Codec=" << (int)codec << "." << LL_ENDL; + break; + } + + size_t imageSize = image->getDataSize(); + mContents.reserve(imageSize); + mContents.assign((char *)image->getData(), imageSize); +} + +LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish) : + LLResourceUploadInfo(std::string(), std::string(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + 0, 0, 0, 0), + mTaskUpload(true), + mTaskId(taskId), + mContents(buffer), + mInvnFinishFn(NULL), + mTaskFinishFn(finish), + mStoredToVFS(false) +{ + setItemId(itemId); + setAssetType(assetType); +} + +LLSD LLBufferedAssetUploadInfo::prepareUpload() +{ + if (getAssetId().isNull()) + generateNewAssetId(); + + LLVFile file(gVFS, getAssetId(), getAssetType(), LLVFile::APPEND); + + S32 size = mContents.length() + 1; + file.setMaxSize(size); + file.write((U8*)mContents.c_str(), size); + + mStoredToVFS = true; + + return LLSD().with("success", LLSD::Boolean(true)); +} + +LLSD LLBufferedAssetUploadInfo::generatePostBody() +{ + LLSD body; + + if (!getTaskId().isNull()) + { + body["task_id"] = getTaskId(); + } + body["item_id"] = getItemId(); + + return body; +} + +LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result) +{ + LLUUID newAssetId = result["new_asset"].asUUID(); + LLUUID itemId = getItemId(); + + if (mStoredToVFS) + { + LLAssetType::EType assetType(getAssetType()); + gVFS->renameFile(getAssetId(), assetType, newAssetId, assetType); + } + + if (mTaskUpload) + { + LLUUID taskId = getTaskId(); + + dialog_refresh_all(); + + if (mTaskFinishFn) + { + mTaskFinishFn(itemId, taskId, newAssetId, result); + } + } + else + { + LLUUID newItemId(LLUUID::null); + + if (itemId.notNull()) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(itemId); + if (!item) + { + LL_WARNS() << "Inventory item for " << getDisplayName() << " is no longer in agent inventory." << LL_ENDL; + return newAssetId; + } + + // Update viewer inventory item + LLPointer<LLViewerInventoryItem> newItem = new LLViewerInventoryItem(item); + newItem->setAssetUUID(newAssetId); + + gInventory.updateItem(newItem); + + newItemId = newItem->getUUID(); + LL_INFOS() << "Inventory item " << item->getName() << " saved into " << newAssetId.asString() << LL_ENDL; + } + + if (mInvnFinishFn) + { + mInvnFinishFn(itemId, newAssetId, newItemId, result); + } + gInventory.notifyObservers(); + } + + return newAssetId; +} + +//========================================================================= + +LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish): + LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish), + mExerienceId(), + mTargetType(LSL2), + mIsRunning(false) +{ +} + +LLScriptAssetUpload::LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType, + bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish): + LLBufferedAssetUploadInfo(taskId, itemId, LLAssetType::AT_LSL_TEXT, buffer, finish), + mExerienceId(exerienceId), + mTargetType(targetType), + mIsRunning(isRunning) +{ +} + +LLSD LLScriptAssetUpload::generatePostBody() +{ + LLSD body; + + if (getTaskId().isNull()) + { + body["item_id"] = getItemId(); + body["target"] = "lsl2"; + } + else + { + body["task_id"] = getTaskId(); + body["item_id"] = getItemId(); + body["is_script_running"] = getIsRunning(); + body["target"] = (getTargetType() == MONO) ? "mono" : "lsl2"; + body["experience"] = getExerienceId(); + } + + return body; +} + +//========================================================================= +/*static*/ +LLUUID LLViewerAssetUpload::EnqueueInventoryUpload(const std::string &url, const LLResourceUploadInfo::ptr_t &uploadInfo) +{ + std::string procName("LLViewerAssetUpload::AssetInventoryUploadCoproc("); + + LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("Upload", + procName + LLAssetType::lookup(uploadInfo->getAssetType()) + ")", + boost::bind(&LLViewerAssetUpload::AssetInventoryUploadCoproc, _1, _2, url, uploadInfo)); + + return queueId; +} + +//========================================================================= +/*static*/ +void LLViewerAssetUpload::AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, + const LLUUID &id, std::string url, LLResourceUploadInfo::ptr_t uploadInfo) +{ + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = uploadInfo->prepareUpload(); + uploadInfo->logPreparedUpload(); + + if (result.has("error")) + { + HandleUploadError(LLCore::HttpStatus(499), result, uploadInfo); + return; + } + + llcoro::suspend(); + + if (uploadInfo->showUploadDialog()) + { + std::string uploadMessage = "Uploading...\n\n"; + uploadMessage.append(uploadInfo->getDisplayName()); + LLUploadDialog::modalUploadDialog(uploadMessage); + } + + LLSD body = uploadInfo->generatePostBody(); + + result = httpAdapter->postAndSuspend(httpRequest, url, body); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if ((!status) || (result.has("error"))) + { + HandleUploadError(status, result, uploadInfo); + if (uploadInfo->showUploadDialog()) + LLUploadDialog::modalUploadFinished(); + return; + } + + std::string uploader = result["uploader"].asString(); + + bool success = false; + if (!uploader.empty() && uploadInfo->getAssetId().notNull()) + { + result = httpAdapter->postFileAndSuspend(httpRequest, uploader, uploadInfo->getAssetId(), uploadInfo->getAssetType()); + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + HandleUploadError(status, result, uploadInfo); + if (uploadInfo->showUploadDialog()) + LLUploadDialog::modalUploadFinished(); + return; + } + + S32 uploadPrice = uploadInfo->getEconomyUploadCost(); + + if (uploadPrice > 0) + { + // this upload costed us L$, update our balance + // and display something saying that it cost L$ + LLStatusBar::sendMoneyBalanceRequest(); + + LLSD args; + args["AMOUNT"] = llformat("%d", uploadPrice); + LLNotificationsUtil::add("UploadPayment", args); + } + } + else + { + LL_WARNS() << "No upload url provided. Nothing uploaded, responding with previous result." << LL_ENDL; + } + LLUUID serverInventoryItem = uploadInfo->finishUpload(result); + + if (uploadInfo->showInventoryPanel()) + { + if (serverInventoryItem.notNull()) + { + success = true; + + // Show the preview panel for textures and sounds to let + // user know that the image (or snapshot) arrived intact. + LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel(); + if (panel) + { + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + panel->setSelection(serverInventoryItem, TAKE_FOCUS_NO); + + // restore keyboard focus + gFocusMgr.setKeyboardFocus(focus); + } + } + else + { + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; + } + } + + // remove the "Uploading..." message + if (uploadInfo->showUploadDialog()) + LLUploadDialog::modalUploadFinished(); + + // Let the Snapshot floater know we have finished uploading a snapshot to inventory. + LLFloater* floater_snapshot = LLFloaterReg::findInstance("snapshot"); + if (uploadInfo->getAssetType() == LLAssetType::AT_TEXTURE && floater_snapshot) + { + floater_snapshot->notify(LLSD().with("set-finished", LLSD().with("ok", success).with("msg", "inventory"))); + } +} + +//========================================================================= +/*static*/ +void LLViewerAssetUpload::HandleUploadError(LLCore::HttpStatus status, LLSD &result, LLResourceUploadInfo::ptr_t &uploadInfo) +{ + std::string reason; + std::string label("CannotUploadReason"); + + LL_WARNS() << ll_pretty_print_sd(result) << LL_ENDL; + + if (result.has("label")) + { + label = result["label"].asString(); + } + + if (result.has("message")) + { + reason = result["message"].asString(); + } + else + { + if (status.getType() == 499) + { + reason = "The server is experiencing unexpected difficulties."; + } + else + { + reason = "Error in upload request. Please visit " + "http://secondlife.com/support for help fixing this problem."; + } + } + + LLSD args; + args["FILE"] = uploadInfo->getDisplayName(); + args["REASON"] = reason; + + LLNotificationsUtil::add(label, args); + + // unfreeze script preview + if (uploadInfo->getAssetType() == LLAssetType::AT_LSL_TEXT) + { + LLPreviewLSL* preview = LLFloaterReg::findTypedInstance<LLPreviewLSL>("preview_script", + uploadInfo->getItemId()); + if (preview) + { + LLSD errors; + errors.append(LLTrans::getString("UploadFailed") + reason); + preview->callbackLSLCompileFailed(errors); + } + } + +} + diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h new file mode 100644 index 0000000000..43e23a0d42 --- /dev/null +++ b/indra/newview/llviewerassetupload.h @@ -0,0 +1,236 @@ +/** +* @file llviewerassetupload.h +* @author optional +* @brief brief description of the file +* +* $LicenseInfo:firstyear=2011&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$ +*/ + +#ifndef LL_VIEWER_ASSET_UPLOAD_H +#define LL_VIEWER_ASSET_UPLOAD_H + +#include "llfoldertype.h" +#include "llassettype.h" +#include "llinventorytype.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h" +#include "llimage.h" + +//========================================================================= +class LLResourceUploadInfo +{ +public: + typedef boost::shared_ptr<LLResourceUploadInfo> ptr_t; + + LLResourceUploadInfo( + LLTransactionID transactId, + LLAssetType::EType assetType, + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost); + + virtual ~LLResourceUploadInfo() + { } + + virtual LLSD prepareUpload(); + virtual LLSD generatePostBody(); + virtual void logPreparedUpload(); + virtual S32 getEconomyUploadCost(); + virtual LLUUID finishUpload(LLSD &result); + + LLTransactionID getTransactionId() const { return mTransactionId; } + LLAssetType::EType getAssetType() const { return mAssetType; } + std::string getAssetTypeString() const; + std::string getName() const { return mName; }; + std::string getDescription() const { return mDescription; }; + S32 getCompressionInfo() const { return mCompressionInfo; }; + LLFolderType::EType getDestinationFolderType() const { return mDestinationFolderType; }; + LLInventoryType::EType getInventoryType() const { return mInventoryType; }; + std::string getInventoryTypeString() const; + U32 getNextOwnerPerms() const { return mNextOwnerPerms; }; + U32 getGroupPerms() const { return mGroupPerms; }; + U32 getEveryonePerms() const { return mEveryonePerms; }; + S32 getExpectedUploadCost() const { return mExpectedUploadCost; }; + + virtual bool showUploadDialog() const { return true; } + virtual bool showInventoryPanel() const { return true; } + + virtual std::string getDisplayName() const; + + LLUUID getFolderId() const { return mFolderId; } + LLUUID getItemId() const { return mItemId; } + LLAssetID getAssetId() const { return mAssetId; } + +protected: + LLResourceUploadInfo( + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost); + + LLResourceUploadInfo( + LLAssetID assetId, + LLAssetType::EType assetType, + std::string name ); + + void setTransactionId(LLTransactionID tid) { mTransactionId = tid; } + void setAssetType(LLAssetType::EType assetType) { mAssetType = assetType; } + void setItemId(LLUUID itemId) { mItemId = itemId; } + + LLAssetID generateNewAssetId(); + void incrementUploadStats() const; + virtual void assignDefaults(); + + void setAssetId(LLUUID assetId) { mAssetId = assetId; } + +private: + LLTransactionID mTransactionId; + LLAssetType::EType mAssetType; + std::string mName; + std::string mDescription; + S32 mCompressionInfo; + LLFolderType::EType mDestinationFolderType; + LLInventoryType::EType mInventoryType; + U32 mNextOwnerPerms; + U32 mGroupPerms; + U32 mEveryonePerms; + S32 mExpectedUploadCost; + + LLUUID mFolderId; + LLUUID mItemId; + LLAssetID mAssetId; +}; + +//------------------------------------------------------------------------- +class LLNewFileResourceUploadInfo : public LLResourceUploadInfo +{ +public: + LLNewFileResourceUploadInfo( + std::string fileName, + std::string name, + std::string description, + S32 compressionInfo, + LLFolderType::EType destinationType, + LLInventoryType::EType inventoryType, + U32 nextOWnerPerms, + U32 groupPerms, + U32 everyonePerms, + S32 expectedCost); + + virtual LLSD prepareUpload(); + + std::string getFileName() const { return mFileName; }; + +protected: + + virtual LLSD exportTempFile(); + +private: + std::string mFileName; + +}; + +//------------------------------------------------------------------------- +class LLBufferedAssetUploadInfo : public LLResourceUploadInfo +{ +public: + typedef boost::function<void(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)> invnUploadFinish_f; + typedef boost::function<void(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)> taskUploadFinish_f; + + LLBufferedAssetUploadInfo(LLUUID itemId, LLAssetType::EType assetType, std::string buffer, invnUploadFinish_f finish); + LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LLImageFormatted> image, invnUploadFinish_f finish); + LLBufferedAssetUploadInfo(LLUUID taskId, LLUUID itemId, LLAssetType::EType assetType, std::string buffer, taskUploadFinish_f finish); + + virtual LLSD prepareUpload(); + virtual LLSD generatePostBody(); + virtual LLUUID finishUpload(LLSD &result); + + LLUUID getTaskId() const { return mTaskId; } + const std::string & getContents() const { return mContents; } + + virtual bool showUploadDialog() const { return false; } + virtual bool showInventoryPanel() const { return false; } + +protected: + + +private: + bool mTaskUpload; + LLUUID mTaskId; + std::string mContents; + invnUploadFinish_f mInvnFinishFn; + taskUploadFinish_f mTaskFinishFn; + bool mStoredToVFS; +}; + +//------------------------------------------------------------------------- +class LLScriptAssetUpload : public LLBufferedAssetUploadInfo +{ +public: + enum TargetType_t + { + LSL2, + MONO + }; + + LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish); + LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType, + bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish); + + virtual LLSD generatePostBody(); + + LLUUID getExerienceId() const { return mExerienceId; } + TargetType_t getTargetType() const { return mTargetType; } + bool getIsRunning() const { return mIsRunning; } + +private: + LLUUID mExerienceId; + TargetType_t mTargetType; + bool mIsRunning; + +}; + +//========================================================================= +class LLViewerAssetUpload +{ +public: + static LLUUID EnqueueInventoryUpload(const std::string &url, const LLResourceUploadInfo::ptr_t &uploadInfo); + + static void AssetInventoryUploadCoproc(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &httpAdapter, const LLUUID &id, std::string url, LLResourceUploadInfo::ptr_t uploadInfo); + +private: + static void HandleUploadError(LLCore::HttpStatus status, LLSD &result, LLResourceUploadInfo::ptr_t &uploadInfo); +}; + +#endif // !VIEWER_ASSET_UPLOAD_H diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp deleted file mode 100755 index e390e8776d..0000000000 --- a/indra/newview/llviewerdisplayname.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** - * @file llviewerdisplayname.cpp - * @brief Wrapper for display name functionality - * - * $LicenseInfo:firstyear=2010&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerdisplayname.h" - -// viewer includes -#include "llagent.h" -#include "llviewerregion.h" -#include "llvoavatar.h" - -// library includes -#include "llavatarnamecache.h" -#include "llhttpclient.h" -#include "llhttpnode.h" -#include "llnotificationsutil.h" -#include "llui.h" // getLanguage() - -namespace LLViewerDisplayName -{ - // Fired when viewer receives server response to display name change - set_name_signal_t sSetDisplayNameSignal; - - // Fired when there is a change in the agent's name - name_changed_signal_t sNameChangedSignal; - - void addNameChangedCallback(const name_changed_signal_t::slot_type& cb) - { - sNameChangedSignal.connect(cb); - } - - void doNothing() { } -} - -class LLSetDisplayNameResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSetDisplayNameResponder); -private: - // only care about errors - /*virtual*/ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); - LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); - } -}; - -void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) -{ - // TODO: simple validation here - - LLViewerRegion* region = gAgent.getRegion(); - llassert(region); - std::string cap_url = region->getCapability("SetDisplayName"); - if (cap_url.empty()) - { - // this server does not support display names, report error - slot(false, "unsupported", LLSD()); - return; - } - - // People API can return localized error messages. Indicate our - // language preference via header. - LLSD headers; - headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); - - // People API requires both the old and new value to change a variable. - // Our display name will be in cache before the viewer's UI is available - // to request a change, so we can use direct lookup without callback. - LLAvatarName av_name; - if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) - { - slot(false, "name unavailable", LLSD()); - return; - } - - // People API expects array of [ "old value", "new value" ] - LLSD change_array = LLSD::emptyArray(); - change_array.append(av_name.getDisplayName()); - change_array.append(display_name); - - LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL; - - // Record our caller for when the server sends back a reply - sSetDisplayNameSignal.connect(slot); - - // POST the requested change. The sim will not send a response back to - // this request directly, rather it will send a separate message after it - // communicates with the back-end. - LLSD body; - body["display_name"] = change_array; - LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); -} - -class LLSetDisplayNameReply : public LLHTTPNode -{ - LOG_CLASS(LLSetDisplayNameReply); -public: - /*virtual*/ void post( - LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD body = input["body"]; - - S32 status = body["status"].asInteger(); - bool success = (status == HTTP_OK); - std::string reason = body["reason"].asString(); - LLSD content = body["content"]; - - LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL; - - // If viewer's concept of display name is out-of-date, the set request - // will fail with 409 Conflict. If that happens, fetch up-to-date - // name information. - if (status == HTTP_CONFLICT) - { - LLUUID agent_id = gAgent.getID(); - // Flush stale data - LLAvatarNameCache::erase( agent_id ); - // Queue request for new data: nothing to do on callback though... - // Note: no need to disconnect the callback as it never gets out of scope - LLAvatarNameCache::get(agent_id, boost::bind(&LLViewerDisplayName::doNothing)); - // Kill name tag, as it is wrong - LLVOAvatar::invalidateNameTag( agent_id ); - } - - // inform caller of result - LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content); - LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); - } -}; - - -class LLDisplayNameUpdate : public LLHTTPNode -{ - /*virtual*/ void post( - LLHTTPNode::ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD body = input["body"]; - LLUUID agent_id = body["agent_id"]; - std::string old_display_name = body["old_display_name"]; - // By convention this record is called "agent" in the People API - LLSD name_data = body["agent"]; - - // Inject the new name data into cache - LLAvatarName av_name; - av_name.fromLLSD( name_data ); - - LL_INFOS() << "name-update now " << LLDate::now() - << " next_update " << LLDate(av_name.mNextUpdate) - << LL_ENDL; - - // Name expiration time may be provided in headers, or we may use a - // default value - // *TODO: get actual headers out of ResponsePtr - //LLSD headers = response->mHeaders; - LLSD headers; - av_name.mExpires = - LLAvatarNameCache::nameExpirationFromHeaders(headers); - - LLAvatarNameCache::insert(agent_id, av_name); - - // force name tag to update - LLVOAvatar::invalidateNameTag(agent_id); - - LLSD args; - args["OLD_NAME"] = old_display_name; - args["SLID"] = av_name.getUserName(); - args["NEW_NAME"] = av_name.getDisplayName(); - LLNotificationsUtil::add("DisplayNameUpdate", args); - if (agent_id == gAgent.getID()) - { - LLViewerDisplayName::sNameChangedSignal(); - } - } -}; - -LLHTTPRegistration<LLSetDisplayNameReply> - gHTTPRegistrationMessageSetDisplayNameReply( - "/message/SetDisplayNameReply"); - -LLHTTPRegistration<LLDisplayNameUpdate> - gHTTPRegistrationMessageDisplayNameUpdate( - "/message/DisplayNameUpdate"); diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h deleted file mode 100755 index 16d59ae43b..0000000000 --- a/indra/newview/llviewerdisplayname.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file llviewerdisplayname.h - * @brief Wrapper for display name functionality - * - * $LicenseInfo:firstyear=2010&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$ - */ - -#ifndef LLVIEWERDISPLAYNAME_H -#define LLVIEWERDISPLAYNAME_H - -#include <boost/signals2.hpp> - -class LLSD; -class LLUUID; - -namespace LLViewerDisplayName -{ - typedef boost::signals2::signal< - void (bool success, const std::string& reason, const LLSD& content)> - set_name_signal_t; - typedef set_name_signal_t::slot_type set_name_slot_t; - - typedef boost::signals2::signal<void (void)> name_changed_signal_t; - typedef name_changed_signal_t::slot_type name_changed_slot_t; - - // Sends an update to the server to change a display name - // and call back when done. May not succeed due to service - // unavailable or name not available. - void set(const std::string& display_name, const set_name_slot_t& slot); - - void addNameChangedCallback(const name_changed_signal_t::slot_type& cb); -} - -#endif // LLVIEWERDISPLAYNAME_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 1178652408..7e76db20c5 100755 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -56,7 +56,6 @@ #include "llfloaterconversationpreview.h" #include "llfloaterdeleteenvpreset.h" #include "llfloaterdestinations.h" -#include "llfloaterdisplayname.h" #include "llfloatereditdaycycle.h" #include "llfloatereditsky.h" #include "llfloatereditwater.h" @@ -92,7 +91,6 @@ #include "llfloaternotificationsconsole.h" #include "llfloaterobjectweights.h" #include "llfloateropenobject.h" -#include "llfloateroutbox.h" #include "llfloaterpathfindingcharacters.h" #include "llfloaterpathfindingconsole.h" #include "llfloaterpathfindinglinksets.h" @@ -247,7 +245,6 @@ void LLViewerFloaterReg::registerFloaters() LLInspectRemoteObjectUtil::registerFloater(); LLFloaterVoiceVolumeUtil::registerFloater(); LLNotificationsUI::registerFloater(); - LLFloaterDisplayNameUtil::registerFloater(); LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLagMeter>); LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterLandHoldings>); @@ -272,7 +269,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); - LLFloaterReg::add("outbox", "floater_merchant_outbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutbox>); LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); LLFloaterPayUtil::registerFloater(); diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 158cacbc81..b8ff2cc9b4 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -137,7 +137,7 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() bool boxes_invisible = !gSavedSettings.getBOOL("InventoryOutboxMakeVisible"); addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Received Items", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible)); - addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, boxes_invisible)); + addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "Inv_SysOpen", "Inv_SysClosed", FALSE, true)); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 24096e3222..573791aca3 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -79,6 +79,16 @@ static const char * const LOG_INV("Inventory"); static const char * const LOG_LOCAL("InventoryLocalize"); static const char * const LOG_NOTECARD("copy_inventory_from_notecard"); +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void doInventoryCb(LLPointer<LLInventoryCallback> cb, LLUUID id) +{ + if (cb.notNull()) + cb->fire(id); +} +#endif + ///---------------------------------------------------------------------------- /// Helper class to store special inventory item names and their localized values. ///---------------------------------------------------------------------------- @@ -1280,16 +1290,14 @@ void link_inventory_array(const LLUUID& category, #endif } - bool ais_ran = false; - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { LLSD new_inventory = LLSD::emptyMap(); new_inventory["links"] = links; - LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb); - ais_ran = cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::CreateInventory(category, new_inventory, cr); } - - if (!ais_ran) + else { LLMessageSystem* msg = gMessageSystem; for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) @@ -1346,8 +1354,7 @@ void update_inventory_item( LLPointer<LLInventoryCallback> cb) { const LLUUID& item_id = update_item->getUUID(); - bool ais_ran = false; - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { LLSD updates = update_item->asLLSD(); // Replace asset_id and/or shadow_id with transaction_id (hash_id) @@ -1361,10 +1368,10 @@ void update_inventory_item( updates.erase("shadow_id"); updates["hash_id"] = update_item->getTransactionID(); } - LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); - ais_ran = cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::UpdateItem(item_id, updates, cr); } - if (!ais_ran) + else { LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL; @@ -1400,13 +1407,12 @@ void update_inventory_item( const LLSD& updates, LLPointer<LLInventoryCallback> cb) { - bool ais_ran = false; - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { - LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); - ais_ran = cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::UpdateItem(item_id, updates, cr); } - if (!ais_ran) + else { LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; @@ -1456,11 +1462,11 @@ void update_inventory_category( LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj); new_cat->fromLLSD(updates); // FIXME - restore this once the back-end work has been done. - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { LLSD new_llsd = new_cat->asLLSD(); - LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); - cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::UpdateCategory(cat_id, new_llsd, cr); } else // no cap { @@ -1522,10 +1528,10 @@ void remove_inventory_item( { const LLUUID item_id(obj->getUUID()); LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL; - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { - LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb); - cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::RemoveItem(item_id, cr); if (immediate_delete) { @@ -1598,10 +1604,10 @@ void remove_inventory_category( LLNotificationsUtil::add("CannotRemoveProtectedCategories"); return; } - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { - LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb); - cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::RemoveCategory(cat_id, cr); } else // no cap { @@ -1701,10 +1707,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb) } else { - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { - LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb); - cmd_ptr->run_command(); + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::PurgeDescendents(id, cr); } else // no cap { @@ -1780,27 +1786,20 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, return; } - // check capability to prevent a crash while LL_ERRS in LLCapabilityListener::capListener. See EXT-8459. - std::string url = viewer_region->getCapability("CopyInventoryFromNotecard"); - if (url.empty()) - { - LL_WARNS(LOG_NOTECARD) << "There is no 'CopyInventoryFromNotecard' capability" - << " for region: " << viewer_region->getName() - << LL_ENDL; - return; - } - - LLSD request, body; + LLSD body; body["notecard-id"] = notecard_inv_id; body["object-id"] = object_id; body["item-id"] = src->getUUID(); body["folder-id"] = destination_id; body["callback-id"] = (LLSD::Integer)callback_id; - request["message"] = "CopyInventoryFromNotecard"; - request["payload"] = body; - - viewer_region->getCapAPI().post(request); + /// *TODO: RIDER: This posts the request under the agents policy. + /// When I convert the inventory over this call should be moved under that + /// policy as well. + if (!gAgent.requestPostCapability("CopyInventoryFromNotecard", body)) + { + LL_WARNS() << "SIM does not have the capability to copy from notecard." << LL_ENDL; + } } void create_new_item(const std::string& name, @@ -1858,12 +1857,13 @@ void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> cb) { - if (AISCommand::isAPIAvailable()) + if (AISAPI::isAvailable()) { LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; - LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); - cmd_ptr->run_command(); + + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::SlamFolder(folder_id, contents, cr); } else // no cap { diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 3eae0f8d86..75a201d92f 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -69,6 +69,7 @@ #include "llwebprofile.h" #include "llwindow.h" #include "llvieweraudio.h" +#include "llcorehttputil.h" #include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. @@ -152,190 +153,6 @@ LLViewerMediaObserver::~LLViewerMediaObserver() } -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLMimeDiscoveryResponder); -public: - LLMimeDiscoveryResponder( viewer_media_t media_impl) - : mMediaImpl(media_impl), - mInitialized(false) - { - if(mMediaImpl->mMimeTypeProbe != NULL) - { - LL_ERRS() << "impl already has an outstanding responder" << LL_ENDL; - } - - mMediaImpl->mMimeTypeProbe = this; - } - - ~LLMimeDiscoveryResponder() - { - disconnectOwner(); - } - -private: - /* virtual */ void httpCompleted() - { - if (!isGoodStatus()) - { - LL_WARNS() << dumpResponse() - << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - } - const std::string& media_type = getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - - LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL; - - // 2xx status codes indicate success. - // Most 4xx status codes are successful enough for our purposes. - // 499 is the error code for host not found, timeout, etc. - // 500 means "Internal Server error" but we decided it's okay to - // accept this and go past it in the MIME type probe - // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com - // 499 is a code specifc to join.secondlife.com apparently safe to ignore -// if( ((status >= 200) && (status < 300)) || -// ((status >= 400) && (status < 499)) || -// (status == 500) || -// (status == 302) || -// (status == 499) -// ) - // We now no longer check the error code returned from the probe. - // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. - //if(1) - { - // The probe was successful. - if(mime_type.empty()) - { - // Some sites don't return any content-type header at all. - // Treat an empty mime type as text/html. - mime_type = HTTP_CONTENT_TEXT_HTML; - } - } - //else - //{ - // LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; - // - // if(mMediaImpl) - // { - // mMediaImpl->mMediaSourceFailed = true; - // } - // return; - //} - - // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. - // Make a local copy so we can call loadURI() afterwards. - LLViewerMediaImpl *impl = mMediaImpl; - - if(impl && !mInitialized && ! mime_type.empty()) - { - if(impl->initializeMedia(mime_type)) - { - mInitialized = true; - impl->loadURI(); - disconnectOwner(); - } - } - } - -public: - void cancelRequest() - { - disconnectOwner(); - } - -private: - void disconnectOwner() - { - if(mMediaImpl) - { - if(mMediaImpl->mMimeTypeProbe != this) - { - LL_ERRS() << "internal error: mMediaImpl->mMimeTypeProbe != this" << LL_ENDL; - } - - mMediaImpl->mMimeTypeProbe = NULL; - } - mMediaImpl = NULL; - } - - -public: - LLViewerMediaImpl *mMediaImpl; - bool mInitialized; -}; - -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLViewerMediaOpenIDResponder); -public: - LLViewerMediaOpenIDResponder( ) - { - } - - ~LLViewerMediaOpenIDResponder() - { - } - - /* virtual */ void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // We don't care about the content of the response, only the Set-Cookie header. - LL_DEBUGS("MediaAuth") << dumpResponse() - << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); - - // *TODO: What about bad status codes? Does this destroy previous cookies? - LLViewerMedia::openIDCookieResponse(cookie); - } - -}; - -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaWebProfileResponder); -public: - LLViewerMediaWebProfileResponder(std::string host) - { - mHost = host; - } - - ~LLViewerMediaWebProfileResponder() - { - } - - void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // We don't care about the content of the response, only the set-cookie header. - LL_WARNS("MediaAuth") << dumpResponse() - << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; - - LLSD stripped_content = getResponseHeaders(); - // *TODO: Check that this works. - stripped_content.erase(HTTP_IN_HEADER_SET_COOKIE); - LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; - - const std::string& cookie = getResponseHeader(HTTP_IN_HEADER_SET_COOKIE); - LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; - - // *TODO: What about bad status codes? Does this destroy previous cookies? - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); - - // Set cookie for snapshot publishing. - std::string auth_cookie = cookie.substr(0, cookie.find(";")); // strip path - LLWebProfile::setAuthCookie(auth_cookie); - } - - std::string mHost; -}; - - LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; LLURL LLViewerMedia::sOpenIDURL; std::string LLViewerMedia::sOpenIDCookie; @@ -1388,87 +1205,172 @@ LLSD LLViewerMedia::getHeaders() return headers; } +LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders() +{ + LLCore::HttpHeaders::ptr_t headers(new LLCore::HttpHeaders); + + headers->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + headers->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_XML); + headers->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); + headers->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); + + return headers; +} + ///////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::setOpenIDCookie() { if(!sOpenIDCookie.empty()) { - // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] - // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. - // We therefore do it here. - std::string authority = sOpenIDURL.mAuthority; - std::string::size_type host_start = authority.find('@'); - if(host_start == std::string::npos) - { - // no username/password - host_start = 0; - } - else - { - // Hostname starts after the @. - // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) - ++host_start; - } - std::string::size_type host_end = authority.rfind(':'); - if((host_end == std::string::npos) || (host_end < host_start)) - { - // no port - host_end = authority.size(); - } - - getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); + std::string profileUrl = getProfileURL(""); + + LLCoros::instance().launch("LLViewerMedia::getOpenIDCookieCoro", + boost::bind(&LLViewerMedia::getOpenIDCookieCoro, profileUrl)); + } +} + +/*static*/ +void LLViewerMedia::getOpenIDCookieCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getOpenIDCookieCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + httpOpts->setFollowRedirects(true); + httpOpts->setWantHeaders(true); + + LLURL hostUrl(url.c_str()); + std::string hostAuth = hostUrl.getAuthority(); + + // *TODO: Expand LLURL to split and extract this information better. + // The structure of a URL is well defined and needing to retrieve parts of it are common. + // original comment: + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type hostStart = authority.find('@'); + if (hostStart == std::string::npos) + { // no username/password + hostStart = 0; + } + else + { // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++hostStart; + } + std::string::size_type hostEnd = authority.rfind(':'); + if ((hostEnd == std::string::npos) || (hostEnd < hostStart)) + { // no port + hostEnd = authority.size(); + } - // Do a web profile get so we can store the cookie - LLSD headers = LLSD::emptyMap(); - headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; - headers[HTTP_OUT_HEADER_COOKIE] = sOpenIDCookie; - headers[HTTP_OUT_HEADER_USER_AGENT] = getCurrentUserAgent(); + getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(hostStart, hostEnd - hostStart)); - std::string profile_url = getProfileURL(""); - LLURL raw_profile_url( profile_url.c_str() ); + // Do a web profile get so we can store the cookie + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, sOpenIDCookie); + httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, getCurrentUserAgent()); + + + LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL; + LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("MediaAuth") << "Error getting web profile." << LL_ENDL; + return; + } + + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) + { + LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL; + return; + } + + const std::string& cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE].asStringRef(); + LL_DEBUGS("MediaAuth") << "cookie = " << cookie << LL_ENDL; + + // *TODO: What about bad status codes? Does this destroy previous cookies? + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, hostAuth); + + // Set cookie for snapshot publishing. + std::string authCookie = cookie.substr(0, cookie.find(";")); // strip path + LLWebProfile::setAuthCookie(authCookie); - LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << LL_ENDL; - LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; - LLHTTPClient::get(profile_url, - new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), - headers); - } } ///////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string &openidToken) { - LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + LL_DEBUGS("MediaAuth") << "url = \"" << openidUrl << "\", token = \"" << openidToken << "\"" << LL_ENDL; - // post the token to the url - // the responder will need to extract the cookie(s). + LLCoros::instance().launch("LLViewerMedia::openIDSetupCoro", + boost::bind(&LLViewerMedia::openIDSetupCoro, openidUrl, openidToken)); +} - // Save the OpenID URL for later -- we may need the host when adding the cookie. - sOpenIDURL.init(openid_url.c_str()); - - // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. - sOpenIDCookie.clear(); +/*static*/ +void LLViewerMedia::openIDSetupCoro(std::string openidUrl, std::string openidToken) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("openIDSetupCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); - LLSD headers = LLSD::emptyMap(); - // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; - // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "application/x-www-form-urlencoded"; - - // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. - size_t size = openid_token.size(); - U8 *data = new U8[size]; - memcpy(data, openid_token.data(), size); - - LLHTTPClient::postRaw( - openid_url, - data, - size, - new LLViewerMediaOpenIDResponder(), - headers); - + httpOpts->setWantHeaders(true); + + // post the token to the url + // the responder will need to extract the cookie(s). + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openidUrl.c_str()); + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded"); + + LLCore::BufferArray::ptr_t rawbody(new LLCore::BufferArray); + LLCore::BufferArrayStream bas(rawbody.get()); + + bas << std::noskipws << openidToken; + + LLSD result = httpAdapter->postRawAndSuspend(httpRequest, openidUrl, rawbody, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("MediaAuth") << "Error getting Open ID cookie" << LL_ENDL; + return; + } + + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + if (!resultHeaders.has(HTTP_IN_HEADER_SET_COOKIE)) + { + LL_WARNS("MediaAuth") << "No cookie in response." << LL_ENDL; + return; + } + + // We don't care about the content of the response, only the Set-Cookie header. + const std::string &cookie = resultHeaders[HTTP_IN_HEADER_SET_COOKIE]; + + // *TODO: What about bad status codes? Does this destroy previous cookies? + LLViewerMedia::openIDCookieResponse(cookie); + LL_DEBUGS("MediaAuth") << "OpenID cookie set." << LL_ENDL; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1661,7 +1563,6 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, mIsParcelMedia(false), mProximity(-1), mProximityDistance(0.0f), - mMimeTypeProbe(NULL), mMediaAutoPlay(false), mInNearbyMediaList(false), mClearCache(false), @@ -1671,8 +1572,10 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, mIsUpdated(false), mTrustedBrowser(false), mZoomFactor(1.0), - mCleanBrowser(false) -{ + mCleanBrowser(false), + mMimeProbe(), + mCanceling(false) +{ // Set up the mute list observer if it hasn't been set up already. if(!sViewerMediaMuteListObserverInitialized) @@ -2610,7 +2513,8 @@ void LLViewerMediaImpl::navigateInternal() return; } - if(mMimeTypeProbe != NULL) + + if (!mMimeProbe.expired()) { LL_WARNS() << "MIME type probe already in progress -- bailing out." << LL_ENDL; return; @@ -2648,14 +2552,8 @@ void LLViewerMediaImpl::navigateInternal() if(scheme.empty() || "http" == scheme || "https" == scheme) { - // If we don't set an Accept header, LLHTTPClient will add one like this: - // Accept: application/llsd+xml - // which is really not what we want. - LLSD headers = LLSD::emptyMap(); - headers[HTTP_OUT_HEADER_ACCEPT] = "*/*"; - // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com - headers[HTTP_OUT_HEADER_COOKIE] = ""; - LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); + LLCoros::instance().launch("LLViewerMediaImpl::mimeDiscoveryCoro", + boost::bind(&LLViewerMediaImpl::mimeDiscoveryCoro, this, mMediaURL)); } else if("data" == scheme || "file" == scheme || "about" == scheme) { @@ -2685,6 +2583,66 @@ void LLViewerMediaImpl::navigateInternal() } } +void LLViewerMediaImpl::mimeDiscoveryCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("mimeDiscoveryCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + mMimeProbe = httpAdapter; + + httpOpts->setFollowRedirects(true); + httpOpts->setHeadersOnly(true); + + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, "*/*"); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, ""); + + LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts, httpHeaders); + + mMimeProbe.reset(); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Error retrieving media headers." << LL_ENDL; + } + + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; + + const std::string& mediaType = resultHeaders[HTTP_IN_HEADER_CONTENT_TYPE].asStringRef(); + + std::string::size_type idx1 = mediaType.find_first_of(";"); + std::string mimeType = mediaType.substr(0, idx1); + + // We now no longer need to check the error code returned from the probe. + // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. + // The probe was successful. + if (mimeType.empty()) + { + // Some sites don't return any content-type header at all. + // Treat an empty mime type as text/html. + mimeType = HTTP_CONTENT_TEXT_HTML; + } + + LL_DEBUGS() << "Media type \"" << mediaType << "\", mime type is \"" << mimeType << "\"" << LL_ENDL; + + // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. + // Make a local copy so we can call loadURI() afterwards. + + if (!mimeType.empty()) + { + if (initializeMedia(mimeType)) + { + loadURI(); + } + } +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateStop() { @@ -2783,7 +2741,7 @@ void LLViewerMediaImpl::update() { // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. } - else if(mMimeTypeProbe != NULL) + else if (!mMimeProbe.expired()) { // this media source is doing a MIME type probe -- don't try loading it again. } @@ -3673,18 +3631,10 @@ void LLViewerMediaImpl::setNavigateSuspended(bool suspend) void LLViewerMediaImpl::cancelMimeTypeProbe() { - if(mMimeTypeProbe != NULL) - { - // There doesn't seem to be a way to actually cancel an outstanding request. - // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. - mMimeTypeProbe->cancelRequest(); - - // The above should already have set mMimeTypeProbe to NULL. - if(mMimeTypeProbe != NULL) - { - LL_ERRS() << "internal error: mMimeTypeProbe is not NULL after cancelling request." << LL_ENDL; - } - } + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t probeAdapter = mMimeProbe.lock(); + + if (probeAdapter) + probeAdapter->cancelSuspendedOperation(); } void LLViewerMediaImpl::addObject(LLVOVolume* obj) diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 6803adfaa2..92d644c900 100755 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -40,6 +40,9 @@ #include "llnotificationptr.h" #include "llurl.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "llcorehttputil.h" class LLViewerMediaImpl; class LLUUID; @@ -161,11 +164,15 @@ public: static void setOnlyAudibleMediaTextureID(const LLUUID& texture_id); static LLSD getHeaders(); + static LLCore::HttpHeaders::ptr_t getHttpHeaders(); private: static void setOpenIDCookie(); static void onTeleportFinished(); - + + static void openIDSetupCoro(std::string openidUrl, std::string openidToken); + static void getOpenIDCookieCoro(std::string url); + static LLPluginCookieStore *sCookieStore; static LLURL sOpenIDURL; static std::string sOpenIDCookie; @@ -180,7 +187,6 @@ class LLViewerMediaImpl public: friend class LLViewerMedia; - friend class LLMimeDiscoveryResponder; LLViewerMediaImpl( const LLUUID& texture_id, @@ -453,7 +459,6 @@ private: S32 mProximity; F64 mProximityDistance; F64 mProximityCamera; - LLMimeDiscoveryResponder *mMimeTypeProbe; bool mMediaAutoPlay; std::string mMediaEntryURL; bool mInNearbyMediaList; // used by LLPanelNearbyMedia::refreshList() for performance reasons @@ -470,6 +475,10 @@ private: BOOL mIsUpdated ; std::list< LLVOVolume* > mObjectList ; + void mimeDiscoveryCoro(std::string url); + LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mMimeProbe; + bool mCanceling; + private: LLViewerMediaTexture *updatePlaceholderImage(); }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2505ae6a9c..d8ec44b132 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -390,32 +390,10 @@ void set_underclothes_menu_options() void set_merchant_SLM_menu() { - // DD-170 : SLM Alpha and Beta program : for the moment, we always show the SLM menu and - // tools so that all merchants can try out the UI, even if not migrated. - // *TODO : Keep SLM UI hidden for non migrated merchant in released viewer - - //if (LLMarketplaceData::instance().getSLMStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT) - //{ - // Merchant not migrated: show only the old Merchant Outbox menu - // gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE); - //} - //else - //{ - // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool - gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE); - LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); - gToolBarView->enableCommand(command->id(), true); - //} -} - -void set_merchant_outbox_menu(U32 status, const LLSD& content) -{ - // If the merchant is fully migrated, the API is disabled (503) and we won't show the old menu item. - // In all other cases, we show it. - if (status != MarketplaceErrorCodes::IMPORT_SERVER_API_DISABLED) - { - gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(TRUE); - } + // All other cases (new merchant, not merchant, migrated merchant): show the new Marketplace Listings menu and enable the tool + gMenuHolder->getChild<LLView>("MarketplaceListings")->setVisible(TRUE); + LLCommand* command = LLCommandManager::instance().getCommand("marketplacelistings"); + gToolBarView->enableCommand(command->id(), true); } void check_merchant_status() @@ -434,17 +412,6 @@ void check_merchant_status() // Launch an SLM test connection to get the merchant status LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); - - // Do the Merchant Outbox init only once per session - if (LLMarketplaceInventoryImporter::instance().getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED) - { - // Hide merchant outbox related menu item - gMenuHolder->getChild<LLView>("MerchantOutbox")->setVisible(FALSE); - - // Launch a Merchant Outbox test connection to get the migration status - LLMarketplaceInventoryImporter::instance().setStatusReportCallback(boost::bind(&set_merchant_outbox_menu,_1, _2)); - LLMarketplaceInventoryImporter::instance().initialize(); - } } } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index f8e50ba463..4f24dfafac 100755 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -62,11 +62,10 @@ #include "lluploaddialog.h" #include "lltrans.h" #include "llfloaterbuycurrency.h" +#include "llviewerassetupload.h" // linden libraries -#include "llassetuploadresponders.h" #include "lleconomy.h" -#include "llhttpclient.h" #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llsdutil.h" @@ -83,8 +82,9 @@ class LLFileEnableUpload : public view_listener_t { bool handleEvent(const LLSD& userdata) { - bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); - return new_value; + return true; +// bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); +// return new_value; } }; @@ -410,7 +410,6 @@ class LLFileUploadBulk : public view_listener_t } // TODO: - // Iterate over all files // Check extensions for uploadability, cost // Check user balance for entire cost // Charge user entire cost @@ -422,37 +421,33 @@ class LLFileUploadBulk : public view_listener_t LLFilePicker& picker = LLFilePicker::instance(); if (picker.getMultipleOpenFiles()) { - const std::string& filename = picker.getFirstFile(); - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - - upload_new_resource( - filename, - asset_name, - asset_name, - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms("Uploads"), - LLFloaterPerms::getGroupPerms("Uploads"), - LLFloaterPerms::getEveryonePerms("Uploads"), - display_name, - callback, - expected_upload_cost, - userdata); - - // *NOTE: Ew, we don't iterate over the file list here, - // we handle the next files in upload_done_callback() + std::string filename = picker.getFirstFile(); + S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + + while (!filename.empty()) + { + std::string name = gDirUtilp->getBaseFileName(filename, true); + + std::string asset_name = name; + LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); + LLStringUtil::replaceChar(asset_name, '|', '?'); + LLStringUtil::stripNonprintable(asset_name); + LLStringUtil::trim(asset_name); + + LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + filename, + asset_name, + asset_name, 0, + LLFolderType::FT_NONE, LLInventoryType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + expected_upload_cost)); + + upload_new_resource(uploadInfo, NULL, NULL); + + filename = picker.getNextFile(); + } } else { @@ -621,6 +616,7 @@ void handle_compress_image(void*) } } + LLUUID upload_new_resource( const std::string& src_filename, std::string name, @@ -636,276 +632,16 @@ LLUUID upload_new_resource( S32 expected_upload_cost, void *userdata) { - // Generate the temporary UUID. - std::string filename = gDirUtilp->getTempFilename(); - LLTransactionID tid; - LLAssetID uuid; - - LLSD args; - - std::string exten = gDirUtilp->getExtension(src_filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - LLAssetType::EType asset_type = LLAssetType::AT_NONE; - std::string error_message; - - BOOL error = FALSE; - - if (exten.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - error_message = llformat( - "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", - short_name.c_str()); - args["FILE"] = short_name; - upload_error(error_message, "NoFileExtension", filename, args); - return LLUUID(); - } - else if (codec != IMG_CODEC_INVALID) - { - // It's an image file, the upload procedure is the same for all - asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec )) - { - error_message = llformat( "Problem with file %s:\n\n%s\n", - src_filename.c_str(), LLImage::getLastError().c_str()); - args["FILE"] = src_filename; - args["ERROR"] = LLImage::getLastError(); - upload_error(error_message, "ProblemWithFile", filename, args); - return LLUUID(); - } - } - else if(exten == "wav") - { - asset_type = LLAssetType::AT_SOUND; // tag it as audio - S32 encode_result = 0; - - LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL; - - encode_result = encode_vorbis_file(src_filename, filename); - - if (LLVORBISENC_NOERR != encode_result) - { - switch(encode_result) - { - case LLVORBISENC_DEST_OPEN_ERR: - error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); - break; - - default: - error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); - break; - } - return LLUUID(); - } - } - else if(exten == "tmp") - { - // This is a generic .lin resource file - asset_type = LLAssetType::AT_OBJECT; - LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */ - if (in) - { - // read in the file header - char buf[16384]; /* Flawfinder: ignore */ - size_t readbytes; - S32 version; - if (fscanf(in, "LindenResource\nversion %d\n", &version)) - { - if (2 == version) - { - // *NOTE: This buffer size is hard coded into scanf() below. - char label[MAX_STRING]; /* Flawfinder: ignore */ - char value[MAX_STRING]; /* Flawfinder: ignore */ - S32 tokens_read; - while (fgets(buf, 1024, in)) - { - label[0] = '\0'; - value[0] = '\0'; - tokens_read = sscanf( /* Flawfinder: ignore */ - buf, - "%254s %254s\n", - label, value); - - LL_INFOS() << "got: " << label << " = " << value - << LL_ENDL; - - if (EOF == tokens_read) - { - fclose(in); - error_message = llformat("corrupt resource file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "CorruptResourceFile", filename, args); - return LLUUID(); - } - - if (2 == tokens_read) - { - if (! strcmp("type", label)) - { - asset_type = (LLAssetType::EType)(atoi(value)); - } - } - else - { - if (! strcmp("_DATA_", label)) - { - // below is the data section - break; - } - } - // other values are currently discarded - } - - } - else - { - fclose(in); - error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownResourceFileVersion", filename, args); - return LLUUID(); - } - } - else - { - // this is an original binary formatted .lin file - // start over at the beginning of the file - fseek(in, 0, SEEK_SET); - - const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256; - const S32 MAX_ASSET_NAME_LENGTH = 64; - S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH; - S16 type_num; - - // read in and throw out most of the header except for the type - if (fread(buf, header_size, 1, in) != 1) - { - LL_WARNS() << "Short read" << LL_ENDL; - } - memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */ - asset_type = (LLAssetType::EType)type_num; - } - - // copy the file's data segment into another file for uploading - LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - if (out) - { - while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ - { - if (fwrite(buf, 1, readbytes, out) != readbytes) - { - LL_WARNS() << "Short write" << LL_ENDL; - } - } - fclose(out); - } - else - { - fclose(in); - error_message = llformat( "Unable to create output file: %s", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "UnableToCreateOutputFile", filename, args); - return LLUUID(); - } - - fclose(in); - } - else - { - LL_INFOS() << "Couldn't open .lin file " << src_filename << LL_ENDL; - } - } - else if (exten == "bvh") - { - error_message = llformat("We do not currently support bulk upload of animation files\n"); - upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); - return LLUUID(); - } - else if (exten == "anim") - { - asset_type = LLAssetType::AT_ANIMATION; - filename = src_filename; - } - else - { - // Unknown extension - error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); - error = TRUE;; - } - - // gen a new transaction ID for this asset - tid.generate(); - if (!error) - { - uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - // copy this file into the vfs for upload - S32 file_size; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); - if (infile.getFileHandle()) - { - LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); - - file.setMaxSize(file_size); - - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while ((file_size = infile.read(copy_buf, buf_size))) - { - file.write(copy_buf, file_size); - } - } - else - { - error_message = llformat( "Unable to access output file: %s", filename.c_str()); - error = TRUE; - } - } - - if (!error) - { - std::string t_disp_name = display_name; - if (t_disp_name.empty()) - { - t_disp_name = src_filename; - } - upload_new_resource( - tid, - asset_type, - name, - desc, - compression_info, // tid - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms, - display_name, - callback, - expected_upload_cost, - userdata); - } - else - { - LL_WARNS() << error_message << LL_ENDL; - LLSD args; - args["ERROR_MESSAGE"] = error_message; - LLNotificationsUtil::add("ErrorMessage", args); - if(LLFile::remove(filename) == -1) - { - LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; - } - LLFilePicker::instance().reset(); - } + LLResourceUploadInfo::ptr_t uploadInfo(new LLNewFileResourceUploadInfo( + src_filename, + name, desc, compression_info, + destination_folder_type, inv_type, + next_owner_perms, group_perms, everyone_perms, + expected_upload_cost)); + upload_new_resource(uploadInfo, callback, userdata); - return uuid; + return LLUUID::null; } void upload_done_callback( @@ -1035,189 +771,62 @@ void upload_done_callback( } } -static LLAssetID upload_new_resource_prep( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - LLAssetID uuid = generate_asset_id_for_new_upload(tid); - - increase_new_upload_stats(asset_type); - - assign_defaults_and_show_upload_message( - asset_type, - inventory_type, - name, - display_name, - description); - - return uuid; -} - -LLSD generate_new_resource_upload_capability_body( - LLAssetType::EType asset_type, - const std::string& name, - const std::string& desc, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms) -{ - LLSD body; - - body["folder_id"] = gInventory.findCategoryUUIDForType( - (destination_folder_type == LLFolderType::FT_NONE) ? - (LLFolderType::EType) asset_type : - destination_folder_type); - - body["asset_type"] = LLAssetType::lookup(asset_type); - body["inventory_type"] = LLInventoryType::lookup(inv_type); - body["name"] = name; - body["description"] = desc; - body["next_owner_mask"] = LLSD::Integer(next_owner_perms); - body["group_mask"] = LLSD::Integer(group_perms); - body["everyone_mask"] = LLSD::Integer(everyone_perms); - - return body; -} - void upload_new_resource( - const LLTransactionID &tid, - LLAssetType::EType asset_type, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) + LLResourceUploadInfo::ptr_t &uploadInfo, + LLAssetStorage::LLStoreAssetCallback callback, + void *userdata) { if(gDisconnected) { return ; } - - LLAssetID uuid = - upload_new_resource_prep( - tid, - asset_type, - inv_type, - name, - display_name, - desc); - - if( LLAssetType::AT_SOUND == asset_type ) - { - add(LLStatViewer::UPLOAD_SOUND, 1); - } - else - if( LLAssetType::AT_TEXTURE == asset_type ) - { - add(LLStatViewer::UPLOAD_TEXTURE, 1); - } - else - if( LLAssetType::AT_ANIMATION == asset_type) - { - add(LLStatViewer::ANIMATION_UPLOADS, 1); - } - if(LLInventoryType::IT_NONE == inv_type) - { - inv_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(desc); - if(name.empty()) - { - name = "(No Name)"; - } - if(desc.empty()) - { - desc = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); - - LL_INFOS() << "*** Uploading: " << LL_ENDL; - LL_INFOS() << "Type: " << LLAssetType::lookup(asset_type) << LL_ENDL; - LL_INFOS() << "UUID: " << uuid << LL_ENDL; - LL_INFOS() << "Name: " << name << LL_ENDL; - LL_INFOS() << "Desc: " << desc << LL_ENDL; - LL_INFOS() << "Expected Upload Cost: " << expected_upload_cost << LL_ENDL; - LL_DEBUGS() << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << LL_ENDL; - LL_DEBUGS() << "Asset Type: " << LLAssetType::lookup(asset_type) << LL_ENDL; - - std::string url = gAgent.getRegion()->getCapability( - "NewFileAgentInventory"); +// uploadInfo->setAssetType(assetType); +// uploadInfo->setTransactionId(tid); + + + std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); if ( !url.empty() ) { - LL_INFOS() << "New Agent Inventory via capability" << LL_ENDL; - - LLSD body; - body = generate_new_resource_upload_capability_body( - asset_type, - name, - desc, - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms); - - LLHTTPClient::post( - url, - body, - new LLNewAgentInventoryResponder( - body, - uuid, - asset_type)); + LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } else { + uploadInfo->prepareUpload(); + uploadInfo->logPreparedUpload(); + LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; // check for adequate funds // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == asset_type || - LLAssetType::AT_TEXTURE == asset_type || - LLAssetType::AT_ANIMATION == asset_type) + if (LLAssetType::AT_SOUND == uploadInfo->getAssetType() || + LLAssetType::AT_TEXTURE == uploadInfo->getAssetType() || + LLAssetType::AT_ANIMATION == uploadInfo->getAssetType()) { S32 balance = gStatusBar->getBalance(); - if (balance < expected_upload_cost) + if (balance < uploadInfo->getExpectedUploadCost()) { // insufficient funds, bail on this upload LLStringUtil::format_map_t args; - args["NAME"] = name; - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); + args["NAME"] = uploadInfo->getName(); + args["AMOUNT"] = llformat("%d", uploadInfo->getExpectedUploadCost()); + LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), uploadInfo->getExpectedUploadCost()); return; } } LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = tid; - data->mAssetInfo.mUuid = uuid; - data->mAssetInfo.mType = asset_type; + data->mAssetInfo.mTransactionID = uploadInfo->getTransactionId(); + data->mAssetInfo.mUuid = uploadInfo->getAssetId(); + data->mAssetInfo.mType = uploadInfo->getAssetType(); data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = inv_type; - data->mNextOwnerPerm = next_owner_perms; - data->mExpectedUploadCost = expected_upload_cost; + data->mInventoryType = uploadInfo->getInventoryType(); + data->mNextOwnerPerm = uploadInfo->getNextOwnerPerms(); + data->mExpectedUploadCost = uploadInfo->getExpectedUploadCost(); data->mUserData = userdata; - data->mAssetInfo.setName(name); - data->mAssetInfo.setDescription(desc); - data->mPreferredLocation = destination_folder_type; + data->mAssetInfo.setName(uploadInfo->getName()); + data->mAssetInfo.setDescription(uploadInfo->getDescription()); + data->mPreferredLocation = uploadInfo->getDestinationFolderType(); LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; if (callback) @@ -1233,66 +842,6 @@ void upload_new_resource( } } -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) -{ - if ( gDisconnected ) - { - LLAssetID rv; - - rv.setNull(); - return rv; - } - - LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - - return uuid; -} - -void increase_new_upload_stats(LLAssetType::EType asset_type) -{ - if ( LLAssetType::AT_SOUND == asset_type ) - { - add(LLStatViewer::UPLOAD_SOUND, 1); - } - else if ( LLAssetType::AT_TEXTURE == asset_type ) - { - add(LLStatViewer::UPLOAD_TEXTURE, 1); - } - else if ( LLAssetType::AT_ANIMATION == asset_type ) - { - add(LLStatViewer::ANIMATION_UPLOADS, 1); - } -} - -void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - if ( LLInventoryType::IT_NONE == inventory_type ) - { - inventory_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(description); - - if ( name.empty() ) - { - name = "(No Name)"; - } - if ( description.empty() ) - { - description = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); -} - void init_menu_file() { diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 3034d00b22..6941b4dc0e 100755 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -34,45 +34,35 @@ #include "llthread.h" #include <queue> +#include "llviewerassetupload.h" + class LLTransactionID; void init_menu_file(); + LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); + const std::string& src_filename, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata); void upload_new_resource( - const LLTransactionID &tid, - LLAssetType::EType type, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata); + LLResourceUploadInfo::ptr_t &uploadInfo, + LLAssetStorage::LLStoreAssetCallback callback = NULL, + void *userdata = NULL); -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid); -void increase_new_upload_stats(LLAssetType::EType asset_type); void assign_defaults_and_show_upload_message( LLAssetType::EType asset_type, LLInventoryType::EType& inventory_type, @@ -80,26 +70,6 @@ void assign_defaults_and_show_upload_message( const std::string& display_name, std::string& description); -LLSD generate_new_resource_upload_capability_body( - LLAssetType::EType asset_type, - const std::string& name, - const std::string& desc, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms); - -void on_new_single_inventory_upload_complete( - LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - const std::string inventory_type_string, - const LLUUID& item_folder_id, - const std::string& item_name, - const std::string& item_description, - const LLSD& server_response, - S32 upload_price); - class LLFilePickerThread : public LLThread { //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread) public: diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 886725be79..4062228ae5 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -120,6 +120,8 @@ #include "llnotificationmanager.h" // #include "llexperiencecache.h" +#include "llexperiencecache.h" + #if LL_MSVC // disable boost::lexical_cast warning #pragma warning (disable:4702) @@ -3490,53 +3492,29 @@ void process_decline_callingcard(LLMessageSystem* msg, void**) LLNotificationsUtil::add("CallingCardDeclined"); } -class ChatTranslationReceiver : public LLTranslate::TranslationReceiver +void translateSuccess(LLChat chat, LLSD toastArgs, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language) { -public : - ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, - const LLChat &chat, const LLSD &toast_args) - : LLTranslate::TranslationReceiver(from_lang, to_lang), - m_chat(chat), - m_toastArgs(toast_args), - m_origMesg(mesg) - { - } - - static ChatTranslationReceiver* build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) - { - return new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args); - } - -protected: - void handleResponse(const std::string &translation, const std::string &detected_language) - { - // filter out non-interesting responeses - if ( !translation.empty() - && (mToLang != detected_language) - && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) ) - { - m_chat.mText += " (" + translation + ")"; - } + // filter out non-interesting responses + if (!translation.empty() + && (expectLang != detected_language) + && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0)) + { + chat.mText += " (" + translation + ")"; + } - LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs); - } + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); +} - void handleFailure(int status, const std::string& err_msg) - { - LL_WARNS() << "Translation failed for mesg " << m_origMesg << " toLang " << mToLang << " fromLang " << mFromLang << LL_ENDL; +void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string err_msg) +{ + std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg)); + LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages + chat.mText += " (" + msg + ")"; - std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg)); - LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages - m_chat.mText += " (" + msg + ")"; + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, toastArgs); +} - LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs); - } -private: - LLChat m_chat; - std::string m_origMesg; - LLSD m_toastArgs; -}; void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { LLChat chat; @@ -3772,8 +3750,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) const std::string from_lang = ""; // leave empty to trigger autodetect const std::string to_lang = LLTranslate::getTranslateLanguage(); - LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, args); - LLTranslate::translateMessage(result, from_lang, to_lang, mesg); + LLTranslate::translateMessage(from_lang, to_lang, mesg, + boost::bind(&translateSuccess, chat, args, mesg, from_lang, _1, _2), + boost::bind(&translateFailure, chat, args, _1, _2)); + } else { @@ -6468,17 +6448,14 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) if (!region) return false; - std::string lookup_url=region->getCapability("ExperiencePreferences"); - if(lookup_url.empty()) - return false; - LLSD permission; - LLSD data; - permission["permission"]="Block"; + LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), LLExperienceCache::ExperienceGetFn_t()); - data[experience.asString()]=permission; - LLHTTPClient::put(lookup_url, data, NULL); - data["experience"]=experience; - LLEventPumps::instance().obtain("experience_permission").post(data); + LLSD permission; + LLSD data; + permission["permission"] = "Block"; + data[experience.asString()] = permission; + data["experience"] = experience; + LLEventPumps::instance().obtain("experience_permission").post(data); } } return false; @@ -6653,7 +6630,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) else if(experienceid.notNull()) { payload["experience"]=experienceid; - LLExperienceCache::get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); + LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); return; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index ac3f07fcd8..190102ff0f 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4437,21 +4437,21 @@ S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) { // Invalid host == get from the agent's sim LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture( - uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost()); return setTETextureCore(te,image); } S32 LLViewerObject::setTENormalMap(const U8 te, const LLUUID& uuid) { LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( - uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost()); return setTENormalMapCore(te, image); } S32 LLViewerObject::setTESpecularMap(const U8 te, const LLUUID& uuid) { LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( - uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost()); return setTESpecularMapCore(te, image); } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 75732a1e19..5f01cdbb6f 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -78,6 +78,10 @@ #include "llappviewer.h" #include "llfloaterperms.h" #include "llvocache.h" +#include "llcorehttputil.h" + +#include <algorithm> +#include <iterator> extern F32 gMinObjectDistance; extern BOOL gAnimateTextures; @@ -795,190 +799,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) LLVOAvatar::cullAvatarsByPixelArea(); } -class LLObjectCostResponder : public LLCurl::Responder -{ - LOG_CLASS(LLObjectCostResponder); -public: - LLObjectCostResponder(const LLSD& object_ids) - : mObjectIDs(object_ids) - { - } - - // Clear's the global object list's pending - // request list for all objects requested - void clear_object_list_pending_requests() - { - // TODO*: No more hard coding - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) - { - gObjectList.onObjectCostFetchFailure(iter->asUUID()); - } - } - -private: - /* virtual */ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - - // TODO*: Error message to user - // For now just clear the request from the pending list - clear_object_list_pending_requests(); - } - - /* virtual */ void httpSuccess() - { - const LLSD& content = getContent(); - if ( !content.isMap() || content.has("error") ) - { - // Improper response or the request had an error, - // show an error to the user? - LL_WARNS() - << "Application level error when fetching object " - << "cost. Message: " << content["error"]["message"].asString() - << ", identifier: " << content["error"]["identifier"].asString() - << LL_ENDL; - - // TODO*: Adaptively adjust request size if the - // service says we've requested too many and retry - - // TODO*: Error message if not retrying - clear_object_list_pending_requests(); - return; - } - - // Success, grab the resource cost and linked set costs - // for an object if one was returned - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) - { - LLUUID object_id = iter->asUUID(); - - // Check to see if the request contains data for the object - if ( content.has(iter->asString()) ) - { - F32 link_cost = - content[iter->asString()]["linked_set_resource_cost"].asReal(); - F32 object_cost = - content[iter->asString()]["resource_cost"].asReal(); - - F32 physics_cost = content[iter->asString()]["physics_cost"].asReal(); - F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal(); - - gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost); - } - else - { - // TODO*: Give user feedback about the missing data? - gObjectList.onObjectCostFetchFailure(object_id); - } - } - } - -private: - LLSD mObjectIDs; -}; - - -class LLPhysicsFlagsResponder : public LLCurl::Responder -{ - LOG_CLASS(LLPhysicsFlagsResponder); -public: - LLPhysicsFlagsResponder(const LLSD& object_ids) - : mObjectIDs(object_ids) - { - } - - // Clear's the global object list's pending - // request list for all objects requested - void clear_object_list_pending_requests() - { - // TODO*: No more hard coding - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) - { - gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID()); - } - } - -private: - /* virtual */ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - - // TODO*: Error message to user - // For now just clear the request from the pending list - clear_object_list_pending_requests(); - } - - /* virtual void */ void httpSuccess() - { - const LLSD& content = getContent(); - if ( !content.isMap() || content.has("error") ) - { - // Improper response or the request had an error, - // show an error to the user? - LL_WARNS() - << "Application level error when fetching object " - << "physics flags. Message: " << content["error"]["message"].asString() - << ", identifier: " << content["error"]["identifier"].asString() - << LL_ENDL; - - // TODO*: Adaptively adjust request size if the - // service says we've requested too many and retry - - // TODO*: Error message if not retrying - clear_object_list_pending_requests(); - return; - } - - // Success, grab the resource cost and linked set costs - // for an object if one was returned - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) - { - LLUUID object_id = iter->asUUID(); - - // Check to see if the request contains data for the object - if ( content.has(iter->asString()) ) - { - const LLSD& data = content[iter->asString()]; - - S32 shape_type = data["PhysicsShapeType"].asInteger(); - - gObjectList.updatePhysicsShapeType(object_id, shape_type); - - if (data.has("Density")) - { - F32 density = data["Density"].asReal(); - F32 friction = data["Friction"].asReal(); - F32 restitution = data["Restitution"].asReal(); - F32 gravity_multiplier = data["GravityMultiplier"].asReal(); - - gObjectList.updatePhysicsProperties(object_id, - density, friction, restitution, gravity_multiplier); - } - } - else - { - // TODO*: Give user feedback about the missing data? - gObjectList.onPhysicsFlagsFetchFailure(object_id); - } - } - } - -private: - LLSD mObjectIDs; -}; - static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy"); void LLViewerObjectList::update(LLAgent &agent) @@ -1174,41 +994,8 @@ void LLViewerObjectList::fetchObjectCosts() if (!url.empty()) { - LLSD id_list; - U32 object_index = 0; - - for ( - std::set<LLUUID>::iterator iter = mStaleObjectCost.begin(); - iter != mStaleObjectCost.end(); - ) - { - // Check to see if a request for this object - // has already been made. - if ( mPendingObjectCost.find(*iter) == - mPendingObjectCost.end() ) - { - mPendingObjectCost.insert(*iter); - id_list[object_index++] = *iter; - } - - mStaleObjectCost.erase(iter++); - - if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) - { - break; - } - } - - if ( id_list.size() > 0 ) - { - LLSD post_data = LLSD::emptyMap(); - - post_data["object_ids"] = id_list; - LLHTTPClient::post( - url, - post_data, - new LLObjectCostResponder(id_list)); - } + LLCoros::instance().launch("LLViewerObjectList::fetchObjectCostsCoro", + boost::bind(&LLViewerObjectList::fetchObjectCostsCoro, this, url)); } else { @@ -1219,6 +1006,107 @@ void LLViewerObjectList::fetchObjectCosts() } } +/*static*/ +void LLViewerObjectList::reportObjectCostFailure(LLSD &objectList) +{ + // TODO*: No more hard coding + for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it) + { + gObjectList.onObjectCostFetchFailure(it->asUUID()); + } +} + + +void LLViewerObjectList::fetchObjectCostsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + + + uuid_set_t diff; + + std::set_difference(mStaleObjectCost.begin(), mStaleObjectCost.end(), + mPendingObjectCost.begin(), mPendingObjectCost.end(), + std::inserter(diff, diff.begin())); + + if (diff.empty()) + { + LL_INFOS() << "No outstanding object IDs to request." << LL_ENDL; + return; + } + + LLSD idList(LLSD::emptyArray()); + + for (uuid_set_t::iterator it = diff.begin(); it != diff.end(); ++it) + { + idList.append(*it); + mStaleObjectCost.erase(*it); + } + + mPendingObjectCost.insert(diff.begin(), diff.end()); + + LLSD postData = LLSD::emptyMap(); + + postData["object_ids"] = idList; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status || result.has("error")) + { + if (result.has("error")) + { + LL_WARNS() << "Application level error when fetching object " + << "cost. Message: " << result["error"]["message"].asString() + << ", identifier: " << result["error"]["identifier"].asString() + << LL_ENDL; + + // TODO*: Adaptively adjust request size if the + // service says we've requested too many and retry + } + reportObjectCostFailure(idList); + + return; + } + + // Success, grab the resource cost and linked set costs + // for an object if one was returned + for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it) + { + LLUUID objectId = it->asUUID(); + + // If the object was added to the StaleObjectCost set after it had been + // added to mPendingObjectCost it would still be in the StaleObjectCost + // set when we got the response back. + mStaleObjectCost.erase(objectId); + mPendingObjectCost.erase(objectId); + + // Check to see if the request contains data for the object + if (result.has(it->asString())) + { + LLSD objectData = result[it->asString()]; + + F32 linkCost = objectData["linked_set_resource_cost"].asReal(); + F32 objectCost = objectData["resource_cost"].asReal(); + F32 physicsCost = objectData["physics_cost"].asReal(); + F32 linkPhysicsCost = objectData["linked_set_physics_cost"].asReal(); + + gObjectList.updateObjectCost(objectId, objectCost, linkCost, physicsCost, linkPhysicsCost); + } + else + { + // TODO*: Give user feedback about the missing data? + gObjectList.onObjectCostFetchFailure(objectId); + } + } + +} + void LLViewerObjectList::fetchPhysicsFlags() { // issue http request for stale object physics flags @@ -1232,41 +1120,8 @@ void LLViewerObjectList::fetchPhysicsFlags() if (!url.empty()) { - LLSD id_list; - U32 object_index = 0; - - for ( - std::set<LLUUID>::iterator iter = mStalePhysicsFlags.begin(); - iter != mStalePhysicsFlags.end(); - ) - { - // Check to see if a request for this object - // has already been made. - if ( mPendingPhysicsFlags.find(*iter) == - mPendingPhysicsFlags.end() ) - { - mPendingPhysicsFlags.insert(*iter); - id_list[object_index++] = *iter; - } - - mStalePhysicsFlags.erase(iter++); - - if (object_index >= MAX_CONCURRENT_PHYSICS_REQUESTS) - { - break; - } - } - - if ( id_list.size() > 0 ) - { - LLSD post_data = LLSD::emptyMap(); - - post_data["object_ids"] = id_list; - LLHTTPClient::post( - url, - post_data, - new LLPhysicsFlagsResponder(id_list)); - } + LLCoros::instance().launch("LLViewerObjectList::fetchPhisicsFlagsCoro", + boost::bind(&LLViewerObjectList::fetchPhisicsFlagsCoro, this, url)); } else { @@ -1277,6 +1132,109 @@ void LLViewerObjectList::fetchPhysicsFlags() } } +/*static*/ +void LLViewerObjectList::reportPhysicsFlagFailure(LLSD &objectList) +{ + // TODO*: No more hard coding + for (LLSD::array_iterator it = objectList.beginArray(); it != objectList.endArray(); ++it) + { + gObjectList.onPhysicsFlagsFetchFailure(it->asUUID()); + } +} + +void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD idList; + U32 objectIndex = 0; + + for (uuid_set_t::iterator it = mStalePhysicsFlags.begin(); it != mStalePhysicsFlags.end();) + { + // Check to see if a request for this object + // has already been made. + if (mPendingPhysicsFlags.find(*it) == mPendingPhysicsFlags.end()) + { + mPendingPhysicsFlags.insert(*it); + idList[objectIndex++] = *it; + } + + mStalePhysicsFlags.erase(it++); + + if (objectIndex >= MAX_CONCURRENT_PHYSICS_REQUESTS) + { + break; + } + } + + if (idList.size() < 1) + { + LL_INFOS() << "No outstanding object physics flags to request." << LL_ENDL; + return; + } + + LLSD postData = LLSD::emptyMap(); + + postData["object_ids"] = idList; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status || result.has("error")) + { + if (result.has("error")) + { + LL_WARNS() << "Application level error when fetching object " + << "physics flags. Message: " << result["error"]["message"].asString() + << ", identifier: " << result["error"]["identifier"].asString() + << LL_ENDL; + + // TODO*: Adaptively adjust request size if the + // service says we've requested too many and retry + } + reportPhysicsFlagFailure(idList); + + return; + } + + // Success, grab the resource cost and linked set costs + // for an object if one was returned + for (LLSD::array_iterator it = idList.beginArray(); it != idList.endArray(); ++it) + { + LLUUID objectId = it->asUUID(); + + // Check to see if the request contains data for the object + if (result.has(it->asString())) + { + const LLSD& data = result[it->asString()]; + + S32 shapeType = data["PhysicsShapeType"].asInteger(); + + gObjectList.updatePhysicsShapeType(objectId, shapeType); + + if (data.has("Density")) + { + F32 density = data["Density"].asReal(); + F32 friction = data["Friction"].asReal(); + F32 restitution = data["Restitution"].asReal(); + F32 gravityMult = data["GravityMultiplier"].asReal(); + + gObjectList.updatePhysicsProperties(objectId, density, + friction, restitution, gravityMult); + } + } + else + { + // TODO*: Give user feedback about the missing data? + gObjectList.onPhysicsFlagsFetchFailure(objectId); + } + } +} void LLViewerObjectList::clearDebugText() { @@ -1563,8 +1521,6 @@ void LLViewerObjectList::updateObjectCost(LLViewerObject* object) void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost) { - mPendingObjectCost.erase(object_id); - LLViewerObject* object = findObject(object_id); if (object) { diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 594317cd9f..94c751acc6 100755 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -36,6 +36,8 @@ // project includes #include "llviewerobject.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLCamera; class LLNetMap; @@ -203,17 +205,17 @@ protected: vobj_list_t mMapObjects; - std::set<LLUUID> mDeadObjects; + uuid_set_t mDeadObjects; std::map<LLUUID, LLPointer<LLViewerObject> > mUUIDObjectMap; //set of objects that need to update their cost - std::set<LLUUID> mStaleObjectCost; - std::set<LLUUID> mPendingObjectCost; + uuid_set_t mStaleObjectCost; + uuid_set_t mPendingObjectCost; //set of objects that need to update their physics flags - std::set<LLUUID> mStalePhysicsFlags; - std::set<LLUUID> mPendingPhysicsFlags; + uuid_set_t mStalePhysicsFlags; + uuid_set_t mPendingPhysicsFlags; std::vector<LLDebugBeacon> mDebugBeacons; @@ -227,6 +229,14 @@ protected: std::set<LLViewerObject *> mSelectPickList; friend class LLViewerObject; + +private: + static void reportObjectCostFailure(LLSD &objectList); + void fetchObjectCostsCoro(std::string url); + + static void reportPhysicsFlagFailure(LLSD &obejectList); + void fetchPhisicsFlagsCoro(std::string url); + }; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 37b249dddd..828271da7a 100755 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -43,6 +43,7 @@ //#include "llfirstuse.h" #include "llpluginclassmedia.h" #include "llviewertexture.h" +#include "llcorehttputil.h" // Static Variables @@ -457,6 +458,7 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * } // Static ///////////////////////////////////////////////////////////////////////////////////////// +// *TODO: I can not find any active code where this method is called... void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) { std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia"); @@ -467,7 +469,9 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) body["agent-id"] = gAgent.getID(); body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); body["url"] = url; - LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(region_url, body, + "Media Navigation sent to sim.", "Media Navigation failed to send to sim."); } else { diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 2a6b105cab..f8c13239a0 100755 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -67,6 +67,7 @@ #include "roles_constants.h" #include "llweb.h" #include "llvieweraudio.h" +#include "llcorehttputil.h" const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; @@ -1286,10 +1287,13 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) { - if(!parcel) return; + if(!parcel) + return; LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); - if (!region) return; + if (!region) + return; + //LL_INFOS() << "found region: " << region->getName() << LL_ENDL; LLSD body; @@ -1302,7 +1306,9 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag parcel->packMessage(body); LL_INFOS() << "Sending parcel properties update via capability to: " << url << LL_ENDL; - LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); + + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "Parcel Properties sent to sim.", "Parcel Properties failed to send to sim."); } else { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 6af3e40f01..b0280ef3e0 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -34,7 +34,6 @@ #include "llavatarnamecache.h" // name lookup cap url #include "llfloaterreg.h" #include "llmath.h" -#include "llhttpclient.h" #include "llregionflags.h" #include "llregionhandle.h" #include "llsurface.h" @@ -47,8 +46,6 @@ #include "llagentcamera.h" #include "llavatarrenderinfoaccountant.h" #include "llcallingcard.h" -#include "llcaphttpsender.h" -#include "llcapabilitylistener.h" #include "llcommandhandler.h" #include "lldir.h" #include "lleventpoll.h" @@ -78,6 +75,9 @@ #include "llviewerdisplay.h" #include "llviewerwindow.h" #include "llprogressview.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" #ifdef LL_WINDOWS #pragma warning(disable:4355) @@ -92,7 +92,6 @@ // We want to allow for seed cap retry, but its not useful after that 60 seconds. // Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; -const F32 CAP_REQUEST_TIMEOUT = 18; // Even though we gave up on login, keep trying for caps after we are logged in: const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; @@ -105,31 +104,62 @@ typedef std::map<std::string, std::string> CapabilityMap; static void log_capabilities(const CapabilityMap &capmap); -class LLViewerRegionImpl { +// support for secondlife:///app/region/{REGION} SLapps +// N.B. this is defined to work exactly like the classic secondlife://{REGION} +// However, the later syntax cannot support spaces in the region name because +// spaces (and %20 chars) are illegal in the hostname of an http URL. Some +// browsers let you get away with this, but some do not (such as Qt's Webkit). +// Hence we introduced the newer secondlife:///app/region alternative. +class LLRegionHandler : public LLCommandHandler +{ +public: + // requests will be throttled from a non-trusted browser + LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + // make sure that we at least have a region name + int num_params = params.size(); + if (num_params < 1) + { + return false; + } + + // build a secondlife://{PLACE} SLurl from this SLapp + std::string url = "secondlife://"; + for (int i = 0; i < num_params; i++) + { + if (i > 0) + { + url += "/"; + } + url += params[i].asString(); + } + + // Process the SLapp as if it was a secondlife://{PLACE} SLurl + LLURLDispatcher::dispatch(url, "clicked", web, true); + return true; + } + +}; +LLRegionHandler gRegionHandler; + + +class LLViewerRegionImpl +{ public: - LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) - : mHost(host), - mCompositionp(NULL), - mEventPoll(NULL), - mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), - mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), - mSeedCapAttempts(0), - mHttpResponderID(0), - mLastCameraUpdate(0), - mLastCameraOrigin(), - mVOCachePartition(NULL), - mLandp(NULL), - // I'd prefer to set the LLCapabilityListener name to match the region - // name -- it's disappointing that's not available at construction time. - // We could instead store an LLCapabilityListener*, making - // setRegionNameAndZone() replace the instance. Would that pose - // consistency problems? Can we even request a capability before calling - // setRegionNameAndZone()? - // For testability -- the new Michael Feathers paradigm -- - // LLCapabilityListener binds all the globals it expects to need at - // construction time. - mCapabilityListener(host.getString(), gMessageSystem, *region, - gAgent.getID(), gAgent.getSessionID()) + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host): + mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), + mSeedCapAttempts(0), + mHttpResponderID(0), + mLastCameraUpdate(0), + mLastCameraOrigin(), + mVOCachePartition(NULL), + mLandp(NULL) {} void buildCapabilityNames(LLSD& capabilityNames); @@ -181,220 +211,292 @@ public: S32 mHttpResponderID; - /// Post an event to this LLCapabilityListener to invoke a capability message on - /// this LLViewerRegion's server - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLCapabilityListener mCapabilityListener; - //spatial partitions for objects in this region std::vector<LLViewerOctreePartition*> mObjectPartition; - LLVector3 mLastCameraOrigin; - U32 mLastCameraUpdate; -}; - -// support for secondlife:///app/region/{REGION} SLapps -// N.B. this is defined to work exactly like the classic secondlife://{REGION} -// However, the later syntax cannot support spaces in the region name because -// spaces (and %20 chars) are illegal in the hostname of an http URL. Some -// browsers let you get away with this, but some do not (such as Qt's Webkit). -// Hence we introduced the newer secondlife:///app/region alternative. -class LLRegionHandler : public LLCommandHandler -{ -public: - // requests will be throttled from a non-trusted browser - LLRegionHandler() : LLCommandHandler("region", UNTRUSTED_THROTTLE) {} - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) - { - // make sure that we at least have a region name - int num_params = params.size(); - if (num_params < 1) - { - return false; - } - - // build a secondlife://{PLACE} SLurl from this SLapp - std::string url = "secondlife://"; - for (int i = 0; i < num_params; i++) - { - if (i > 0) - { - url += "/"; - } - url += params[i].asString(); - } + LLVector3 mLastCameraOrigin; + U32 mLastCameraUpdate; - // Process the SLapp as if it was a secondlife://{PLACE} SLurl - LLURLDispatcher::dispatch(url, "clicked", web, true); - return true; - } + void requestBaseCapabilitiesCoro(U64 regionHandle); + void requestBaseCapabilitiesCompleteCoro(U64 regionHandle); + void requestSimulatorFeatureCoro(std::string url, U64 regionHandle); }; -LLRegionHandler gRegionHandler; -class BaseCapabilitiesComplete : public LLHTTPClient::Responder +void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) { - LOG_CLASS(BaseCapabilitiesComplete); -public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) - : mRegionHandle(region_handle), mID(id) - { } - virtual ~BaseCapabilitiesComplete() - { } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) - { - return new BaseCapabilitiesComplete(region_handle, id); - } + LLSD result; + LLViewerRegion *regionp = NULL; -private: - /* virtual */void httpFailure() - { - LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if (regionp) - { - regionp->failedSeedCapability(); - } - } + // This loop is used for retrying a capabilities request. + do + { + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + std::string url = regionp->getCapability("Seed"); + if (url.empty()) + { + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + // After a few attempts, continue login. But keep trying to get the caps: + if (mSeedCapAttempts >= mSeedCapMaxAttemptsBeforeLogin && + STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); + } + + if (mSeedCapAttempts > mSeedCapMaxAttempts) + { + // *TODO: Give a user pop-up about this error? + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + S32 id = ++mHttpResponderID; + ++mSeedCapAttempts; + + LLSD capabilityNames = LLSD::emptyArray(); + buildCapabilityNames(capabilityNames); + + LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url + << " (attempt #" << mSeedCapAttempts << ")" << LL_ENDL; + + regionp = NULL; + result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + if (id != mHttpResponderID) // region is no longer referring to this request + { + LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; + // setup for retry. + continue; + } + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; + // setup for retry. + continue; + } + + // remove the http_result from the llsd + result.erase("http_result"); + + LLSD::map_const_iterator iter; + for (iter = result.beginMap(); iter != result.endMap(); ++iter) + { + regionp->setCapability(iter->first, iter->second); + + LL_DEBUGS("AppInit", "Capabilities") + << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; + } - /* virtual */ void httpSuccess() - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region was removed - { - LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder - { - LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; - regionp->failedSeedCapability(); - return ; - } +#if 0 + log_capabilities(mCapabilities); +#endif - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - regionp->setCapability(iter->first, iter->second); + regionp->setCapabilitiesReceived(true); - LL_DEBUGS("AppInit", "Capabilities") - << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; + if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); + } - /* HACK we're waiting for the ServerReleaseNotes */ - if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) - { - regionp->showReleaseNotes(); - } - } + break; + } + while (true); - regionp->setCapabilitiesReceived(true); + if (regionp && regionp->isCapabilityAvailable("ServerReleaseNotes") && + regionp->getReleaseNotesRequested()) + { // *HACK: we're waiting for the ServerReleaseNotes + regionp->showReleaseNotes(); + } - if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - } +} -private: - U64 mRegionHandle; - S32 mID; -}; -class BaseCapabilitiesCompleteTracker : public LLHTTPClient::Responder +void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) { - LOG_CLASS(BaseCapabilitiesCompleteTracker); -public: - BaseCapabilitiesCompleteTracker( U64 region_handle) - : mRegionHandle(region_handle) - { } - - virtual ~BaseCapabilitiesCompleteTracker() - { } + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - static BaseCapabilitiesCompleteTracker* build( U64 region_handle ) - { - return new BaseCapabilitiesCompleteTracker( region_handle ); - } + LLSD result; + LLViewerRegion *regionp = NULL; -private: - /* virtual */ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - } + // This loop is used for retrying a capabilities request. + do + { + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + std::string url = regionp->getCapabilityDebug("Seed"); + if (url.empty()) + { + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + LLSD capabilityNames = LLSD::emptyArray(); + buildCapabilityNames(capabilityNames); + + LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << LL_ENDL; + + regionp = NULL; + result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; + break; // no retry + } + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + // remove the http_result from the llsd + result.erase("http_result"); + + LLSD::map_const_iterator iter; + for (iter = result.beginMap(); iter != result.endMap(); ++iter) + { + regionp->setCapabilityDebug(iter->first, iter->second); + //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; + } - /* virtual */ void httpSuccess() - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if( !regionp ) - { - LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } +#if 0 + log_capabilities(mCapabilities); +#endif - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - regionp->setCapabilityDebug(iter->first, iter->second); - //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<<iter->first<<" "<< iter->second<<LL_ENDL; - } - - if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) - { - LL_WARNS("AppInit", "Capabilities") - << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " - << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() - << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() - << LL_ENDL; + if (mCapabilities.size() != mSecondCapabilitiesTracker.size()) + { + LL_WARNS("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << mCapabilities.size() + << " mSecondCapabilitiesTracker == " << mSecondCapabilitiesTracker.size() + << LL_ENDL; #ifdef DEBUG_CAPS_GRANTS - LL_WARNS("AppInit", "Capabilities") - << "Initial Base capabilities: " << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") + << "Initial Base capabilities: " << LL_ENDL; - log_capabilities(regionp->getRegionImpl()->mCapabilities); + log_capabilities(mCapabilities); - LL_WARNS("AppInit", "Capabilities") - << "Latest base capabilities: " << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") + << "Latest base capabilities: " << LL_ENDL; - log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + log_capabilities(mSecondCapabilitiesTracker); #endif - if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) - { - // *HACK Since we were granted more base capabilities in this grant request than the initial, replace - // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a - // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the - // inventory api capability grants. - - // Need to clear a std::map before copying into it because old keys take precedence. - regionp->getRegionImplNC()->mCapabilities.clear(); - regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; - } - } - else - { - LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; - } - regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); - } + if (mSecondCapabilitiesTracker.size() > mCapabilities.size()) + { + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + // Need to clear a std::map before copying into it because old keys take precedence. + mCapabilities.clear(); + mCapabilities = mSecondCapabilitiesTracker; + } + } + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + mSecondCapabilitiesTracker.clear(); + } + while (false); -private: - U64 mRegionHandle; -}; +} + +void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 regionHandle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("BaseCapabilitiesRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLViewerRegion *regionp = NULL; + S32 attemptNumber = 0; + // This loop is used for retrying a capabilities request. + do + { + ++attemptNumber; + + if (attemptNumber > MAX_CAP_REQUEST_ATTEMPTS) + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Retries count exceeded attempting to get Simulator feature from " + << url << LL_ENDL; + break; + } + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + regionp = NULL; + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("AppInit", "SimulatorFeatures") << "HttpStatus error retrying" << LL_ENDL; + continue; + } + + // remove the http_result from the llsd + result.erase("http_result"); + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL; + break; // this error condition is not recoverable. + } + + regionp->setSimulatorFeatures(result); + + break; + } + while (true); + +} LLViewerRegion::LLViewerRegion(const U64 &handle, const LLHost &host, @@ -515,8 +617,9 @@ LLViewerRegion::~LLViewerRegion() delete mParcelOverlay; delete mImpl->mLandp; delete mImpl->mEventPoll; +#if 0 LLHTTPSender::clearSender(mImpl->mHost); - +#endif std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); saveObjectCache(); @@ -525,11 +628,6 @@ LLViewerRegion::~LLViewerRegion() mImpl = NULL; } -LLEventPump& LLViewerRegion::getCapAPI() const -{ - return mImpl->mCapabilityListener.getCapAPI(); -} - /*virtual*/ const LLHost& LLViewerRegion::getHost() const { @@ -2730,7 +2828,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); capabilityNames.append("IncrementCOFVersion"); - AISCommand::getCapabilityNames(capabilityNames); + AISAPI::getCapNames(capabilityNames); capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetExperiences"); @@ -2810,15 +2908,14 @@ void LLViewerRegion::setSeedCapability(const std::string& url) if (getCapability("Seed") == url) { setCapabilityDebug("Seed", url); - LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + LL_WARNS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << url << LL_ENDL; //Instead of just returning we build up a second set of seed caps and compare them //to the "original" seed cap received and determine why there is problem! - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames( capabilityNames ); - LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() ), - LLSD(), CAP_REQUEST_TIMEOUT ); + std::string coroname = + LLCoros::instance().launch("LLEnvironmentRequest::requestBaseCapabilitiesCompleteCoro", + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro, mImpl, getHandle())); return; } @@ -2828,15 +2925,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url) mImpl->mCapabilities.clear(); setCapability("Seed", url); - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - LL_INFOS() << "posting to seed " << url << LL_ENDL; + std::string coroname = + LLCoros::instance().launch("LLViewerRegionImpl::requestBaseCapabilitiesCoro", + boost::bind(&LLViewerRegionImpl::requestBaseCapabilitiesCoro, mImpl, getHandle())); - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); + LL_INFOS("AppInit", "Capabilities") << "Launching " << coroname << " requesting seed capabilities from " << url << LL_ENDL; } S32 LLViewerRegion::getNumSeedCapRetries() @@ -2844,94 +2937,6 @@ S32 LLViewerRegion::getNumSeedCapRetries() return mImpl->mSeedCapAttempts; } -void LLViewerRegion::failedSeedCapability() -{ - // Should we retry asking for caps? - mImpl->mSeedCapAttempts++; - std::string url = getCapability("Seed"); - if ( url.empty() ) - { - LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; - return; - } - // After a few attempts, continue login. We will keep trying once in-world: - if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && - STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } - - if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) - { - LLSD capabilityNames = LLSD::emptyArray(); - mImpl->buildCapabilityNames(capabilityNames); - - LL_INFOS() << "posting to seed " << url << " (retry " - << mImpl->mSeedCapAttempts << ")" << LL_ENDL; - - S32 id = ++mImpl->mHttpResponderID; - LLHTTPClient::post(url, capabilityNames, - BaseCapabilitiesComplete::build(getHandle(), id), - LLSD(), CAP_REQUEST_TIMEOUT); - } - else - { - // *TODO: Give a user pop-up about this error? - LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; - } -} - -class SimulatorFeaturesReceived : public LLHTTPClient::Responder -{ - LOG_CLASS(SimulatorFeaturesReceived); -public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - /* virtual */ void httpFailure() - { - LL_WARNS("AppInit", "SimulatorFeatures") << dumpResponse() << LL_ENDL; - retry(); - } - - /* virtual */ void httpSuccess() - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS("AppInit", "SimulatorFeatures") - << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - regionp->setSimulatorFeatures(content); - } - - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; -}; - - void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") @@ -2942,12 +2947,16 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u } else if(name == "UntrustedSimulatorMessage") { - LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); + mImpl->mHost.setUntrustedSimulatorCap(url); } else if (name == "SimulatorFeatures") { // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); + std::string coroname = + LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", + boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); + + LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL; } else { @@ -2970,9 +2979,20 @@ void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::stri mHttpUrl = url ; } } +} +std::string LLViewerRegion::getCapabilityDebug(const std::string& name) const +{ + CapabilityMap::const_iterator iter = mImpl->mSecondCapabilitiesTracker.find(name); + if (iter == mImpl->mSecondCapabilitiesTracker.end()) + { + return ""; + } + + return iter->second; } + bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) { return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; @@ -3025,7 +3045,7 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) { mCapabilitiesReceivedSignal(getRegionID()); - LLFloaterPermsDefault::sendInitialPerms(); + //LLFloaterPermsDefault::sendInitialPerms(); // This is a single-shot signal. Forget callbacks to save resources. mCapabilitiesReceivedSignal.disconnect_all_slots(); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c14fa5aee8..8c4966369c 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -40,7 +40,6 @@ #include "llweb.h" #include "llcapabilityprovider.h" #include "m4math.h" // LLMatrix4 -#include "llhttpclient.h" #include "llframetimer.h" // Surface id's @@ -62,7 +61,6 @@ class LLVOCache; class LLVOCacheEntry; class LLSpatialPartition; class LLEventPump; -class LLCapabilityListener; class LLDataPacker; class LLDataPackerBinaryBuffer; class LLHost; @@ -253,13 +251,14 @@ public: // Get/set named capability URLs for this region. void setSeedCapability(const std::string& url); - void failedSeedCapability(); S32 getNumSeedCapRetries(); void setCapability(const std::string& name, const std::string& url); void setCapabilityDebug(const std::string& name, const std::string& url); bool isCapabilityAvailable(const std::string& name) const; // implements LLCapabilityProvider virtual std::string getCapability(const std::string& name) const; + std::string getCapabilityDebug(const std::string& name) const; + // has region received its final (not seed) capability list? bool capabilitiesReceived() const; @@ -269,10 +268,6 @@ public: static bool isSpecialCapabilityName(const std::string &name); void logActiveCapabilities() const; - /// Get LLEventPump on which we listen for capability requests - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLEventPump& getCapAPI() const; - /// implements LLCapabilityProvider /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index f60829e9e8..2c3067cd3a 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -60,6 +60,7 @@ #include "llfeaturemanager.h" #include "llviewernetwork.h" #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llcorehttputil.h" namespace LLStatViewer { @@ -410,24 +411,6 @@ void update_statistics() } } -class ViewerStatsResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(ViewerStatsResponder); -public: - ViewerStatsResponder() { } - -private: - /* virtual */ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - } - - /* virtual */ void httpSuccess() - { - LL_INFOS() << "OK" << LL_ENDL; - } -}; - /* * The sim-side LLSD is in newsim/llagentinfo.cpp:forwardViewerStats. * @@ -618,8 +601,8 @@ void send_stats() body["MinimalSkin"] = false; LLViewerStats::getInstance()->addToMessage(body); - LLHTTPClient::post(url, body, new ViewerStatsResponder()); - + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "Statistics posted to sim", "Failed to post statistics to sim"); LLViewerStats::instance().getRecording().resume(); } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index aed7e94945..e496cb9f78 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -266,7 +266,7 @@ class LLViewerFetchedTexture : public LLViewerTexture protected: /*virtual*/ ~LLViewerFetchedTexture(); public: - LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); + LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE); LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps); LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE); @@ -498,7 +498,7 @@ protected: S32 mCachedRawDiscardLevel; BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit. - LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator + LLHost mTargetHost; // if invalid, just request from agent's simulator // Timers LLFrameTimer mLastPacketTimer; // Time since last packet. @@ -528,7 +528,7 @@ protected: /*virtual*/ ~LLViewerLODTexture(){} public: - LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); + LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost(), BOOL usemipmaps = TRUE); LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE); /*virtual*/ S8 getType() const; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 926c40307b..2fbd9f0acb 100755 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -236,7 +236,7 @@ void LLViewerTextureList::shutdown() if (!image->hasGLTexture() || !image->getUseDiscard() || image->needsAux() || - image->getTargetHost() != LLHost::invalid || + !image->getTargetHost().isInvalid() || !image->getUrl().empty() ) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f753448770..db949437a7 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8095,7 +8095,7 @@ LLHost LLVOAvatar::getObjectHost() const } else { - return LLHost::invalid; + return LLHost(); } } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index c1ca0aed69..e7dee14387 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -65,6 +65,7 @@ #include "llsdutil.h" #include "llstartup.h" #include "llsdserialize.h" +#include "llcorehttputil.h" #if LL_MSVC // disable boost::lexical_cast warning @@ -106,6 +107,9 @@ void selfClearPhases() using namespace LLAvatarAppearanceDefines; + +LLSD summarize_by_buckets(std::vector<LLSD> in_records, std::vector<std::string> by_fields, std::string val_field); + /********************************************************************************* ** ** ** Begin private LLVOAvatarSelf Support classes @@ -128,25 +132,6 @@ struct LocalTextureData LLTextureEntry *mTexEntry; }; -// TODO - this class doesn't really do anything, could just use a base -// class responder if nothing else gets added. -class LLHoverHeightResponder: public LLHTTPClient::Responder -{ -public: - LLHoverHeightResponder(): LLHTTPClient::Responder() {} - -private: - void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - } - - void httpSuccess() - { - LL_INFOS() << dumpResponse() << LL_ENDL; - } -}; - //----------------------------------------------------------------------------- // Callback data //----------------------------------------------------------------------------- @@ -181,7 +166,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, mRegionCrossingCount(0), // Value outside legal range, so will always be a mismatch the // first time through. - mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)) + mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)), + mInitialMetric(true), + mMetricSequence(0) { mMotionController.mIsSelf = TRUE; @@ -2164,43 +2151,76 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const return text; } -class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder -{ - LOG_CLASS(ViewerAppearanceChangeMetricsResponder); -public: - ViewerAppearanceChangeMetricsResponder( S32 expected_sequence, - volatile const S32 & live_sequence, - volatile bool & reporting_started): - mExpectedSequence(expected_sequence), - mLiveSequence(live_sequence), - mReportingStarted(reporting_started) - { - } - -private: - /* virtual */ void httpSuccess() - { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - - gPendingMetricsUploads--; - if (mLiveSequence == mExpectedSequence) - { - mReportingStarted = true; - } - } - - /* virtual */ void httpFailure() - { - // if we add retry, this should be removed from the httpFailure case - LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; - gPendingMetricsUploads--; - } - -private: - S32 mExpectedSequence; - volatile const S32 & mLiveSequence; - volatile bool & mReportingStarted; -}; +void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("appearanceChangeMetrics", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + S32 currentSequence = mMetricSequence; + if (S32_MAX == ++mMetricSequence) + mMetricSequence = 0; + + LLSD msg; + msg["message"] = "ViewerAppearanceChangeMetrics"; + msg["session_id"] = gAgentSessionID; + msg["agent_id"] = gAgentID; + msg["sequence"] = currentSequence; + msg["initial"] = mInitialMetric; + msg["break"] = false; + msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); + + // Status of our own rezzing. + msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); + + // Status of all nearby avs including ourself. + msg["nearby"] = LLSD::emptyArray(); + std::vector<S32> rez_counts; + LLVOAvatar::getNearbyRezzedStats(rez_counts); + for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat) + { + std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); + msg["nearby"][rez_status_name] = rez_counts[rez_stat]; + } + + // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); + std::vector<std::string> by_fields; + by_fields.push_back("timer_name"); + by_fields.push_back("completed"); + by_fields.push_back("grid_x"); + by_fields.push_back("grid_y"); + by_fields.push_back("is_using_server_bakes"); + by_fields.push_back("is_self"); + by_fields.push_back("central_bake_version"); + LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed")); + msg["timers"] = summary; + + mPendingTimerRecords.clear(); + + LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL; + + gPendingMetricsUploads++; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, msg); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + gPendingMetricsUploads--; + + if (!status) + { + LL_WARNS("Avatar") << "Unable to upload statistics" << LL_ENDL; + return; + } + else + { + LL_INFOS("Avatar") << "Statistics upload OK" << LL_ENDL; + mInitialMetric = false; + } +} bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send) { @@ -2278,51 +2298,7 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records, void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() { - static volatile bool reporting_started(false); - static volatile S32 report_sequence(0); - - LLSD msg; - msg["message"] = "ViewerAppearanceChangeMetrics"; - msg["session_id"] = gAgentSessionID; - msg["agent_id"] = gAgentID; - msg["sequence"] = report_sequence; - msg["initial"] = !reporting_started; - msg["break"] = false; - msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); - - // Status of our own rezzing. - msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); - - // Status of all nearby avs including ourself. - msg["nearby"] = LLSD::emptyArray(); - std::vector<S32> rez_counts; - LLVOAvatar::getNearbyRezzedStats(rez_counts); - for (S32 rez_stat=0; rez_stat < rez_counts.size(); ++rez_stat) - { - std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); - msg["nearby"][rez_status_name] = rez_counts[rez_stat]; - } - - // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); - std::vector<std::string> by_fields; - by_fields.push_back("timer_name"); - by_fields.push_back("completed"); - by_fields.push_back("grid_x"); - by_fields.push_back("grid_y"); - by_fields.push_back("is_using_server_bakes"); - by_fields.push_back("is_self"); - by_fields.push_back("central_bake_version"); - LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed")); - msg["timers"] = summary; - - mPendingTimerRecords.clear(); - - // Update sequence number - if (S32_MAX == ++report_sequence) - report_sequence = 0; - - LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL; - std::string caps_url; + std::string caps_url; if (getRegion()) { // runway - change here to activate. @@ -2330,13 +2306,9 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() } if (!caps_url.empty()) { - gPendingMetricsUploads++; - LLCurlRequest::headers_t headers; - LLHTTPClient::post(caps_url, - msg, - new ViewerAppearanceChangeMetricsResponder(report_sequence, - report_sequence, - reporting_started)); + + LLCoros::instance().launch("LLVOAvatarSelf::appearanceChangeMetricsCoro", + boost::bind(&LLVOAvatarSelf::appearanceChangeMetricsCoro, this, caps_url)); mTimeSinceLastRezMessage.reset(); } } @@ -2759,8 +2731,12 @@ void LLVOAvatarSelf::sendHoverHeight() const update["hover_height"] = hover_offset[2]; LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL; - LLHTTPClient::post(url, update, new LLHoverHeightResponder); + // *TODO: - this class doesn't really do anything, could just use a base + // class responder if nothing else gets added. + // (comment from removed Responder) + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, update, + "Hover hight sent to sim", "Hover hight not sent to sim"); mLastHoverOffsetSent = hover_offset; } } diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 257a760eeb..cdd82a8a44 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -31,6 +31,8 @@ #include "llviewertexture.h" #include "llvoavatar.h" #include <map> +#include "lleventcoro.h" +#include "llcoros.h" struct LocalTextureData; class LLInventoryCallback; @@ -394,6 +396,9 @@ private: F32 mDebugBakedTextureTimes[LLAvatarAppearanceDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture void debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + void appearanceChangeMetricsCoro(std::string url); + bool mInitialMetric; + S32 mMetricSequence; /** Diagnostics ** ** *******************************************************************************/ diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 426ca332e4..3abb716593 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -28,7 +28,6 @@ #include "llagent.h" #include "llfloaterreg.h" -#include "llhttpclient.h" #include "llimview.h" #include "llnotifications.h" #include "llnotificationsutil.h" @@ -37,7 +36,7 @@ #include "llviewercontrol.h" #include "llviewerregion.h" #include "llvoicechannel.h" - +#include "llcorehttputil.h" LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; @@ -52,71 +51,6 @@ BOOL LLVoiceChannel::sSuspended = FALSE; // const U32 DEFAULT_RETRIES_COUNT = 3; - -class LLVoiceCallCapResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLVoiceCallCapResponder); -public: - LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - -protected: - // called with bad status codes - virtual void httpFailure(); - virtual void httpSuccess(); - -private: - LLUUID mSessionID; -}; - - -void LLVoiceCallCapResponder::httpFailure() -{ - LL_WARNS("Voice") << dumpResponse() << LL_ENDL; - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); - if ( channelp ) - { - if ( HTTP_FORBIDDEN == getStatus() ) - { - //403 == no ability - LLNotificationsUtil::add( - "VoiceNotAllowed", - channelp->getNotifyArgs()); - } - else - { - LLNotificationsUtil::add( - "VoiceCallGenericError", - channelp->getNotifyArgs()); - } - channelp->deactivate(); - } -} - -void LLVoiceCallCapResponder::httpSuccess() -{ - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); - if (channelp) - { - //*TODO: DEBUG SPAM - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " - << iter->first << LL_ENDL; - } - - channelp->setChannelInfo( - content["voice_credentials"]["channel_uri"].asString(), - content["voice_credentials"]["channel_credentials"].asString()); - } -} - // // LLVoiceChannel // @@ -545,12 +479,9 @@ void LLVoiceChannelGroup::getChannelInfo() if (region) { std::string url = region->getCapability("ChatSessionRequest"); - LLSD data; - data["method"] = "call"; - data["session-id"] = mSessionID; - LLHTTPClient::post(url, - data, - new LLVoiceCallCapResponder(mSessionID)); + + LLCoros::instance().launch("LLVoiceChannelGroup::voiceCallCapCoro", + boost::bind(&LLVoiceChannelGroup::voiceCallCapCoro, this, url)); } } @@ -673,6 +604,66 @@ void LLVoiceChannelGroup::setState(EState state) } } +void LLVoiceChannelGroup::voiceCallCapCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceCallCapCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD postData; + postData["method"] = "call"; + postData["session-id"] = mSessionID; + + LL_INFOS("Voice", "voiceCallCapCoro") << "Generic POST for " << url << LL_ENDL; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); + if (!channelp) + { + LL_WARNS("Voice") << "Unable to retrieve channel with Id = " << mSessionID << LL_ENDL; + return; + } + + if (!status) + { + if (status == LLCore::HttpStatus(HTTP_FORBIDDEN)) + { + //403 == no ability + LLNotificationsUtil::add( + "VoiceNotAllowed", + channelp->getNotifyArgs()); + } + else + { + LLNotificationsUtil::add( + "VoiceCallGenericError", + channelp->getNotifyArgs()); + } + channelp->deactivate(); + return; + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + + LLSD::map_const_iterator iter; + for (iter = result.beginMap(); iter != result.endMap(); ++iter) + { + LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " + << iter->first << LL_ENDL; + } + + channelp->setChannelInfo( + result["voice_credentials"]["channel_uri"].asString(), + result["voice_credentials"]["channel_credentials"].asString()); + +} + + // // LLVoiceChannelProximal // diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index fed44974fd..ef15b2c79e 100755 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -29,6 +29,8 @@ #include "llhandle.h" #include "llvoiceclient.h" +#include "lleventcoro.h" +#include "llcoros.h" class LLPanel; @@ -157,6 +159,8 @@ protected: virtual void setState(EState state); private: + void voiceCallCapCoro(std::string url); + U32 mRetries; BOOL mIsRetrying; }; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a6a7a35b03..d14fac5fb8 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -64,6 +64,8 @@ #include "llviewernetwork.h" #include "llnotificationsutil.h" +#include "llcorehttputil.h" + #include "stringize.h" // for base64 decoding @@ -122,66 +124,6 @@ static int scale_speaker_volume(float volume) } -class LLVivoxVoiceAccountProvisionResponder : - public LLHTTPClient::Responder -{ - LOG_CLASS(LLVivoxVoiceAccountProvisionResponder); -public: - LLVivoxVoiceAccountProvisionResponder(int retries) - { - mRetries = retries; - } - -private: - /* virtual */ void httpFailure() - { - LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, " - << ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) - << " " << dumpResponse() << LL_ENDL; - - if ( mRetries > 0 ) - { - LLVivoxVoiceClient::getInstance()->requestVoiceAccountProvision(mRetries - 1); - } - else - { - LLVivoxVoiceClient::getInstance()->giveUp(); - } - } - - /* virtual */ void httpSuccess() - { - std::string voice_sip_uri_hostname; - std::string voice_account_server_uri; - - LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - if(content.has("voice_sip_uri_hostname")) - voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); - - // this key is actually misnamed -- it will be an entire URI, not just a hostname. - if(content.has("voice_account_server_name")) - voice_account_server_uri = content["voice_account_server_name"].asString(); - - LLVivoxVoiceClient::getInstance()->login( - content["username"].asString(), - content["password"].asString(), - voice_sip_uri_hostname, - voice_account_server_uri); - } - -private: - int mRetries; -}; - - - /////////////////////////////////////////////////////////////////////////////////////////////// class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver @@ -194,59 +136,6 @@ static LLVivoxVoiceClientMuteListObserver mutelist_listener; static bool sMuteListListener_listening = false; /////////////////////////////////////////////////////////////////////////////////////////////// - -class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLVivoxVoiceClientCapResponder); -public: - LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; - -private: - // called with bad status codes - /* virtual */ void httpFailure(); - /* virtual */ void httpSuccess(); - - LLVivoxVoiceClient::state mRequestingState; // state -}; - -void LLVivoxVoiceClientCapResponder::httpFailure() -{ - LL_WARNS("Voice") << dumpResponse() << LL_ENDL; - LLVivoxVoiceClient::getInstance()->sessionTerminate(); -} - -void LLVivoxVoiceClientCapResponder::httpSuccess() -{ - LLSD::map_const_iterator iter; - - LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL; - - std::string uri; - std::string credentials; - - const LLSD& content = getContent(); - if ( content.has("voice_credentials") ) - { - LLSD voice_credentials = content["voice_credentials"]; - if ( voice_credentials.has("channel_uri") ) - { - uri = voice_credentials["channel_uri"].asString(); - } - if ( voice_credentials.has("channel_credentials") ) - { - credentials = - voice_credentials["channel_credentials"].asString(); - } - } - - // set the spatial channel. If no voice credentials or uri are - // available, then we simply drop out of voice spatially. - if(LLVivoxVoiceClient::getInstance()->parcelVoiceInfoReceived(mRequestingState)) - { - LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials); - } -} - static LLProcessPtr sGatewayPtr; static bool isGatewayRunning() @@ -556,16 +445,51 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries) if ( !url.empty() ) { - LLHTTPClient::post( - url, - LLSD(), - new LLVivoxVoiceAccountProvisionResponder(retries)); - + LLCoros::instance().launch("LLVivoxVoiceClient::voiceAccountProvisionCoro", + boost::bind(&LLVivoxVoiceClient::voiceAccountProvisionCoro, this, url, retries)); setState(stateConnectorStart); } } } +void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + httpOpts->setRetries(retries); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL; + giveUp(); + return; + } + + std::string voice_sip_uri_hostname; + std::string voice_account_server_uri; + + //LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + + if (result.has("voice_sip_uri_hostname")) + voice_sip_uri_hostname = result["voice_sip_uri_hostname"].asString(); + + // this key is actually misnamed -- it will be an entire URI, not just a hostname. + if (result.has("voice_account_server_name")) + voice_account_server_uri = result["voice_account_server_name"].asString(); + + login(result["username"].asString(), result["password"].asString(), + voice_sip_uri_hostname, voice_account_server_uri); +} + void LLVivoxVoiceClient::login( const std::string& account_name, const std::string& password, @@ -4003,14 +3927,60 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo() LLSD data; LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; - LLHTTPClient::post( - url, - data, - new LLVivoxVoiceClientCapResponder(getState())); + LLCoros::instance().launch("LLVivoxVoiceClient::parcelVoiceInfoRequestCoro", + boost::bind(&LLVivoxVoiceClient::parcelVoiceInfoRequestCoro, this, url)); return true; } } +void LLVivoxVoiceClient::parcelVoiceInfoRequestCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("parcelVoiceInfoRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + state requestingState = getState(); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD()); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("Voice") << "No voice on parcel" << LL_ENDL; + sessionTerminate(); + return; + } + + std::string uri; + std::string credentials; + + if (result.has("voice_credentials")) + { + LLSD voice_credentials = result["voice_credentials"]; + if (voice_credentials.has("channel_uri")) + { + uri = voice_credentials["channel_uri"].asString(); + } + if (voice_credentials.has("channel_credentials")) + { + credentials = + voice_credentials["channel_credentials"].asString(); + } + } + + LL_INFOS("Voice") << "Voice URI is " << uri << LL_ENDL; + + // set the spatial channel. If no voice credentials or uri are + // available, then we simply drop out of voice spatially. + if (parcelVoiceInfoReceived(requestingState)) + { + setSpatialChannel(uri, credentials); + } + +} + void LLVivoxVoiceClient::switchChannel( std::string uri, bool spatial, diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index a4ec9f2a69..b12ed80e41 100755 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -37,6 +37,9 @@ class LLVivoxProtocolParser; #include "llframetimer.h" #include "llviewerregion.h" #include "llcallingcard.h" // for LLFriendObserver +#include "lleventcoro.h" +#include "llcoros.h" +#include <queue> #ifdef LL_USESYSTEMLIBS # include "expat.h" @@ -46,7 +49,6 @@ class LLVivoxProtocolParser; #include "llvoiceclient.h" class LLAvatarName; -class LLVivoxVoiceAccountProvisionResponder; class LLVivoxVoiceClientMuteListObserver; @@ -251,7 +253,6 @@ protected: ////////////////////// // Vivox Specific definitions - friend class LLVivoxVoiceAccountProvisionResponder; friend class LLVivoxVoiceClientMuteListObserver; friend class LLVivoxVoiceClientFriendsObserver; @@ -635,6 +636,10 @@ protected: void accountGetTemplateFontsResponse(int statusCode, const std::string &statusString); private: + + void voiceAccountProvisionCoro(std::string url, S32 retries); + void parcelVoiceInfoRequestCoro(std::string url); + LLVoiceVersionInfo mVoiceVersion; /// Clean up objects created during a voice session. diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 0432f6f27c..267061b83d 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4172,6 +4172,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons for (U32 j = 0; j < maxJoints; ++j) { LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); + if (!joint) + { + joint = avatar->getJoint("mPelvis"); + } if (joint) { mat[j] = skin->mInvBindMatrix[j]; diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index ddb7f7bfce..06ce497510 100755 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -30,14 +30,17 @@ // libs #include "llbufferstream.h" -#include "llhttpclient.h" #include "llimagepng.h" #include "llplugincookiestore.h" +#include "llsdserialize.h" + // newview #include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals +#include "llcorehttputil.h" + // third-party #include "reader.h" // JSON @@ -55,139 +58,6 @@ */ /////////////////////////////////////////////////////////////////////////////// -// LLWebProfileResponders::ConfigResponder - -class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebProfileResponders::ConfigResponder); - -public: - ConfigResponder(LLPointer<LLImageFormatted> imagep) - : mImagep(imagep) - { - } - - // *TODO: Check for 'application/json' content type, and parse json at the base class. - /*virtual*/ void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - - if (getStatus() != HTTP_OK) - { - LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL; - LLWebProfile::reportImageUploadStatus(false); - return; - } - - Json::Value root; - Json::Reader reader; - if (!reader.parse(body, root)) - { - LL_WARNS() << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << LL_ENDL; - LLWebProfile::reportImageUploadStatus(false); - return; - } - - // *TODO: 404 = not supported by the grid - // *TODO: increase timeout or handle 499 Expired - - // Convert config to LLSD. - const Json::Value data = root["data"]; - const std::string upload_url = root["url"].asString(); - LLSD config; - config["acl"] = data["acl"].asString(); - config["AWSAccessKeyId"] = data["AWSAccessKeyId"].asString(); - config["Content-Type"] = data["Content-Type"].asString(); - config["key"] = data["key"].asString(); - config["policy"] = data["policy"].asString(); - config["success_action_redirect"] = data["success_action_redirect"].asString(); - config["signature"] = data["signature"].asString(); - config["add_loc"] = data.get("add_loc", "0").asString(); - config["caption"] = data.get("caption", "").asString(); - - // Do the actual image upload using the configuration. - LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL; - LLWebProfile::post(mImagep, config, upload_url); - } - -private: - LLPointer<LLImageFormatted> mImagep; -}; - -/////////////////////////////////////////////////////////////////////////////// -// LLWebProfilePostImageRedirectResponder -class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebProfileResponders::PostImageRedirectResponder); - -public: - /*virtual*/ void completedRaw( - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - if (getStatus() != HTTP_OK) - { - LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL; - LLWebProfile::reportImageUploadStatus(false); - return; - } - - LLBufferStream istr(channels, buffer.get()); - std::stringstream strstrm; - strstrm << istr.rdbuf(); - const std::string body = strstrm.str(); - LL_INFOS() << "Image uploaded." << LL_ENDL; - LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL; - LLWebProfile::reportImageUploadStatus(true); - } -}; - - -/////////////////////////////////////////////////////////////////////////////// -// LLWebProfileResponders::PostImageResponder -class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLWebProfileResponders::PostImageResponder); - -public: - /*virtual*/ void completedRaw(const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // Viewer seems to fail to follow a 303 redirect on POST request - // (URLRequest Error: 65, Send failed since rewinding of the data stream failed). - // Handle it manually. - if (getStatus() == HTTP_SEE_OTHER) - { - LLSD headers = LLViewerMedia::getHeaders(); - headers[HTTP_OUT_HEADER_COOKIE] = LLWebProfile::getAuthCookie(); - const std::string& redir_url = getResponseHeader(HTTP_IN_HEADER_LOCATION); - if (redir_url.empty()) - { - LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL; - LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - LLWebProfile::reportImageUploadStatus(false); - } - else - { - LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; - LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); - } - } - else - { - LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL; - LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; - LLWebProfile::reportImageUploadStatus(false); - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// // LLWebProfile std::string LLWebProfile::sAuthCookie; @@ -196,15 +66,9 @@ LLWebProfile::status_callback_t LLWebProfile::mStatusCallback; // static void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::string& caption, bool add_location) { - // Get upload configuration data. - std::string config_url(getProfileURL(LLStringUtil::null) + "snapshots/s3_upload_config"); - config_url += "?caption=" + LLURI::escape(caption); - config_url += "&add_loc=" + std::string(add_location ? "1" : "0"); - - LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL; - LLSD headers = LLViewerMedia::getHeaders(); - headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); - LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers); + LLCoros::instance().launch("LLWebProfile::uploadImageCoro", + boost::bind(&LLWebProfile::uploadImageCoro, image, caption, add_location)); + } // static @@ -214,74 +78,178 @@ void LLWebProfile::setAuthCookie(const std::string& cookie) sAuthCookie = cookie; } -// static -void LLWebProfile::post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url) + +/*static*/ +LLCore::HttpHeaders::ptr_t LLWebProfile::buildDefaultHeaders() { - if (dynamic_cast<LLImagePNG*>(image.get()) == 0) - { - LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL; - llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0); - return; - } + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + LLSD headers = LLViewerMedia::getHeaders(); - const std::string boundary = "----------------------------0123abcdefab"; + for (LLSD::map_iterator it = headers.beginMap(); it != headers.endMap(); ++it) + { + httpHeaders->append((*it).first, (*it).second.asStringRef()); + } - LLSD headers = LLViewerMedia::getHeaders(); - headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie(); - headers[HTTP_OUT_HEADER_CONTENT_TYPE] = "multipart/form-data; boundary=" + boundary; + return httpHeaders; +} - std::ostringstream body; - // *NOTE: The order seems to matter. - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"key\"\r\n\r\n" - << config["key"].asString() << "\r\n"; +/*static*/ +void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool addLocation) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + LLCore::HttpHeaders::ptr_t httpHeaders; - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n" - << config["AWSAccessKeyId"].asString() << "\r\n"; + if (dynamic_cast<LLImagePNG*>(image.get()) == 0) + { + LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL; + llassert(dynamic_cast<LLImagePNG*>(image.get()) != 0); + return; + } - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"acl\"\r\n\r\n" - << config["acl"].asString() << "\r\n"; + httpOpts->setWantHeaders(true); + httpOpts->setFollowRedirects(false); - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n" - << config["Content-Type"].asString() << "\r\n"; + // Get upload configuration data. + std::string configUrl(getProfileURL(std::string()) + "snapshots/s3_upload_config"); + configUrl += "?caption=" + LLURI::escape(caption); + configUrl += "&add_loc=" + std::string(addLocation ? "1" : "0"); - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"policy\"\r\n\r\n" - << config["policy"].asString() << "\r\n"; + LL_DEBUGS("Snapshots") << "Requesting " << configUrl << LL_ENDL; - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"signature\"\r\n\r\n" - << config["signature"].asString() << "\r\n"; + httpHeaders = buildDefaultHeaders(); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n" - << config["success_action_redirect"].asString() << "\r\n"; + LLSD result = httpAdapter->getJsonAndSuspend(httpRequest, configUrl, httpOpts, httpHeaders); - body << "--" << boundary << "\r\n" - << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" - << "Content-Type: image/png\r\n\r\n"; + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } + if (!status) + { + LL_WARNS("Snapshots") << "Failed to get image upload config" << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + return; + } + + // Ready to build our image post body. + + const LLSD &data = result["data"]; + const std::string &uploadUrl = result["url"].asStringRef(); + const std::string boundary = "----------------------------0123abcdefab"; + + // a new set of headers. + httpHeaders = LLWebProfile::buildDefaultHeaders(); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); + httpHeaders->remove(HTTP_OUT_HEADER_CONTENT_TYPE); + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "multipart/form-data; boundary=" + boundary); + + LLCore::BufferArray::ptr_t body = LLWebProfile::buildPostData(data, image, boundary); + + result = httpAdapter->postAndSuspend(httpRequest, uploadUrl, body, httpOpts, httpHeaders); + + body.reset(); + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - body << "\r\n--" << boundary << "--\r\n"; + if (!status && (status != LLCore::HttpStatus(HTTP_SEE_OTHER))) + { + LL_WARNS("Snapshots") << "Failed to upload image data." << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + return; + } - // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); - U8 *data = new U8[size]; - memcpy(data, body.str().data(), size); + LLSD resultHeaders = httpResults[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; - // Send request, successful upload will trigger posting metadata. - LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers); + httpHeaders = LLWebProfile::buildDefaultHeaders(); + httpHeaders->append(HTTP_OUT_HEADER_COOKIE, getAuthCookie()); + + const std::string& redirUrl = resultHeaders[HTTP_IN_HEADER_LOCATION].asStringRef(); + + if (redirUrl.empty()) + { + LL_WARNS("Snapshots") << "Received empty redirection URL in post image." << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + } + + LL_DEBUGS("Snapshots") << "Got redirection URL: " << redirUrl << LL_ENDL; + + result = httpAdapter->getRawAndSuspend(httpRequest, redirUrl, httpOpts, httpHeaders); + + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status != LLCore::HttpStatus(HTTP_OK)) + { + LL_WARNS("Snapshots") << "Failed to upload image." << LL_ENDL; + LLWebProfile::reportImageUploadStatus(false); + return; + } + + //LLSD raw = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW]; + + LL_INFOS("Snapshots") << "Image uploaded." << LL_ENDL; + //LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << raw.asString() << "]" << LL_ENDL; + LLWebProfile::reportImageUploadStatus(true); + + +} + +/*static*/ +LLCore::BufferArray::ptr_t LLWebProfile::buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary) +{ + LLCore::BufferArray::ptr_t body(new LLCore::BufferArray); + LLCore::BufferArrayStream bas(body.get()); + + // *NOTE: The order seems to matter. + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"key\"\r\n\r\n" + << data["key"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\n" + << data["AWSAccessKeyId"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"acl\"\r\n\r\n" + << data["acl"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"Content-Type\"\r\n\r\n" + << data["Content-Type"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"policy\"\r\n\r\n" + << data["policy"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"signature\"\r\n\r\n" + << data["signature"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"success_action_redirect\"\r\n\r\n" + << data["success_action_redirect"].asString() << "\r\n"; + + bas << "--" << boundary << "\r\n" + << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" + << "Content-Type: image/png\r\n\r\n"; + + // Insert the image data. + //char *datap = (char *)(image->getData()); + //bas.write(datap, image->getDataSize()); + U8* image_data = image->getData(); + for (S32 i = 0; i < image->getDataSize(); ++i) + { + bas << image_data[i]; + } + + bas << "\r\n--" << boundary << "--\r\n"; + + return body; } // static diff --git a/indra/newview/llwebprofile.h b/indra/newview/llwebprofile.h index 10279bffac..6227e00afe 100755 --- a/indra/newview/llwebprofile.h +++ b/indra/newview/llwebprofile.h @@ -28,6 +28,10 @@ #define LL_LLWEBPROFILE_H #include "llimage.h" +#include "lleventcoro.h" +#include "llcoros.h" +#include "httpheaders.h" +#include "bufferarray.h" namespace LLWebProfileResponders { @@ -54,11 +58,11 @@ public: static void setImageUploadResultCallback(status_callback_t cb) { mStatusCallback = cb; } private: - friend class LLWebProfileResponders::ConfigResponder; - friend class LLWebProfileResponders::PostImageResponder; - friend class LLWebProfileResponders::PostImageRedirectResponder; + static LLCore::HttpHeaders::ptr_t buildDefaultHeaders(); + + static void uploadImageCoro(LLPointer<LLImageFormatted> image, std::string caption, bool add_location); + static LLCore::BufferArray::ptr_t buildPostData(const LLSD &data, LLPointer<LLImageFormatted> &image, const std::string &boundary); - static void post(LLPointer<LLImageFormatted> image, const LLSD& config, const std::string& url); static void reportImageUploadStatus(bool ok); static std::string getAuthCookie(); diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 3bedfbe502..87e8c3008e 100755 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -32,6 +32,7 @@ #include "llviewerregion.h" #include "llenvmanager.h" #include "llnotificationsutil.h" +#include "llcorehttputil.h" /**** * LLEnvironmentRequest @@ -81,55 +82,62 @@ bool LLEnvironmentRequest::doRequest() return false; } - LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; - LLHTTPClient::get(url, new LLEnvironmentRequestResponder()); - return true; -} - -/**** - * LLEnvironmentRequestResponder - ****/ -int LLEnvironmentRequestResponder::sCount = 0; // init to 0 + std::string coroname = + LLCoros::instance().launch("LLEnvironmentRequest::environmentRequestCoro", + boost::bind(&LLEnvironmentRequest::environmentRequestCoro, url)); -LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() -{ - mID = ++sCount; + LL_INFOS("WindlightCaps") << "Requesting region windlight settings via " << url << LL_ENDL; + return true; } -/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess() -{ - const LLSD& unvalidated_content = getContent(); - LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; - if (mID != sCount) - { - LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL; - return; - } - - LLUUID regionId; - if( gAgent.getRegion() ) - { - regionId = gAgent.getRegion()->getRegionID(); - } - - if (unvalidated_content[0]["regionID"].asUUID() != regionId ) - { - LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting " - << regionId << " but got " << unvalidated_content[0]["regionID"].asUUID() - << ") - ignoring..." << LL_ENDL; - return; - } +S32 LLEnvironmentRequest::sLastRequest = 0; - LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content); -} -/*virtual*/ -void LLEnvironmentRequestResponder::httpFailure() +//static +void LLEnvironmentRequest::environmentRequestCoro(std::string url) { - LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " - << dumpResponse() << LL_ENDL; - LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + S32 requestId = ++LLEnvironmentRequest::sLastRequest; + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentRequest", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + if (requestId != LLEnvironmentRequest::sLastRequest) + { + LL_INFOS("WindlightCaps") << "Got superseded by another responder; ignoring..." << LL_ENDL; + return; + } + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("WindlightCaps") << "Got an error, not using region windlight... " << LL_ENDL; + LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); + return; + } + result = result["content"]; + LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; + + LLUUID regionId; + if (gAgent.getRegion()) + { + regionId = gAgent.getRegion()->getRegionID(); + } + + if ((result[0]["regionID"].asUUID() != regionId) && regionId.notNull()) + { + LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting " + << regionId << " but got " << result[0]["regionID"].asUUID() + << ") - ignoring..." << LL_ENDL; + return; + } + + LLEnvManagerNew::getInstance()->onRegionSettingsResponse(result); } + /**** * LLEnvironmentApply ****/ @@ -161,53 +169,86 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) return false; } - LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; - LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; - LLHTTPClient::post(url, content, new LLEnvironmentApplyResponder()); + LL_INFOS("WindlightCaps") << "Sending windlight settings to " << url << LL_ENDL; + LL_DEBUGS("WindlightCaps") << "content: " << content << LL_ENDL; + + std::string coroname = + LLCoros::instance().launch("LLEnvironmentApply::environmentApplyCoro", + boost::bind(&LLEnvironmentApply::environmentApplyCoro, url, content)); return true; } -/**** - * LLEnvironmentApplyResponder - ****/ -/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess() -{ - const LLSD& content = getContent(); - if (!content.isMap() || !content.has("regionID")) - { - failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); - return; - } - if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) - { - LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " - << gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID() - << "); ignoring..." << LL_ENDL; - return; - } - else if (content["success"].asBoolean()) - { - LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL; - LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); - } - else - { - LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << dumpResponse() << LL_ENDL; - LLSD args(LLSD::emptyMap()); - args["FAIL_REASON"] = content["fail_reason"].asString(); - LLNotificationsUtil::add("WLRegionApplyFail", args); - LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); - } -} -/*virtual*/ -void LLEnvironmentApplyResponder::httpFailure() +void LLEnvironmentApply::environmentApplyCoro(std::string url, LLSD content) { - LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " - << dumpResponse() << LL_ENDL; - - LLSD args(LLSD::emptyMap()); - std::stringstream msg; - msg << getReason() << " (Code " << getStatus() << ")"; - args["FAIL_REASON"] = msg.str(); - LLNotificationsUtil::add("WLRegionApplyFail", args); + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("EnvironmentApply", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, content); + + LLSD notify; // for error reporting. If there is something to report to user this will be defined. + /* + * Expecting reply from sim in form of: + * { + * regionID : uuid, + * messageID: uuid, + * success : true + * } + * or + * { + * regionID : uuid, + * success : false, + * fail_reason : string + * } + */ + + do // while false. + { // Breaks from loop in the case of an error. + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! " << LL_ENDL; + + std::stringstream msg; + msg << status.toString() << " (Code " << status.toTerseString() << ")"; + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = msg.str(); + break; + } + + if (!result.has("regionID")) + { + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = "Missing regionID, malformed response"; + break; + } + else if (result["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) + { + // note that there is no report to the user in this failure case. + LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " + << gAgent.getRegion()->getRegionID() << ", reply is from " << result["regionID"].asUUID() + << "); ignoring..." << LL_ENDL; + break; + } + else if (!result["success"].asBoolean()) + { + LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! " << LL_ENDL; + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = result["fail_reason"].asString(); + break; + } + + LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << result["regionID"].asUUID() << LL_ENDL; + LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); + + } while (false); + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } } diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 089c799da7..eb2bbf9553 100755 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -28,7 +28,7 @@ #define LL_LLWLHANDLERS_H #include "llviewerprecompiledheaders.h" -#include "llhttpclient.h" +#include "llcoros.h" class LLEnvironmentRequest { @@ -40,21 +40,10 @@ public: private: static void onRegionCapsReceived(const LLUUID& region_id); static bool doRequest(); -}; - -class LLEnvironmentRequestResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(LLEnvironmentRequestResponder); -private: - /* virtual */ void httpSuccess(); - /* virtual */ void httpFailure(); -private: - friend class LLEnvironmentRequest; + static void environmentRequestCoro(std::string url); - LLEnvironmentRequestResponder(); - static int sCount; - int mID; + static S32 sLastRequest; }; class LLEnvironmentApply @@ -67,35 +56,8 @@ public: private: static clock_t sLastUpdate; static clock_t UPDATE_WAIT_SECONDS; -}; -class LLEnvironmentApplyResponder: public LLHTTPClient::Responder -{ - LOG_CLASS(LLEnvironmentApplyResponder); -private: - /* - * Expecting reply from sim in form of: - * { - * regionID : uuid, - * messageID: uuid, - * success : true - * } - * or - * { - * regionID : uuid, - * success : false, - * fail_reason : string - * } - */ - /* virtual */ void httpSuccess(); - - // non-2xx errors only - /* virtual */ void httpFailure(); - -private: - friend class LLEnvironmentApply; - - LLEnvironmentApplyResponder() {} + static void environmentApplyCoro(std::string url, LLSD content); }; #endif // LL_LLWLHANDLERS_H diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index c12c2cc24c..442ed73c2d 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -34,7 +34,12 @@ #include "llxmlrpctransaction.h" #include "llxmlrpclistener.h" -#include "llcurl.h" +#include "httpcommon.h" +#include "llhttpconstants.h" +#include "httprequest.h" +#include "httpoptions.h" +#include "httpheaders.h" +#include "bufferarray.h" #include "llviewercontrol.h" // Have to include these last to avoid queue redefinition! @@ -43,6 +48,13 @@ #include "llappviewer.h" #include "lltrans.h" +#include "boost/move/unique_ptr.hpp" + +namespace boost +{ + using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace. +} + // Static instance of LLXMLRPCListener declared here so that every time we // bring in this code, we instantiate a listener. If we put the static // instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would @@ -155,55 +167,158 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const } +class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler +{ +public: + Handler(LLCore::HttpRequest::ptr_t &request, LLXMLRPCTransaction::Impl *impl); + virtual ~Handler(); + + virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + + typedef boost::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t; + +private: + + LLXMLRPCTransaction::Impl *mImpl; + LLCore::HttpRequest::ptr_t mRequest; +}; + class LLXMLRPCTransaction::Impl { public: typedef LLXMLRPCTransaction::EStatus EStatus; - LLCurlEasyRequest* mCurlRequest; + LLCore::HttpRequest::ptr_t mHttpRequest; + + + EStatus mStatus; + CURLcode mCurlCode; + std::string mStatusMessage; + std::string mStatusURI; + LLCore::HttpResponse::TransferStats::ptr_t mTransferStats; + Handler::ptr_t mHandler; + LLCore::HttpHandle mPostH; - EStatus mStatus; - CURLcode mCurlCode; - std::string mStatusMessage; - std::string mStatusURI; - LLCurl::TransferInfo mTransferInfo; - std::string mURI; - char* mRequestText; - int mRequestTextSize; - + std::string mProxyAddress; std::string mResponseText; XMLRPC_REQUEST mResponse; std::string mCertStore; LLPointer<LLCertificate> mErrorCert; - + Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip); Impl(const std::string& uri, - const std::string& method, LLXMLRPCValue params, bool useGzip); + const std::string& method, LLXMLRPCValue params, bool useGzip); ~Impl(); - + bool process(); - - void setStatus(EStatus code, - const std::string& message = "", const std::string& uri = ""); - void setCurlStatus(CURLcode); + + void setStatus(EStatus code, const std::string& message = "", const std::string& uri = ""); + void setHttpStatus(const LLCore::HttpStatus &status); private: void init(XMLRPC_REQUEST request, bool useGzip); - static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param); - static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param); - static size_t curlDownloadCallback( - char* data, size_t size, size_t nmemb, void* user_data); }; +LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request, + LLXMLRPCTransaction::Impl *impl) : + mImpl(impl), + mRequest(request) +{ +} + +LLXMLRPCTransaction::Handler::~Handler() +{ +} + +void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle, + LLCore::HttpResponse * response) +{ + LLCore::HttpStatus status = response->getStatus(); + + if (!status) + { + if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) && + (status.toULong() != CURLE_SSL_CACERT)) + { + // if we have a curl error that's not already been handled + // (a non cert error), then generate the error message as + // appropriate + mImpl->setHttpStatus(status); + LLCertificate *errordata = static_cast<LLCertificate *>(status.getErrorData()); + + if (errordata) + { + mImpl->mErrorCert = LLPointer<LLCertificate>(errordata); + status.setErrorData(NULL); + errordata->unref(); + } + + LL_WARNS() << "LLXMLRPCTransaction error " + << status.toHex() << ": " << status.toString() << LL_ENDL; + LL_WARNS() << "LLXMLRPCTransaction request URI: " + << mImpl->mURI << LL_ENDL; + } + + return; + } + + mImpl->setStatus(LLXMLRPCTransaction::StatusComplete); + mImpl->mTransferStats = response->getTransferStats(); + + // the contents of a buffer array are potentially noncontiguous, so we + // will need to copy them into an contiguous block of memory for XMLRPC. + LLCore::BufferArray *body = response->getBody(); + char * bodydata = new char[body->size()]; + + body->read(0, bodydata, body->size()); + + mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, body->size(), 0); + + delete[] bodydata; + + bool hasError = false; + bool hasFault = false; + int faultCode = 0; + std::string faultString; + + LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse)); + if (error.isValid()) + { + hasError = true; + faultCode = error["faultCode"].asInt(); + faultString = error["faultString"].asString(); + } + else if (XMLRPC_ResponseIsFault(mImpl->mResponse)) + { + hasFault = true; + faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse); + faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse); + } + + if (hasError || hasFault) + { + mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError); + + LL_WARNS() << "LLXMLRPCTransaction XMLRPC " + << (hasError ? "error " : "fault ") + << faultCode << ": " + << faultString << LL_ENDL; + LL_WARNS() << "LLXMLRPCTransaction request URI: " + << mImpl->mURI << LL_ENDL; + } + +} + +//========================================================================= + LLXMLRPCTransaction::Impl::Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip) - : mCurlRequest(0), + : mHttpRequest(), mStatus(LLXMLRPCTransaction::StatusNotStarted), mURI(uri), - mRequestText(0), mResponse(0) { init(request, useGzip); @@ -212,10 +327,9 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri, LLXMLRPCTransaction::Impl::Impl(const std::string& uri, const std::string& method, LLXMLRPCValue params, bool useGzip) - : mCurlRequest(0), + : mHttpRequest(), mStatus(LLXMLRPCTransaction::StatusNotStarted), mURI(uri), - mRequestText(0), mResponse(0) { XMLRPC_REQUEST request = XMLRPC_RequestNew(); @@ -231,127 +345,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri, XMLRPC_RequestFree(request, 1); } -// _sslCertVerifyCallback -// callback called when a cert verification is requested. -// calls SECAPI to validate the context -int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param) +void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) { - LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param; - LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore); - LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx); - LLSD validation_params = LLSD::emptyMap(); - LLURI uri(transaction->mURI); - validation_params[CERT_HOSTNAME] = uri.hostName(); - try - { - // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects - store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); - } - catch (LLCertValidationTrustException& cert_exception) - { - // this exception is is handled differently than the general cert - // exceptions, as we allow the user to actually add the certificate - // for trust. - // therefore we pass back a different error code - // NOTE: We're currently 'wired' to pass around CURL error codes. This is - // somewhat clumsy, as we may run into errors that do not map directly to curl - // error codes. Should be refactored with login refactoring, perhaps. - transaction->mCurlCode = CURLE_SSL_CACERT; - // set the status directly. set curl status generates error messages and we want - // to use the fixed ones from the exceptions - transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); - // We should probably have a more generic way of passing information - // back to the error handlers. - transaction->mErrorCert = cert_exception.getCert(); - return 0; - } - catch (LLCertException& cert_exception) - { - transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE; - // set the status directly. set curl status generates error messages and we want - // to use the fixed ones from the exceptions - transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string()); - transaction->mErrorCert = cert_exception.getCert(); - return 0; - } - catch (...) - { - // any other odd error, we just handle as a connect error. - transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR; - transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR); - return 0; - } - return 1; -} + LLCore::HttpOptions::ptr_t httpOpts; + LLCore::HttpHeaders::ptr_t httpHeaders; -// _sslCtxFunction -// Callback function called when an SSL Context is created via CURL -// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion -// based on SECAPI - -CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param) -{ - SSL_CTX * ctx = (SSL_CTX *) sslctx; - // disable any default verification for server certs - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); - // set the verification callback. - SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param); - // the calls are void - return CURLE_OK; - -} -void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) -{ - if (!mCurlRequest) + if (!mHttpRequest) { - mCurlRequest = new LLCurlEasyRequest(); + mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest); } - if(!mCurlRequest->isValid()) - { - LL_WARNS() << "mCurlRequest is invalid." << LL_ENDL ; - delete mCurlRequest ; - mCurlRequest = NULL ; - return ; - } + // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer + httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); - mErrorCert = NULL; + httpOpts->setTimeout(40L); -// mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging - mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); - mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this); - BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); + bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCertStore = gSavedSettings.getString("CertStore"); - mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert); - mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0); - // Be a little impatient about establishing connections. - mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L); - mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this); - /* Setting the DNS cache timeout to -1 disables it completely. - This might help with bug #503 */ - mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1); + httpOpts->setSSLVerifyPeer( vefifySSLCert ); + httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0); - mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); + // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer + httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); - if (useGzip) - { - mCurlRequest->setoptString(CURLOPT_ENCODING, ""); - } + httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); + + ///* Setting the DNS cache timeout to -1 disables it completely. + //This might help with bug #503 */ + //httpOpts->setDNSCacheTimeout(-1); + + LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray()); + + // TODO: See if there is a way to serialize to a preallocated buffer I'm + // not fond of the copy here. + int requestSize(0); + char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize); + + body->append(requestText, requestSize); - mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); - if (mRequestText) - { - mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText); - mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize); - } - else - { - setStatus(StatusOtherError); - } + XMLRPC_Free(requestText); + + mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this )); + + mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0, + mURI, body.get(), httpOpts, httpHeaders, mHandler.get()); - mCurlRequest->sendRequest(mURI); } @@ -361,28 +401,17 @@ LLXMLRPCTransaction::Impl::~Impl() { XMLRPC_RequestFree(mResponse, 1); } - - if (mRequestText) - { - XMLRPC_Free(mRequestText); - } - - delete mCurlRequest; - mCurlRequest = NULL ; } bool LLXMLRPCTransaction::Impl::process() { - if(!mCurlRequest || !mCurlRequest->isValid()) + if (!mPostH || !mHttpRequest) { - LL_WARNS() << "transaction failed." << LL_ENDL ; - - delete mCurlRequest ; - mCurlRequest = NULL ; - return true ; //failed, quit. + LL_WARNS() << "transaction failed." << LL_ENDL; + return true; //failed, quit. } - switch(mStatus) + switch (mStatus) { case LLXMLRPCTransaction::StatusComplete: case LLXMLRPCTransaction::StatusCURLError: @@ -391,93 +420,25 @@ bool LLXMLRPCTransaction::Impl::process() { return true; } - + case LLXMLRPCTransaction::StatusNotStarted: { setStatus(LLXMLRPCTransaction::StatusStarted); break; } - + default: - { - // continue onward - } - } - - if(!mCurlRequest->wait()) - { - return false ; + break; } - while(1) - { - CURLcode result; - bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo); - if (newmsg) - { - if (result != CURLE_OK) - { - if ((result != CURLE_SSL_PEER_CERTIFICATE) && - (result != CURLE_SSL_CACERT)) - { - // if we have a curl error that's not already been handled - // (a non cert error), then generate the error message as - // appropriate - setCurlStatus(result); - - LL_WARNS() << "LLXMLRPCTransaction CURL error " - << mCurlCode << ": " << mCurlRequest->getErrorString() << LL_ENDL; - LL_WARNS() << "LLXMLRPCTransaction request URI: " - << mURI << LL_ENDL; - } - - return true; - } - - setStatus(LLXMLRPCTransaction::StatusComplete); + LLCore::HttpStatus status = mHttpRequest->update(0); - mResponse = XMLRPC_REQUEST_FromXML( - mResponseText.data(), mResponseText.size(), NULL); - - bool hasError = false; - bool hasFault = false; - int faultCode = 0; - std::string faultString; - - LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse)); - if (error.isValid()) - { - hasError = true; - faultCode = error["faultCode"].asInt(); - faultString = error["faultString"].asString(); - } - else if (XMLRPC_ResponseIsFault(mResponse)) - { - hasFault = true; - faultCode = XMLRPC_GetResponseFaultCode(mResponse); - faultString = XMLRPC_GetResponseFaultString(mResponse); - } - - if (hasError || hasFault) - { - setStatus(LLXMLRPCTransaction::StatusXMLRPCError); - - LL_WARNS() << "LLXMLRPCTransaction XMLRPC " - << (hasError ? "error " : "fault ") - << faultCode << ": " - << faultString << LL_ENDL; - LL_WARNS() << "LLXMLRPCTransaction request URI: " - << mURI << LL_ENDL; - } - - return true; - } - else - { - break; // done - } + status = mHttpRequest->getStatus(); + if (!status) + { + return false; } - + return false; } @@ -516,64 +477,51 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status, } } -void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) +void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status) { + CURLcode code = static_cast<CURLcode>(status.toULong()); std::string message; std::string uri = "http://secondlife.com/community/support.php"; - + LLURI failuri(mURI); + + switch (code) { - case CURLE_COULDNT_RESOLVE_HOST: - message = - "DNS could not resolve the host name.\n" - "Please verify that you can connect to the www.secondlife.com\n" - "web site. If you can, but continue to receive this error,\n" - "please go to the support section and report this problem."; - break; - - case CURLE_SSL_PEER_CERTIFICATE: - message = - "The login server couldn't verify itself via SSL.\n" - "If you continue to receive this error, please go\n" - "to the Support section of the SecondLife.com web site\n" - "and report the problem."; - break; - - case CURLE_SSL_CACERT: - case CURLE_SSL_CONNECT_ERROR: - message = - "Often this means that your computer\'s clock is set incorrectly.\n" - "Please go to Control Panels and make sure the time and date\n" - "are set correctly.\n" - "Also check that your network and firewall are set up correctly.\n" - "If you continue to receive this error, please go\n" - "to the Support section of the SecondLife.com web site\n" - "and report the problem."; - break; - - default: - break; + case CURLE_COULDNT_RESOLVE_HOST: + message = + std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n" + "Please verify that you can connect to the www.secondlife.com\n" + "web site. If you can, but continue to receive this error,\n" + "please go to the support section and report this problem."; + break; + + case CURLE_SSL_PEER_CERTIFICATE: + message = + "The login server couldn't verify itself via SSL.\n" + "If you continue to receive this error, please go\n" + "to the Support section of the SecondLife.com web site\n" + "and report the problem."; + break; + + case CURLE_SSL_CACERT: + case CURLE_SSL_CONNECT_ERROR: + message = + "Often this means that your computer\'s clock is set incorrectly.\n" + "Please go to Control Panels and make sure the time and date\n" + "are set correctly.\n" + "Also check that your network and firewall are set up correctly.\n" + "If you continue to receive this error, please go\n" + "to the Support section of the SecondLife.com web site\n" + "and report the problem."; + break; + + default: + break; } - + mCurlCode = code; setStatus(StatusCURLError, message, uri); -} - -size_t LLXMLRPCTransaction::Impl::curlDownloadCallback( - char* data, size_t size, size_t nmemb, void* user_data) -{ - Impl& impl(*(Impl*)user_data); - - size_t n = size * nmemb; - impl.mResponseText.append(data, n); - - if (impl.mStatus == LLXMLRPCTransaction::StatusStarted) - { - impl.setStatus(LLXMLRPCTransaction::StatusDownloading); - } - - return n; } @@ -645,11 +593,11 @@ F64 LLXMLRPCTransaction::transferRate() return 0.0L; } - double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0; + double rate_bits_per_sec = impl.mTransferStats->mSpeedDownload * 8.0; LL_INFOS("AppInit") << "Buffer size: " << impl.mResponseText.size() << " B" << LL_ENDL; - LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL; - LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL; + LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferStats->mSizeDownload << " B" << LL_ENDL; + LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferStats->mTotalTime << " s" << LL_ENDL; LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL; return rate_bits_per_sec; diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h index f2589c7f41..3a1c9c82b7 100755 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpctransaction.h @@ -81,7 +81,7 @@ private: class LLXMLRPCTransaction - // an asynchronous request and respones via XML-RPC + // an asynchronous request and responses via XML-RPC { public: LLXMLRPCTransaction(const std::string& uri, @@ -127,7 +127,9 @@ public: // only valid if StsatusComplete, otherwise 0.0 private: + class Handler; class Impl; + Impl& impl; }; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 03712c1065..57e2faca5b 100755 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -105,7 +105,6 @@ #include "llspatialpartition.h" #include "llmutelist.h" #include "lltoolpie.h" -#include "llcurl.h" #include "llnotifications.h" #include "llpathinglib.h" #include "llfloaterpathfindingconsole.h" diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index a4acd1df78..7183b2f1f9 100755 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -31,6 +31,7 @@ <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string> <string name="mesh_status_missing_lod">Missing required level of detail.</string> <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string> + <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string> <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" --> <string name="decomposing">Analyzing...</string> <string name="simplifying">Simplifying...</string> @@ -66,7 +67,7 @@ follows="top|left" layout="topleft" height="19" - max_length_bytes="64" + max_length_bytes="63" name="description_form" prevalidate_callback="ascii" top_pad="5" @@ -1027,19 +1028,19 @@ bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3" follows="left|top" - height="16" + height="19" layout="topleft" left="18" name="physics info" - top_pad="15" - width="589"> + top_pad="12" + width="319"> <text follows="top|left" height="15" layout="topleft" left="0" text_color="White" - top_pad="0" + top_pad="3" name="results_text" width="50"> Results: @@ -1077,6 +1078,33 @@ Hulls: [HULLS] </text> </panel> + <panel + bg_alpha_color="0 0 0 0" + bg_opaque_color="0 0 0 0.3" + follows="left|top" + height="19" + layout="topleft" + left_pad="5" + top_delta="0" + name="physics message" + width="270"> + <icon + follows="left|top" + height="16" + left="0" + layout="topleft" + name="physics_status_message_icon" + top_pad="0" + width="16" /> + <text + follows="left|top" + height="15" + layout="topleft" + left_pad="2" + name="physics_status_message_text" + width="252" + top_delta="3"/> + </panel> </panel> <!-- MODIFIERS PANEL --> <panel diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 91adec0789..3deb8f7233 100755 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -785,14 +785,6 @@ layout="topleft" name="Marketplace Separator" /> <menu_item_call - label="Copy to Merchant Outbox" - layout="topleft" - name="Merchant Copy"> - <menu_item_call.on_click - function="Inventory.DoToSelected" - parameter="copy_to_outbox" /> - </menu_item_call> - <menu_item_call label="Copy to Marketplace Listings" layout="topleft" name="Marketplace Copy"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 2463c5f43b..52fcfba79d 100755 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -173,13 +173,6 @@ <menu_item_call.on_click function="BuyCurrency" /> </menu_item_call> - <menu_item_call - label="Merchant Outbox..." - name="MerchantOutbox"> - <menu_item_call.on_click - function="Floater.ToggleOrBringToFront" - parameter="outbox" /> - </menu_item_call> <menu_item_call label="Marketplace listings..." name="MarketplaceListings"> diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp deleted file mode 100755 index bde991a01e..0000000000 --- a/indra/newview/tests/llcapabilitylistener_test.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/** - * @file llcapabilitylistener_test.cpp - * @author Nat Goodspeed - * @date 2008-12-31 - * @brief Test for llcapabilitylistener.cpp. - * - * $LicenseInfo:firstyear=2008&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" -// Own header -#include "../llcapabilitylistener.h" -// STL headers -#include <stdexcept> -#include <map> -#include <vector> -// std headers -// external library headers -#include "boost/bind.hpp" -// other Linden headers -#include "../test/lltut.h" -#include "../llcapabilityprovider.h" -#include "lluuid.h" -#include "tests/networkio.h" -#include "tests/commtest.h" -#include "tests/wrapllerrs.h" -#include "message.h" -#include "stringize.h" - -#if defined(LL_WINDOWS) -#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr -#endif - -/***************************************************************************** -* TestCapabilityProvider -*****************************************************************************/ -struct TestCapabilityProvider: public LLCapabilityProvider -{ - TestCapabilityProvider(const LLHost& host): - mHost(host) - {} - - std::string getCapability(const std::string& cap) const - { - CapMap::const_iterator found = mCaps.find(cap); - if (found != mCaps.end()) - return found->second; - // normal LLViewerRegion lookup failure mode - return ""; - } - void setCapability(const std::string& cap, const std::string& url) - { - mCaps[cap] = url; - } - const LLHost& getHost() const { return mHost; } - std::string getDescription() const { return "TestCapabilityProvider"; } - - LLHost mHost; - typedef std::map<std::string, std::string> CapMap; - CapMap mCaps; -}; - -/***************************************************************************** -* Dummy LLMessageSystem methods -*****************************************************************************/ -/*==========================================================================*| -// This doesn't work because we're already linking in llmessage.a, and we get -// duplicate-symbol errors from the linker. Perhaps if I wanted to go through -// the exercise of providing dummy versions of every single symbol defined in -// message.o -- maybe some day. -typedef std::vector< std::pair<std::string, std::string> > StringPairVector; -StringPairVector call_history; - -S32 LLMessageSystem::sendReliable(const LLHost& host) -{ - call_history.push_back(StringPairVector::value_type("sendReliable", stringize(host))); - return 0; -} -|*==========================================================================*/ - -/***************************************************************************** -* TUT -*****************************************************************************/ -namespace tut -{ - struct llcapears_data: public commtest_data - { - TestCapabilityProvider provider; - LLCapabilityListener regionListener; - LLEventPump& regionPump; - - llcapears_data(): - provider(host), - regionListener("testCapabilityListener", NULL, provider, LLUUID(), LLUUID()), - regionPump(regionListener.getCapAPI()) - { - LLCurl::initClass(); - provider.setCapability("good", server + "capability-test"); - provider.setCapability("fail", server + "fail"); - } - }; - typedef test_group<llcapears_data> llcapears_group; - typedef llcapears_group::object llcapears_object; - llcapears_group llsdmgr("llcapabilitylistener"); - - template<> template<> - void llcapears_object::test<1>() - { - LLSD request, body; - body["data"] = "yes"; - request["payload"] = body; - request["reply"] = replyPump.getName(); - request["error"] = errorPump.getName(); - std::string threw; - try - { - WrapLLErrs capture; - regionPump.post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } - ensure_contains("missing capability name", threw, "without 'message' key"); - } - - template<> template<> - void llcapears_object::test<2>() - { - LLSD request, body; - body["data"] = "yes"; - request["message"] = "good"; - request["payload"] = body; - request["reply"] = replyPump.getName(); - request["error"] = errorPump.getName(); - regionPump.post(request); - ensure("got response", netio.pump()); - ensure("success response", success); - ensure_equals(result["reply"].asString(), "success"); - - body["status"] = 499; - body["reason"] = "custom error message"; - request["message"] = "fail"; - request["payload"] = body; - regionPump.post(request); - ensure("got response", netio.pump()); - ensure("failure response", ! success); - ensure_equals(result["status"].asInteger(), body["status"].asInteger()); - ensure_equals(result["reason"].asString(), body["reason"].asString()); - } - - template<> template<> - void llcapears_object::test<3>() - { - LLSD request, body; - body["data"] = "yes"; - request["message"] = "unknown"; - request["payload"] = body; - request["reply"] = replyPump.getName(); - request["error"] = errorPump.getName(); - std::string threw; - try - { - WrapLLErrs capture; - regionPump.post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } - ensure_contains("bad capability name", threw, "unsupported capability"); - } - - struct TestMapper: public LLCapabilityListener::CapabilityMapper - { - // Instantiator gets to specify whether mapper expects a reply. - // I'd really like to be able to test CapabilityMapper::buildMessage() - // functionality, too, but -- even though LLCapabilityListener accepts - // the LLMessageSystem* that it passes to CapabilityMapper -- - // LLMessageSystem::sendReliable(const LLHost&) isn't virtual, so it's - // not helpful to pass a subclass instance. I suspect that making any - // LLMessageSystem methods virtual would provoke howls of outrage, - // given how heavily it's used. Nor can I just provide a local - // definition of LLMessageSystem::sendReliable(const LLHost&) because - // we're already linking in the rest of message.o via llmessage.a, and - // that produces duplicate-symbol link errors. - TestMapper(const std::string& replyMessage = std::string()): - LLCapabilityListener::CapabilityMapper("test", replyMessage) - {} - virtual void buildMessage(LLMessageSystem* msg, - const LLUUID& agentID, - const LLUUID& sessionID, - const std::string& capabilityName, - const LLSD& payload) const - { - msg->newMessageFast(_PREHASH_SetStartLocationRequest); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, agentID); - msg->addUUIDFast(_PREHASH_SessionID, sessionID); - msg->nextBlockFast( _PREHASH_StartLocationData); - // corrected by sim - msg->addStringFast(_PREHASH_SimName, ""); - msg->addU32Fast(_PREHASH_LocationID, payload["HomeLocation"]["LocationId"].asInteger()); -/*==========================================================================*| - msg->addVector3Fast(_PREHASH_LocationPos, - ll_vector3_from_sdmap(payload["HomeLocation"]["LocationPos"])); - msg->addVector3Fast(_PREHASH_LocationLookAt, - ll_vector3_from_sdmap(payload["HomeLocation"]["LocationLookAt"])); -|*==========================================================================*/ - } - }; - - template<> template<> - void llcapears_object::test<4>() - { - TestMapper testMapper("WantReply"); - LLSD request, body; - body["data"] = "yes"; - request["message"] = "test"; - request["payload"] = body; - request["reply"] = replyPump.getName(); - request["error"] = errorPump.getName(); - std::string threw; - try - { - WrapLLErrs capture; - regionPump.post(request); - } - catch (const WrapLLErrs::FatalException& e) - { - threw = e.what(); - } - ensure_contains("capability mapper wants reply", threw, "unimplemented support for reply message"); - } - - template<> template<> - void llcapears_object::test<5>() - { - TestMapper testMapper; - std::string threw; - try - { - TestMapper testMapper2; - } - catch (const std::runtime_error& e) - { - threw = e.what(); - } - ensure_contains("no dup cap mapper", threw, "DupCapMapper"); - } -} diff --git a/indra/newview/tests/llhttpretrypolicy_test.cpp b/indra/newview/tests/llhttpretrypolicy_test.cpp index 25e6de46d9..21c83184dc 100755 --- a/indra/newview/tests/llhttpretrypolicy_test.cpp +++ b/indra/newview/tests/llhttpretrypolicy_test.cpp @@ -234,13 +234,13 @@ void RetryPolicyTestObject::test<6>() std::string str1("0"); seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str1, seconds_to_wait); + success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str1, seconds_to_wait); ensure("parse 1", success); ensure_equals("parse 1", seconds_to_wait, 0.0); std::string str2("999.9"); seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str2, seconds_to_wait); + success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str2, seconds_to_wait); ensure("parse 2", success); ensure_approximately_equals("parse 2", seconds_to_wait, 999.9F, 8); @@ -248,7 +248,7 @@ void RetryPolicyTestObject::test<6>() time(&nowseconds); std::string str3 = LLDate((F64)(nowseconds+44)).asRFC1123(); seconds_to_wait = F32_MAX; - success = getSecondsUntilRetryAfter(str3, seconds_to_wait); + success = LLAdaptiveRetryPolicy::getSecondsUntilRetryAfter(str3, seconds_to_wait); std::cerr << " str3 [" << str3 << "]" << std::endl; ensure("parse 3", success); ensure_approximately_equals_range("parse 3", seconds_to_wait, 44.0F, 2.0F); @@ -285,10 +285,10 @@ void RetryPolicyTestObject::test<7>() ensure_approximately_equals_range("header 2", seconds_to_wait, 7.0F, 2.0F); LLCore::HttpResponse *response; - LLCore::HttpHeaders *headers; + LLCore::HttpHeaders::ptr_t headers; response = new LLCore::HttpResponse(); - headers = new LLCore::HttpHeaders(); + headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); response->setStatus(503); response->setHeaders(headers); headers->append(HTTP_IN_HEADER_RETRY_AFTER, std::string("600")); @@ -299,7 +299,7 @@ void RetryPolicyTestObject::test<7>() response->release(); response = new LLCore::HttpResponse(); - headers = new LLCore::HttpHeaders(); + headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()); response->setStatus(503); response->setHeaders(headers); time(&nowseconds); diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp index 6f57daf151..61120686e4 100755 --- a/indra/newview/tests/llmediadataclient_test.cpp +++ b/indra/newview/tests/llmediadataclient_test.cpp @@ -106,7 +106,7 @@ const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true"); LLSD *gPostRecords = NULL; F64 gMinimumInterestLevel = (F64)0.0; - +#if 0 // stubs: void LLHTTPClient::post( const std::string& url, @@ -140,6 +140,7 @@ void LLHTTPClient::post( } responder->successResult(result); } +#endif const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index c49b0350e9..ea5014a59c 100755 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "../test/lltut.h" +#if 0 #include "../llremoteparcelrequest.h" @@ -134,3 +135,4 @@ namespace tut processor.processParcelInfoReply(gMessageSystem, NULL); } } +#endif diff --git a/indra/newview/tests/lltranslate_test.cpp b/indra/newview/tests/lltranslate_test.cpp deleted file mode 100755 index 5e73dbb981..0000000000 --- a/indra/newview/tests/lltranslate_test.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/** - * @file lltranslate_test.cpp - * - * $LicenseInfo:firstyear=2011&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 "linden_common.h" - -#include "../test/lltut.h" -#include "../lltranslate.h" -#include "../llversioninfo.h" -#include "../llviewercontrol.h" - -#include "llbufferstream.h" -#include "lltrans.h" -#include "llui.h" - -#include "../../llmessage/llhttpconstants.cpp" - -static const std::string GOOGLE_VALID_RESPONSE1 = -"{\ - \"data\": {\ - \"translations\": [\ - {\ - \"translatedText\": \"привет\",\ - \"detectedSourceLanguage\": \"es\"\ - }\ - ]\ - }\ -}"; - -static const std::string GOOGLE_VALID_RESPONSE2 = -"{\ - \"data\": {\ - \"translations\": [\ - {\ - \"translatedText\": \"привет\"\ - }\ - ]\ - }\ -}\ -"; - -static const std::string GOOGLE_VALID_RESPONSE3 = -"{\ - \"error\": {\ - \"errors\": [\ - {\ - \"domain\": \"global\",\ - \"reason\": \"invalid\",\ - \"message\": \"Invalid Value\"\ - }\ - ],\ - \"code\": 400,\ - \"message\": \"Invalid Value\"\ - }\ -}"; - -static const std::string BING_VALID_RESPONSE1 = -"<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет</string>"; - -static const std::string BING_VALID_RESPONSE2 = -"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p><p>Parameter: </p>\ -<p>Message: 'from' must be a valid language</p><code></code>\ -<p>message id=3743.V2_Rest.Translate.58E8454F</p></body></html>"; - -static const std::string BING_VALID_RESPONSE3 = -"<html><body><h1>Argument Exception</h1><p>Method: Translate()</p>\ -<p>Parameter: appId</p><p>Message: Invalid appId
\nParameter name: appId</p>\ -<code></code><p>message id=3737.V2_Rest.Translate.56016759</p></body></html>"; - -namespace tut -{ - class translate_test - { - protected: - void test_translation( - LLTranslationAPIHandler& handler, - int status, const std::string& resp, - const std::string& exp_trans, const std::string& exp_lang, const std::string& exp_err) - { - std::string translation, detected_lang, err_msg; - bool rc = handler.parseResponse(status, resp, translation, detected_lang, err_msg); - ensure_equals("rc", rc, (status == 200)); - ensure_equals("err_msg", err_msg, exp_err); - ensure_equals("translation", translation, exp_trans); - ensure_equals("detected_lang", detected_lang, exp_lang); - } - - LLGoogleTranslationHandler mGoogle; - LLBingTranslationHandler mBing; - }; - - typedef test_group<translate_test> translate_test_group_t; - typedef translate_test_group_t::object translate_test_object_t; - tut::translate_test_group_t tut_translate("LLTranslate"); - - template<> template<> - void translate_test_object_t::test<1>() - { - test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE1, "привет", "es", ""); - } - - template<> template<> - void translate_test_object_t::test<2>() - { - test_translation(mGoogle, 200, GOOGLE_VALID_RESPONSE2, "привет", "", ""); - } - - template<> template<> - void translate_test_object_t::test<3>() - { - test_translation(mGoogle, 400, GOOGLE_VALID_RESPONSE3, "", "", "Invalid Value"); - } - - template<> template<> - void translate_test_object_t::test<4>() - { - test_translation(mGoogle, 400, - "", - "", "", "* Line 1, Column 1\n Syntax error: value, object or array expected.\n"); - } - - template<> template<> - void translate_test_object_t::test<5>() - { - test_translation(mGoogle, 400, - "[]", - "", "", ""); - } - - template<> template<> - void translate_test_object_t::test<6>() - { - test_translation(mGoogle, 400, - "{\"oops\": \"invalid\"}", - "", "", ""); - } - - template<> template<> - void translate_test_object_t::test<7>() - { - test_translation(mGoogle, 400, - "{\"data\": {}}", - "", "", ""); - } - - template<> template<> - void translate_test_object_t::test<8>() - { - test_translation(mGoogle, 400, - "{\"data\": { \"translations\": [ {} ] }}", - "", "", ""); - } - - template<> template<> - void translate_test_object_t::test<9>() - { - test_translation(mGoogle, 400, - "{\"data\": { \"translations\": [ { \"translatedTextZZZ\": \"привет\", \"detectedSourceLanguageZZZ\": \"es\" } ] }}", - "", "", ""); - } - - template<> template<> - void translate_test_object_t::test<10>() - { - test_translation(mBing, 200, BING_VALID_RESPONSE1, "Привет", "", ""); - } - - template<> template<> - void translate_test_object_t::test<11>() - { - test_translation(mBing, 400, BING_VALID_RESPONSE2, "", "", "'from' must be a valid language"); - } - - template<> template<> - void translate_test_object_t::test<12>() - { - test_translation(mBing, 400, BING_VALID_RESPONSE3, "", "", "Invalid appId\nParameter name: appId"); - } - - template<> template<> - void translate_test_object_t::test<13>() - { - test_translation(mBing, 200, - "Привет</string>", - "Привет", "", ""); - } - - template<> template<> - void translate_test_object_t::test<14>() - { - test_translation(mBing, 200, - "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">Привет", - "Привет", "", ""); - } - - template<> template<> - void translate_test_object_t::test<15>() - { - test_translation(mBing, 200, - "Привет", - "Привет", "", ""); - } - - template<> template<> - void translate_test_object_t::test<16>() - { - test_translation(mBing, 400, - "Message: some error</p>", - "", "", "some error"); - } - - template<> template<> - void translate_test_object_t::test<17>() - { - test_translation(mBing, 400, - "Message: some error", - "", "", "some error"); - } - - template<> template<> - void translate_test_object_t::test<18>() - { - test_translation(mBing, 400, - "some error</p>", - "", "", "some error"); - } - - template<> template<> - void translate_test_object_t::test<19>() - { - test_translation(mBing, 400, - "some error", - "", "", "some error"); - } - - template<> template<> - void translate_test_object_t::test<20>() - { - std::string url; - mBing.getTranslateURL(url, "en", "es", "hi"); - ensure_equals("bing URL", url, - "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es&from=en"); - } - - template<> template<> - void translate_test_object_t::test<21>() - { - std::string url; - mBing.getTranslateURL(url, "", "es", "hi"); - ensure_equals("bing URL", url, - "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=dummy&text=hi&to=es"); - } - - template<> template<> - void translate_test_object_t::test<22>() - { - std::string url; - mGoogle.getTranslateURL(url, "en", "es", "hi"); - ensure_equals("google URL", url, - "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es&source=en"); - } - - template<> template<> - void translate_test_object_t::test<23>() - { - std::string url; - mGoogle.getTranslateURL(url, "", "es", "hi"); - ensure_equals("google URL", url, - "https://www.googleapis.com/language/translate/v2?key=dummy&q=hi&target=es"); - } -} - -//== Misc stubs =============================================================== -LLControlGroup gSavedSettings("test"); - -std::string LLUI::getLanguage() { return "en"; } -std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args) { return "dummy"; } - -LLControlGroup::LLControlGroup(const std::string& name) : LLInstanceTracker<LLControlGroup, std::string>(name) {} -std::string LLControlGroup::getString(const std::string& name) { return "dummy"; } -LLControlGroup::~LLControlGroup() {} - -LLCurl::Responder::Responder() {} -void LLCurl::Responder::httpFailure() { } -void LLCurl::Responder::httpSuccess() { } -void LLCurl::Responder::httpCompleted() { } -void LLCurl::Responder::completedRaw(LLChannelDescriptors const &,boost::shared_ptr<LLBufferArray> const &) { } -LLCurl::Responder::~Responder() {} - -void LLHTTPClient::get(const std::string&, const LLSD&, ResponderPtr, const LLSD&, const F32, bool) {} -void LLHTTPClient::get(const std::string&, LLPointer<LLCurl::Responder>, const LLSD&, const F32, bool) {} - -LLBufferStream::LLBufferStream(const LLChannelDescriptors& channels, LLBufferArray* buffer) -: std::iostream(&mStreamBuf), mStreamBuf(channels, buffer) {} -LLBufferStream::~LLBufferStream() {} - -LLBufferStreamBuf::LLBufferStreamBuf(const LLChannelDescriptors&, LLBufferArray*) {} -#if( LL_WINDOWS || __GNUC__ > 2) -LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff( - off_type off, - std::ios::seekdir way, - std::ios::openmode which) -#else -streampos LLBufferStreamBuf::seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which) -#endif -{ return 0; } -int LLBufferStreamBuf::sync() {return 0;} -int LLBufferStreamBuf::underflow() {return 0;} -int LLBufferStreamBuf::overflow(int) {return 0;} -LLBufferStreamBuf::~LLBufferStreamBuf() {} - -S32 LLVersionInfo::getBuild() { return 0; } -const std::string& LLVersionInfo::getChannel() {static std::string dummy; return dummy;} -S32 LLVersionInfo::getMajor() { return 0; } -S32 LLVersionInfo::getMinor() { return 0; } -S32 LLVersionInfo::getPatch() { return 0; } |