diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 929da0e9cb5799c72aa22285e37aa5dd43b11893..227b1c5461979f6dcd6de1fa4f384f8e8339f702 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16034,6 +16034,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>UseHTTPInventory</key> + <map> + <key>Comment</key> + <string>Allow use of http inventory transfers instead of UDP</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>ClickToWalk</key> <map> <key>Comment</key> diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 2ec20b827176a3683f8d109ebc7c01ff81917cbc..e6a77c8ccbb1e1336b64b7b0e4487ef4c6d7392e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -3035,7 +3035,9 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory, processBulkUpdateInventory, NULL); + msg->setHandlerFuncFast(_PREHASH_InventoryDescendents, processInventoryDescendents); msg->setHandlerFuncFast(_PREHASH_MoveInventoryItem, processMoveInventoryItem); + msg->setHandlerFuncFast(_PREHASH_FetchInventoryReply, processFetchInventoryReply); } @@ -3055,6 +3057,14 @@ void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, vo } +// static +void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**) +{ + // no accounting + gInventory.messageUpdateCore(msg, false); +} + + bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { //make sure our added inventory observer is active @@ -3519,6 +3529,62 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) } } +// static +void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) +{ + LLUUID agent_id; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + if(agent_id != gAgent.getID()) + { + LL_WARNS() << "Got a UpdateInventoryItem for the wrong agent." << LL_ENDL; + return; + } + LLUUID parent_id; + msg->getUUID("AgentData", "FolderID", parent_id); + LLUUID owner_id; + msg->getUUID("AgentData", "OwnerID", owner_id); + S32 version; + msg->getS32("AgentData", "Version", version); + S32 descendents; + msg->getS32("AgentData", "Descendents", descendents); + + S32 i; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id); + for(i = 0; i < count; ++i) + { + tcategory->unpackMessage(msg, _PREHASH_FolderData, i); + gInventory.updateCategory(tcategory); + } + + count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); + LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; + for(i = 0; i < count; ++i) + { + titem->unpackMessage(msg, _PREHASH_ItemData, i); + // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added. + if (gInventory.getItem(titem->getUUID())) + { + LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() + << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; + continue; + } + gInventory.updateItem(titem); + } + + // set version and descendentcount according to message. + LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); + if(cat) + { + cat->setVersion(version); + cat->setDescendentCount(descendents); + // Get this UUID on the changed list so that whatever's listening for it + // will get triggered. + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat->getUUID()); + } + gInventory.notifyObservers(); +} + // static void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index d60884c3516c31c6f963936e1805b18331ea9bf7..cf8b1613306becb86c9b36b81a3b6ff58080ce69 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -664,7 +664,9 @@ class LLInventoryModel static void processRemoveInventoryObjects(LLMessageSystem* msg, void**); static void processSaveAssetIntoInventory(LLMessageSystem* msg, void**); static void processBulkUpdateInventory(LLMessageSystem* msg, void**); + static void processInventoryDescendents(LLMessageSystem* msg, void**); static void processMoveInventoryItem(LLMessageSystem* msg, void**); + static void processFetchInventoryReply(LLMessageSystem* msg, void**); protected: bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting, U32 mask = 0x0); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 362fed2aa009b7d13e8b6b3b1214f57a82ae69f7..dc9436dd6b94631adccc9c13d8484cb89c72745c 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -41,6 +41,8 @@ #include "bufferarray.h" #include "bufferstream.h" #include "llcorehttputil.h" +#include "llviewermenu.h" +#include "llviewernetwork.h" // History (may be apocryphal) // @@ -174,6 +176,8 @@ class BGFolderHttpHandler : public LLCore::HttpHandler }; +const S32 MAX_FETCH_RETRIES = 10; + const char * const LOG_INV("Inventory"); } // end of namespace anonymous @@ -190,7 +194,11 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch(): mAllFoldersFetched(FALSE), mRecursiveInventoryFetchStarted(FALSE), mRecursiveLibraryFetchStarted(FALSE), - mMinTimeBetweenFetches(0.3f) + mTimelyFetchPending(FALSE), + mNumFetchRetries(0), + mMinTimeBetweenFetches(0.3f), + mMaxTimeBetweenFetches(10.f) + {} LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() @@ -339,7 +347,164 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - bulkFetch(); + if (LLGridManager::instanceFast().isInSecondlife() || gSavedSettings.getBOOL("UseHTTPInventory")) + { + bulkFetch(); + return; + } + +#if 1 + //-------------------------------------------------------------------------------- + // DEPRECATED OLD CODE + // + + // No more categories to fetch, stop fetch process. + if (mFetchQueue.empty()) + { + setAllFoldersFetched(); + return; + } + + F32 fast_fetch_time = ll_lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f); + F32 slow_fetch_time = ll_lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f); + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time) + { + // Double timeouts on failure. + mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f); + mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f); + LL_DEBUGS(LOG_INV) << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL; + // fetch is no longer considered "timely" although we will wait for full time-out. + mTimelyFetchPending = FALSE; + } + + while(1) + { + if (mFetchQueue.empty()) + { + break; + } + + if (gDisconnected) + { + // Just bail if we are disconnected. + break; + } + + const FetchQueueInfo info = mFetchQueue.front(); + + if (info.mIsCategory) + { + + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mUUID); + + // Category has been deleted, remove from queue. + if (!cat) + { + mFetchQueue.pop_front(); + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && + LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + // Category exists but has no children yet, fetch the descendants + // for now, just request every time and rely on retry timer to throttle. + if (cat->fetch()) + { + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else + { + // The catagory also tracks if it has expired and here it says it hasn't + // yet. Get out of here because nothing is going to happen until we + // update the timers. + break; + } + } + // Do I have all my children? + else if (gInventory.isCategoryComplete(info.mUUID)) + { + // Finished with this category, remove from queue. + mFetchQueue.pop_front(); + + // Add all children to queue. + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); + } + + // We received a response in less than the fast time. + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) + { + // Shrink timeouts based on success. + mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); + mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); + LL_DEBUGS(LOG_INV) << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL; + } + + mTimelyFetchPending = FALSE; + continue; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + // Received first packet, but our num descendants does not match db's num descendants + // so try again later. + mFetchQueue.pop_front(); + + if (mNumFetchRetries++ < MAX_FETCH_RETRIES) + { + // push on back of queue + mFetchQueue.push_back(info); + } + mTimelyFetchPending = FALSE; + mFetchTimer.reset(); + break; + } + + // Not enough time has elapsed to do a new fetch + break; + } + else + { + LLViewerInventoryItem* itemp = gInventory.getItem(info.mUUID); + + mFetchQueue.pop_front(); + if (!itemp) + { + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches) + { + itemp->fetchFromServer(); + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else if (itemp->mIsComplete) + { + mTimelyFetchPending = FALSE; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + mFetchQueue.push_back(info); + mFetchTimer.reset(); + mTimelyFetchPending = FALSE; + } + // Not enough time has elapsed to do a new fetch + break; + } + } + + // + // DEPRECATED OLD CODE + //-------------------------------------------------------------------------------- +#endif } } @@ -391,7 +556,10 @@ void LLInventoryModelBackgroundFetch::bulkFetch() // OnIdle it will be called anyway due to Add flag for processed item. // It seems like in some cases we are updaiting on fail (no flag), // but is there anything to update? - gInventory.notifyObservers(); + if (LLGridManager::getInstance()->isInSecondlife()) + { + gInventory.notifyObservers(); + } } if ((mFetchCount > max_concurrent_fetches) || @@ -700,6 +868,10 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res titem->setParent(lost_uuid); titem->updateParentOnServer(FALSE); gInventory.updateItem(titem); + if (!LLGridManager::getInstance()->isInSecondlife()) + { + gInventory.notifyObservers(); + } } } } @@ -761,6 +933,11 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res { fetcher->setAllFoldersFetched(); } + + if (!LLGridManager::getInstance()->isInSecondlife()) + { + gInventory.notifyObservers(); + } } @@ -800,6 +977,11 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http fetcher->setAllFoldersFetched(); } } + + if (!LLGridManager::getInstance()->isInSecondlife()) + { + gInventory.notifyObservers(); + } } @@ -834,6 +1016,11 @@ void BGFolderHttpHandler::processFailure(const char * const reason, LLCore::Http fetcher->setAllFoldersFetched(); } } + + if (!LLGridManager::getInstance()->isInSecondlife()) + { + gInventory.notifyObservers(); + } } diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index b7839cf08075b033614cd793207906656967069f..67066bc0e2402cc2239398eb5e2faca87a594985 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -89,7 +89,11 @@ class LLInventoryModelBackgroundFetch final : public LLSingleton<LLInventoryMode S32 mFetchCount; LLFrameTimer mFetchTimer; + BOOL mTimelyFetchPending; + S32 mNumFetchRetries; F32 mMinTimeBetweenFetches; + F32 mMaxTimeBetweenFetches; + struct FetchQueueInfo { diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 8ef8e0cc6a3ccd76a3b86096d8ffe6d05f32c9e7..be6de01a62aedc753d5c8584a81ef2282c55f610 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -56,6 +56,8 @@ #include "llsdutil.h" #include <deque> +#include "llviewernetwork.h" + const F32 LLInventoryFetchItemsObserver::FETCH_TIMER_EXPIRY = 60.0f; @@ -241,11 +243,39 @@ void fetch_items_from_llsd(const LLSD& items_llsd) gInventory.requestPost(true, url, body[i], handler, (i ? "Library Item" : "Inventory Item")); continue; } - else - { - LL_WARNS("INVENTORY") << "Failed to get capability." << LL_ENDL; - } - + else if (!LLGridManager::instance().isInSecondlife()) + { + LLMessageSystem* msg = gMessageSystem; + BOOL start_new_message = TRUE; + for (S32 j = 0; j < body[i]["items"].size(); j++) + { + LLSD item_entry = body[i]["items"][j]; + if (start_new_message) + { + start_new_message = FALSE; + msg->newMessageFast(_PREHASH_FetchInventory); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID()); + msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID()); + if (msg->isSendFull(NULL)) + { + start_new_message = TRUE; + gAgent.sendReliableMessage(); + } + } + if (!start_new_message) + { + gAgent.sendReliableMessage(); + } + } + else + { + LL_WARNS("INVENTORY") << "Failed to get capability or udp fallback." << LL_ENDL; + } } } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index d7c6f692f686d019457d9748edd99b31861a552e..ff85fbfc039f6071990e1876b0d1098df9024c1d 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -429,26 +429,42 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); gInventory.accountForUpdate(up); - LLSD updates = asLLSD(); - // Replace asset_id and/or shadow_id with transaction_id (hash_id) - if (updates.has("asset_id")) - { - updates.erase("asset_id"); - if(getTransactionID().notNull()) + if (AISAPI::isAvailable()) + { + LLSD updates = asLLSD(); + // Replace asset_id and/or shadow_id with transaction_id (hash_id) + if (updates.has("asset_id")) { - updates["hash_id"] = getTransactionID(); + updates.erase("asset_id"); + if(getTransactionID().notNull()) + { + updates["hash_id"] = getTransactionID(); + } } - } - if (updates.has("shadow_id")) - { - updates.erase("shadow_id"); - if(getTransactionID().notNull()) + if (updates.has("shadow_id")) { - updates["hash_id"] = getTransactionID(); + updates.erase("shadow_id"); + if(getTransactionID().notNull()) + { + updates["hash_id"] = getTransactionID(); + } } - } - AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL, _1); - AISAPI::UpdateItem(getUUID(), updates, cr); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL, _1); + AISAPI::UpdateItem(getUUID(), updates, cr); + } + else + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + packMessage(msg); + gAgent.sendReliableMessage(); + } } void LLViewerInventoryItem::fetchFromServer(void) const @@ -657,9 +673,26 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const return; } - LLSD new_llsd = asLLSD(); - AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL, _1); - AISAPI::UpdateCategory(getUUID(), new_llsd, cr); + if (AISAPI::isAvailable()) + { + LLSD new_llsd = asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL, _1); + AISAPI::UpdateCategory(getUUID(), new_llsd, cr); + } + else + { + LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); + gInventory.accountForUpdate(up); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + packMessage(msg); + gAgent.sendReliableMessage(); + } } S32 LLViewerInventoryCategory::getVersion() const @@ -696,6 +729,29 @@ bool LLViewerInventoryCategory::fetch() { LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } + else + { + // bitfield + // 1 = by date + // 2 = folders by date + // Need to mask off anything but the first bit. + // This comes from LLInventoryFilter from llfolderview.h + U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("FetchInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", mUUID); + msg->addUUID("OwnerID", mOwnerID); + + msg->addS32("SortOrder", sort_order); + msg->addBOOL("FetchFolders", FALSE); + msg->addBOOL("FetchItems", TRUE); + gAgent.sendReliableMessage(); + } return true; } return false; @@ -824,16 +880,33 @@ void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type) const LLUUID &parent_id = getParentUUID(); const std::string &name = getName(); - LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(folder_id, - parent_id, - new_folder_type, - name, - gAgent.getID()); + if (AISAPI::isAvailable()) + { + LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(folder_id, + parent_id, + new_folder_type, + name, + gAgent.getID()); - LLSD new_llsd = new_cat->asLLSD(); - AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>) NULL, _1); - AISAPI::UpdateCategory(folder_id, new_llsd, cr); + LLSD new_llsd = new_cat->asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>) NULL, _1); + AISAPI::UpdateCategory(folder_id, new_llsd, cr); + } + else + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + } setPreferredType(new_folder_type); gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); @@ -1238,10 +1311,40 @@ void link_inventory_array(const LLUUID& category, << " UUID:" << category << " ] " << LL_ENDL; #endif } - LLSD new_inventory = LLSD::emptyMap(); - new_inventory["links"] = links; - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::CreateInventory(category, new_inventory, cr); + + if (AISAPI::isAvailable()) + { + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["links"] = links; + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::CreateInventory(category, new_inventory, cr); + } + else + { + LLMessageSystem* msg = gMessageSystem; + for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) + { + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlock(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlock(_PREHASH_InventoryBlock); + { + LLSD link = (*iter); + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, category); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); + msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID()); + msg->addS8Fast(_PREHASH_Type, link["type"].asInteger()); + msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger()); + msg->addStringFast(_PREHASH_Name, link["name"].asString()); + msg->addStringFast(_PREHASH_Description, link["desc"].asString()); + } + gAgent.sendReliableMessage(); + } + } } void move_inventory_item( @@ -1273,27 +1376,55 @@ void update_inventory_item( LLPointer<LLInventoryCallback> cb) { const LLUUID& item_id = update_item->getUUID(); - - LLSD updates = update_item->asLLSD(); - // Replace asset_id and/or shadow_id with transaction_id (hash_id) - if (updates.has("asset_id")) - { - updates.erase("asset_id"); - if (update_item->getTransactionID().notNull()) - { - updates["hash_id"] = update_item->getTransactionID(); - } - } - if (updates.has("shadow_id")) - { - updates.erase("shadow_id"); - if (update_item->getTransactionID().notNull()) - { - updates["hash_id"] = update_item->getTransactionID(); - } - } - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::UpdateItem(item_id, updates, cr); + if (AISAPI::isAvailable()) + { + LLSD updates = update_item->asLLSD(); + // Replace asset_id and/or shadow_id with transaction_id (hash_id) + if (updates.has("asset_id")) + { + updates.erase("asset_id"); + if (update_item->getTransactionID().notNull()) + { + updates["hash_id"] = update_item->getTransactionID(); + } + } + if (updates.has("shadow_id")) + { + updates.erase("shadow_id"); + if (update_item->getTransactionID().notNull()) + { + updates["hash_id"] = update_item->getTransactionID(); + } + } + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateItem(item_id, updates, cr); + } + 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; + if(obj) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + update_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(update_item); + if (cb) + { + cb->fire(item_id); + } + } + } } // Note this only supports updating an existing item. Goes through AISv3 @@ -1304,8 +1435,41 @@ void update_inventory_item( const LLSD& updates, LLPointer<LLInventoryCallback> cb) { - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::UpdateItem(item_id, updates, cr); + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateItem(item_id, updates, cr); + } + else + { + LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); + new_item->copyViewerItem(obj); + new_item->fromLLSD(updates,false); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + new_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(new_item); + if (cb) + { + cb->fire(item_id); + } + } + } } void update_inventory_category( @@ -1325,9 +1489,31 @@ void update_inventory_category( LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj); new_cat->fromLLSD(updates); - LLSD new_llsd = new_cat->asLLSD(); - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::UpdateCategory(cat_id, new_llsd, cr); + if (AISAPI::isAvailable()) + { + LLSD new_llsd = new_cat->asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateCategory(cat_id, new_llsd, cr); + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + new_cat->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateCategory(new_cat); + if (cb) + { + cb->fire(cat_id); + } + } } } @@ -1449,8 +1635,41 @@ void remove_inventory_category( LLNotificationsUtil::add("CannotRemoveProtectedCategories"); return; } - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::RemoveCategory(cat_id, cr); + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::RemoveCategory(cat_id, cr); + } + else // no cap + { + // RemoveInventoryFolder does not remove children, so must + // clear descendents first. + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); + if(children != LLInventoryModel::CHILDREN_NO) + { + LL_DEBUGS(LOG_INV) << "Will purge descendents first before deleting category " << cat_id << LL_ENDL; + LLPointer<LLInventoryCallback> wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb); + purge_descendents_of(cat_id, wrap_cb); + return; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, cat_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(cat_id); + if (cb) + { + cb->fire(cat_id); + } + } } else { @@ -1729,11 +1948,47 @@ void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> cb) { - LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id - << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + if (AISAPI::isAvailable()) + { + LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; - AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); - AISAPI::SlamFolder(folder_id, contents, cr); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::SlamFolder(folder_id, contents, cr); + } + else // no cap + { +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) + LL_DEBUGS(LOG_INV) << "using item-by-item calls to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + + LLInventoryModel::item_array_t items; + for (LLSD::array_const_iterator itItem = contents.beginArray(); itItem != contents.endArray(); ++itItem) + { + LLViewerInventoryItem* pItem = new LLViewerInventoryItem; + pItem->fromLLSD(*itItem); + items.push_back(pItem); + } + + LLInventoryModel::item_array_t items_to_add, items_to_remove; + sync_inventory_folder(folder_id, items, items_to_add, items_to_remove); + + link_inventory_items(folder_id, items_to_add, cb); + remove_inventory_items(items_to_remove, cb); +// [/RLVa:KB] +// LL_DEBUGS(LOG_INV) << "using item-by-item calls to slam folder, id " << folder_id +// << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; +// for (LLSD::array_const_iterator it = contents.beginArray(); +// it != contents.endArray(); +// ++it) +// { +// const LLSD& item_contents = *it; +// LLViewerInventoryItem *item = new LLViewerInventoryItem; +// item->fromLLSD(item_contents); +// link_inventory_object(folder_id, item, cb); +// } +// remove_folder_contents(folder_id,false,cb); + } } void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index fa1b12878883538b6816ce892d8d4cd01b9a002b..c1ddf5f3aad6e00c6aee9a1180611d815cb94680 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -83,6 +83,7 @@ #include "llcallstack.h" #include "llsettingsdaycycle.h" #include "llviewerparcelmgr.h" +#include "llviewernetwork.h" #include <boost/regex.hpp> @@ -2997,12 +2998,15 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("EventQueueGet"); capabilityNames.append("ExtEnvironment"); - capabilityNames.append("FetchLib2"); - capabilityNames.append("FetchLibDescendents2"); - capabilityNames.append("FetchInventory2"); - capabilityNames.append("FetchInventoryDescendents2"); - capabilityNames.append("IncrementCOFVersion"); - AISAPI::getCapNames(capabilityNames); + if (LLGridManager::instanceFast().isInSecondlife() || gSavedSettings.getBOOL("UseHTTPInventory")) + { + capabilityNames.append("FetchLib2"); + capabilityNames.append("FetchLibDescendents2"); + capabilityNames.append("FetchInventory2"); + capabilityNames.append("FetchInventoryDescendents2"); + capabilityNames.append("IncrementCOFVersion"); + AISAPI::getCapNames(capabilityNames); + } capabilityNames.append("InterestList");