From d843a0d8bef5d36d3a4ef838b1b0335b4532147b Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Thu, 25 Apr 2013 17:09:05 -0400 Subject: SH-4137 WIP - added callback-based support for purge descendents, remove category --- indra/llinventory/llinventory.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 41d58c6deb..a4cd8333cf 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -249,13 +249,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co return TRUE; } - -void LLInventoryObject::removeFromServer() -{ - // don't do nothin' - llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl; -} - void LLInventoryObject::updateParentOnServer(BOOL) const { // don't do nothin' -- cgit v1.3 From 6c56c77ec575141963c5de8dfa228253fe175bc3 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 24 May 2013 08:53:21 -0400 Subject: SH-4027 WIP - initial implementation of item update via AIS. --- indra/llinventory/llinventory.cpp | 2 +- indra/llinventory/llinventory.h | 4 +- indra/llmessage/llhttpclient.cpp | 12 +- indra/llmessage/llhttpclient.h | 8 + indra/llmessage/llhttpconstants.h | 37 ++- indra/llmessage/llurlrequest.cpp | 11 + indra/newview/llappearancemgr.cpp | 4 +- indra/newview/llinventorybridge.cpp | 10 +- indra/newview/llinventoryfunctions.cpp | 9 +- indra/newview/llinventorymodel.cpp | 93 +++++- indra/newview/llinventorymodel.h | 6 + indra/newview/llviewerinventory.cpp | 510 +++++++++++++++++++++++---------- indra/newview/llviewerinventory.h | 14 + 13 files changed, 523 insertions(+), 197 deletions(-) mode change 100644 => 100755 indra/llmessage/llhttpconstants.h (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index a4cd8333cf..641532ec29 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -261,7 +261,7 @@ void LLInventoryObject::updateServer(BOOL) const llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl; } -inline +// static void LLInventoryObject::correctInventoryName(std::string& name) { LLStringUtil::replaceNonstandardASCII(name, ' '); diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 8b865f044d..17421b3f5e 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -86,16 +86,14 @@ public: void setType(LLAssetType::EType type); virtual void setCreationDate(time_t creation_date_utc); // only stored for items -private: // in place correction for inventory name string - void correctInventoryName(std::string& name); + static void correctInventoryName(std::string& name); //-------------------------------------------------------------------- // File Support // Implemented here so that a minimal information set can be transmitted // between simulator and viewer. //-------------------------------------------------------------------- -public: // virtual BOOL importFile(LLFILE* fp); virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const; virtual BOOL importLegacyStream(std::istream& input_stream); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 5830a5eca0..53cef54559 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -304,7 +304,7 @@ static void request( gMessageSystem->mPort)); } - if (method == HTTP_PUT || method == HTTP_POST) + if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH) { if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE)) { @@ -556,6 +556,16 @@ void LLHTTPClient::put( request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); } +void LLHTTPClient::patch( + const std::string& url, + const LLSD& body, + ResponderPtr responder, + const LLSD& headers, + const F32 timeout) +{ + request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers); +} + void LLHTTPClient::post( const std::string& url, const LLSD& body, diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index a7236ba169..4e7495495f 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -74,6 +74,14 @@ public: ResponderPtr, const LLSD& headers = LLSD(), const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + + static void patch( + const std::string& url, + const LLSD& body, + ResponderPtr, + const LLSD& headers = LLSD(), + const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h old mode 100644 new mode 100755 index 8cc3459654..aa947af414 --- a/indra/llmessage/llhttpconstants.h +++ b/indra/llmessage/llhttpconstants.h @@ -2,31 +2,25 @@ * @file llhttpconstants.h * @brief Constants for HTTP requests and responses * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2013, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2001-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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -117,6 +111,7 @@ enum EHTTPMethod HTTP_DELETE, HTTP_MOVE, // Caller will need to set 'Destination' header HTTP_OPTIONS, + HTTP_PATCH, HTTP_METHOD_COUNT }; diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 49cfef2771..cadff49cb8 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -487,6 +487,17 @@ bool LLURLRequest::configure() rv = true; break; + case HTTP_PATCH: + // Disable the expect http 1.1 extension. POST and PUT default + // to turning this on, and I am not too sure what it means. + addHeader(HTTP_OUT_HEADER_EXPECT); + + mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); + mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); + mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH"); + rv = true; + break; + case HTTP_POST: // Disable the expect http 1.1 extension. POST and PUT default // to turning this on, and I am not too sure what it means. diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index cfe9055aab..14eed6e1df 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2812,8 +2812,10 @@ struct WearablesOrderComparator //items with ordering information but not for the associated wearables type if (!item1_valid && item2_valid) return false; + else if (item1_valid && !item2_valid) + return true; - return true; + return item1->getName() < item2->getName(); } U32 mControlSize; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c32abe507e..89c56ab82c 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1692,13 +1692,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name) LLViewerInventoryItem* item = getItem(); if(item && (item->getName() != new_name)) { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - new_item->updateServer(FALSE); - model->updateItem(new_item); - - model->notifyObservers(); - buildDisplayName(); + LLSD updates; + updates["name"] = new_name; + update_inventory_item(item->getUUID(),updates, NULL); } // return FALSE because we either notified observers (& therefore // rebuilt) or we didn't update. diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index f1a4889f5a..b5fb226872 100755 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s return; } - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); - - model->notifyObservers(); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 73ef3e60da..06c614aeaa 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1196,6 +1196,36 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS onObjectDeletedFromServer(*it, false); } + if (update.has("item_id")) + { + // item has been modified or possibly created (would be better if we could distinguish these cases directly) + LLUUID item_id = update["item_id"].asUUID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LLViewerInventoryCategory *cat = gInventory.getCategory(item_id); + if (item) + { + LLSD changes; + if (update.has("name") && update["name"] != item->getName()) + { + changes["name"] = update["name"]; + } + if (update.has("desc") && update["desc"] != item->getActualDescription()) + { + changes["desc"] = update["desc"]; + } + onItemUpdated(item_id,changes); + } + else if (cat) + { + llerrs << "don't handle cat update yet" << llendl; + } + else + { + llerrs << "don't handle creation case yet" << llendl; + } + + } + // TODO - how can we use this version info? Need to be sure all // changes are going through AIS first, or at least through // something with a reliable responder. @@ -1212,10 +1242,71 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS } } #endif - } +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer item = gInventory.getItem(item_id); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << llendl; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + llinfos << "Updating name from " << item->getName() << " to " << it->second.asString() << llendl; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + llinfos << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << llendl; + item->setDescription(it->second.asString()); + } + else + { + llerrs << "unhandled updates for field: " << it->first << llendl; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + gInventory.notifyObservers(); // do we want to be able to make this optional? + } +} + +void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer cat = gInventory.getCategory(cat_id); + LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << llendl; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + llinfos << "Updating name from " << cat->getName() << " to " << it->second.asString() << llendl; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + llerrs << "unhandled updates for field: " << it->first << llendl; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + gInventory.notifyObservers(); // do we want to be able to make this optional? + } +} + // Update model after descendents have been purged. void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 696d0a9163..515c99c0b4 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -339,6 +339,12 @@ public: // Update model after all descendents removed from server. void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); + // Update model after an existing item gets updated on server. + void onItemUpdated(const LLUUID& item_id, const LLSD& updates); + + // Update model after an existing category gets updated on server. + void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); + // Delete a particular inventory object by ID. Will purge one // object from the internal data structures, maintaining a // consistent internal state. No cache accounting, observer diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 50d67463c7..90fef3b5ed 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -259,6 +259,240 @@ public: LLInventoryHandler gInventoryHandler; +///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- +class AISCommand: public LLHTTPClient::Responder +{ +public: + typedef boost::function command_func_type; + + AISCommand(LLPointer callback): + mCallback(callback) + { + mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); + } + + virtual ~AISCommand() + { + } + + void run_command() + { + mCommandFunc(); + } + + void setCommandFunc(command_func_type command_func) + { + mCommandFunc = command_func; + } + + // Need to do command-specific parsing to get an id here. May or + // may not need to bother, since most LLInventoryCallbacks do + // their work in the destructor. + virtual bool getResponseUUID(const LLSD& content, LLUUID& id) + { + return false; + } + + /* virtual */ void 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); + + if (mCallback) + { + LLUUID item_id; // will default to null if parse fails. + getResponseUUID(content,item_id); + mCallback->fire(item_id); + } + } + + /*virtual*/ void httpFailure() + { + const LLSD& content = getContent(); + S32 status = getStatus(); + const std::string& reason = getReason(); + const LLSD& headers = getResponseHeaders(); + if (!content.isMap()) + { + LL_DEBUGS("Inventory") << "Malformed response contents " << content + << " status " << status << " reason " << reason << llendl; + } + else + { + LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content) + << " status " << status << " reason " << reason << llendl; + } + 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. + setCommandFunc(no_op); + } + } + + static bool getCap(std::string& cap) + { + if (gAgent.getRegion()) + { + cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); + } + if (!cap.empty()) + { + return true; + } + return false; + } + +private: + command_func_type mCommandFunc; + LLPointer mRetryPolicy; + LLPointer mCallback; +}; + +class RemoveItemCommand: public AISCommand +{ +public: + RemoveItemCommand(const LLUUID& item_id, + LLPointer callback): + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + std::string url = cap + std::string("/item/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << llendl; + 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); + } +}; + +class RemoveCategoryCommand: public AISCommand +{ +public: + RemoveCategoryCommand(const LLUUID& item_id, + LLPointer callback): + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + std::string url = cap + std::string("/category/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << llendl; + 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); + } +}; + +class PurgeDescendentsCommand: public AISCommand +{ +public: + PurgeDescendentsCommand(const LLUUID& item_id, + LLPointer callback): + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; + LL_DEBUGS("Inventory") << "url: " << url << llendl; + 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); + } +}; + +class UpdateItemCommand: public AISCommand +{ +public: + UpdateItemCommand(const LLUUID& item_id, + const LLSD& updates, + LLPointer callback): + mUpdates(updates), + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + std::string url = cap + std::string("/item/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << llendl; + 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); + } +private: + LLSD mUpdates; +}; + +class UpdateCategoryCommand: public AISCommand +{ +public: + UpdateCategoryCommand(const LLUUID& item_id, + const LLSD& updates, + LLPointer callback): + mUpdates(updates), + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + std::string url = cap + std::string("/category/") + item_id.asString(); + LL_DEBUGS("Inventory") << "url: " << url << llendl; + 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); + } +private: + LLSD mUpdates; +}; + ///---------------------------------------------------------------------------- /// Class LLViewerInventoryItem ///---------------------------------------------------------------------------- @@ -456,6 +690,20 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_ // virtual void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const { + static const LLSD updates; + packUpdateMessage(msg,updates); +} + +void LLViewerInventoryItem::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const +{ + for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it) + { + if ((it->first != "desc") && (it->first != "name")) + { + llerrs << "unhandled field: " << it->first << llendl; + } + } + msg->addUUIDFast(_PREHASH_ItemID, mUUID); msg->addUUIDFast(_PREHASH_FolderID, mParentUUID); mPermissions.packMessage(msg); @@ -466,12 +714,29 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const msg->addS8Fast(_PREHASH_InvType, type); msg->addU32Fast(_PREHASH_Flags, mFlags); mSaleInfo.packMessage(msg); - msg->addStringFast(_PREHASH_Name, mName); - msg->addStringFast(_PREHASH_Description, mDescription); + if (updates.has("name")) + { + std::string new_name = updates["name"].asString(); + LLInventoryObject::correctInventoryName(new_name); + msg->addStringFast(_PREHASH_Name, new_name); + } + else + { + msg->addStringFast(_PREHASH_Name, mName); + } + if (updates.has("desc")) + { + msg->addStringFast(_PREHASH_Description, updates["desc"].asString()); + } + else + { + msg->addStringFast(_PREHASH_Description, mDescription); + } msg->addS32Fast(_PREHASH_CreationDate, mCreationDate); U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); } + // virtual BOOL LLViewerInventoryItem::importFile(LLFILE* fp) { @@ -583,6 +848,32 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego } +void LLViewerInventoryCategory::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const +{ + for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it) + { + if (it->first != "name") + { + llerrs << "unhandled field: " << it->first << llendl; + } + } + + msg->addUUIDFast(_PREHASH_FolderID, mUUID); + msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); + S8 type = static_cast(mPreferredType); + msg->addS8Fast(_PREHASH_Type, type); + if (updates.has("name")) + { + std::string new_name = updates["name"].asString(); + LLInventoryObject::correctInventoryName(new_name); + msg->addStringFast(_PREHASH_Name, new_name); + } + else + { + msg->addStringFast(_PREHASH_Name, mName); + } +} + void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const { LLMessageSystem* msg = gMessageSystem; @@ -1139,180 +1430,87 @@ void move_inventory_item( gAgent.sendReliableMessage(); } -class AISCommand: public LLHTTPClient::Responder +// Note this only supports updating an existing item. Goes through AISv3 +// code path where available. Not all uses of item->updateServer() can +// easily be switched to this paradigm. +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer cb) { -public: - typedef boost::function command_func_type; - - AISCommand(LLPointer callback): - mCallback(callback) - { - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); - } - - virtual ~AISCommand() - { - } - - void run_command() - { - mCommandFunc(); - } - - void setCommandFunc(command_func_type command_func) - { - mCommandFunc = command_func; - } - - // Need to do command-specific parsing to get an id here. May or - // may not need to bother, since most LLInventoryCallbacks do - // their work in the destructor. - virtual bool getResponseUUID(const LLSD& content, LLUUID& id) - { - return false; - } - - /* virtual */ void 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); - - if (mCallback) - { - LLUUID item_id; // will default to null if parse fails. - getResponseUUID(content,item_id); - mCallback->fire(item_id); - } - } - - /*virtual*/ void httpFailure() + LLPointer obj = gInventory.getItem(item_id); + LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; + if(obj) { - const LLSD& content = getContent(); - S32 status = getStatus(); - const std::string& reason = getReason(); - const LLSD& headers = getResponseHeaders(); - if (!content.isMap()) - { - LL_DEBUGS("Inventory") << "Malformed response contents " << content - << " status " << status << " reason " << reason << llendl; - } - else - { - LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content) - << " status " << status << " reason " << reason << llendl; - } - mRetryPolicy->onFailure(status, headers); - F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(seconds_to_wait)) + std::string cap; + if (AISCommand::getCap(cap)) { - doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait); + LLPointer cmd_ptr = new UpdateItemCommand(item_id, updates, cb); + cmd_ptr->run_command(); } - else + else // no cap { - // Command func holds a reference to self, need to release it - // after a success or final failure. - setCommandFunc(no_op); - } - } + 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, obj->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + obj->packUpdateMessage(msg, updates); + gAgent.sendReliableMessage(); - static bool getCap(std::string& cap) - { - if (gAgent.getRegion()) - { - cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); - } - if (!cap.empty()) - { - return true; + gInventory.onItemUpdated(item_id, updates); + if (cb) + { + cb->fire(item_id); + } } - return false; } +} -private: - command_func_type mCommandFunc; - LLPointer mRetryPolicy; - LLPointer mCallback; -}; - -class RemoveItemCommand: public AISCommand +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer cb) { -public: - RemoveItemCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) + LLPointer obj = gInventory.getCategory(cat_id); + LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; + if(obj) { - std::string cap; - if (!getCap(cap)) + if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())) { - llwarns << "No cap found" << llendl; + LLNotificationsUtil::add("CannotModifyProtectedCategories"); return; } - std::string url = cap + std::string("/item/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -}; -class RemoveCategoryCommand: public AISCommand -{ -public: - RemoveCategoryCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) + //std::string cap; + // FIXME - restore this once the back-end work has been done. + if (0) // if (AISCommand::getCap(cap)) { - llwarns << "No cap found" << llendl; - return; + LLPointer cmd_ptr = new UpdateCategoryCommand(cat_id, updates, cb); + cmd_ptr->run_command(); } - std::string url = cap + std::string("/category/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -}; - -class PurgeDescendentsCommand: public AISCommand -{ -public: - PurgeDescendentsCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) + else // no cap { - llwarns << "No cap found" << llendl; - return; + 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); + obj->packUpdateMessage(msg, updates); + gAgent.sendReliableMessage(); + + gInventory.onCategoryUpdated(cat_id, updates); + if (cb) + { + cb->fire(cat_id); + } } - std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); } -}; +} void remove_inventory_item( const LLUUID& item_id, diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 4e24dc87d1..c52b0c2d9d 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -139,6 +139,8 @@ public: //void updateAssetOnServer() const; virtual void packMessage(LLMessageSystem* msg) const; + // Contents of updates will take precedence over fields of item where they differ. + void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const; virtual void setTransactionID(const LLTransactionID& transaction_id); struct comparePointers { @@ -224,6 +226,8 @@ public: void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); + void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const; + private: friend class LLInventoryModel; void localizeName(); // intended to be called from the LLInventoryModel @@ -363,6 +367,16 @@ void move_inventory_item( const std::string& new_name, LLPointer cb); +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer cb); + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer cb); + void remove_inventory_item( const LLUUID& item_id, LLPointer cb); -- cgit v1.3 From 34d2cd03765b6b9b582035a933f4ec11fb262ff4 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 24 May 2013 15:51:33 -0400 Subject: SH-4207 WIP - use item updates with callback when updating link descriptions. Reworked updateAppearanceFromCOF() cof-validation stages. --- indra/llinventory/llinventory.cpp | 9 +++- indra/llinventory/llinventory.h | 1 + indra/newview/llappearancemgr.cpp | 96 ++++++++++++++++++++----------------- indra/newview/llappearancemgr.h | 12 +++-- indra/newview/llinventorymodel.cpp | 51 ++++---------------- indra/newview/llinventorymodel.h | 2 +- indra/newview/llviewerinventory.cpp | 6 ++- 7 files changed, 82 insertions(+), 95 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 641532ec29..a529aa3af3 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -416,12 +416,17 @@ U32 LLInventoryItem::getCRC32() const return crc; } +// static +void LLInventoryItem::correctInventoryDescription(std::string& desc) +{ + LLStringUtil::replaceNonstandardASCII(desc, ' '); + LLStringUtil::replaceChar(desc, '|', ' '); +} void LLInventoryItem::setDescription(const std::string& d) { std::string new_desc(d); - LLStringUtil::replaceNonstandardASCII(new_desc, ' '); - LLStringUtil::replaceChar(new_desc, '|', ' '); + LLInventoryItem::correctInventoryDescription(new_desc); if( new_desc != mDescription ) { mDescription = new_desc; diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 17421b3f5e..cc474f3d4c 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -171,6 +171,7 @@ public: //-------------------------------------------------------------------- public: void setAssetUUID(const LLUUID& asset_id); + static void correctInventoryDescription(std::string& name); void setDescription(const std::string& new_desc); void setSaleInfo(const LLSaleInfo& sale_info); void setPermissions(const LLPermissions& perm); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 14eed6e1df..83ad06a3c7 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -422,10 +422,12 @@ public: }; LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering, - bool enforce_item_restrictions): + bool enforce_item_restrictions, + bool enforce_ordering): mFireCount(0), mUpdateBaseOrder(update_base_outfit_ordering), - mEnforceItemRestrictions(enforce_item_restrictions) + mEnforceItemRestrictions(enforce_item_restrictions), + mEnforceOrdering(enforce_ordering) { selfStartPhase("update_appearance_on_destroy"); } @@ -449,7 +451,7 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder, mEnforceItemRestrictions); + LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder, mEnforceItemRestrictions, mEnforceOrdering); } } @@ -1918,8 +1920,22 @@ void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, -1, items_to_kill); } +void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer cb) +{ + LLInventoryModel::item_array_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); + if (items_to_kill.size()>0) + { + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + removeAll(items_to_kill, cb); + return; + } +} + void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering, - bool enforce_item_restrictions) + bool enforce_item_restrictions, + bool enforce_ordering) { if (mIsInUpdateAppearanceFromCOF) { @@ -1927,35 +1943,37 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering, return; } - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - selfStartPhase("update_appearance_from_cof"); - LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; if (enforce_item_restrictions) { - LLInventoryModel::item_array_t items_to_kill; - findAllExcessOrDuplicateItems(getCOF(), items_to_kill); - if (items_to_kill.size()>0) - { - // The point here is just to call - // updateAppearanceFromCOF() again after excess items - // have been removed. That time we will set - // enforce_item_restrictions to false so we don't get - // caught in a perpetual loop. - LLPointer cb( - new LLUpdateAppearanceOnDestroy(update_base_outfit_ordering, false)); - - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - removeAll(items_to_kill, cb); - return; - } + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer cb( + new LLUpdateAppearanceOnDestroy(update_base_outfit_ordering, false, enforce_ordering)); + enforceCOFItemRestrictions(cb); + return; } - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); + if (enforce_ordering) + { + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) + + // As with enforce_item_restrictions handling above, we want + // to wait for the update callbacks, then (finally!) call + // updateAppearanceFromCOF() with no additional COF munging needed. + LLPointer cb( + new LLUpdateAppearanceOnDestroy(false, false, false)); + updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering, cb); + return; + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + selfStartPhase("update_appearance_from_cof"); // update dirty flag to see if the state of the COF matches // the saved outfit stored as a folder link @@ -1966,11 +1984,6 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering, { requestServerAppearanceUpdate(); } - // DRANO really should wait for the appearance message to set this. - // verify that deleting this line doesn't break anything. - //gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()); - - //dumpCat(getCOF(),"COF, start"); LLUUID current_outfit_id = getCOF(); @@ -2821,7 +2834,9 @@ struct WearablesOrderComparator U32 mControlSize; }; -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, + bool update_base_outfit_ordering, + LLPointer cb) { if (cat_id.isNull()) { @@ -2831,7 +2846,7 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base const LLUUID base_outfit_id = getBaseOutfitUUID(); if (base_outfit_id.notNull()) { - updateClothingOrderingInfo(base_outfit_id,false); + updateClothingOrderingInfo(base_outfit_id,false,cb); } } } @@ -2843,7 +2858,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); divvyWearablesByType(wear_items, items_by_type); - bool inventory_changed = false; for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) { @@ -2862,17 +2876,11 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base std::string new_order_str = build_order_string((LLWearableType::EType)type, i); if (new_order_str == item->getActualDescription()) continue; - item->setDescription(new_order_str); - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); - - inventory_changed = true; + LLSD updates; + updates["desc"] = new_order_str; + update_inventory_item(item->getUUID(),updates,cb); } } - - //*TODO do we really need to notify observers? - if (inventory_changed) gInventory.notifyObservers(); } class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 2cc76c4b4c..246401ae85 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -50,7 +50,8 @@ public: typedef std::vector wearables_by_type_t; void updateAppearanceFromCOF(bool update_base_outfit_ordering = false, - bool enforce_item_restrictions = true); + bool enforce_item_restrictions = true, + bool enforce_ordering = true); bool needToSaveCOF(); void updateCOF(const LLUUID& category, bool append = false); void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); @@ -68,6 +69,7 @@ public: LLInventoryModel::item_array_t& items_to_kill); void findAllExcessOrDuplicateItems(const LLUUID& cat_id, LLInventoryModel::item_array_t& items_to_kill); + void enforceCOFItemRestrictions(LLPointer cb); // Copy all items and the src category itself. void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, @@ -190,7 +192,9 @@ public: //Check ordering information on wearables stored in links' descriptions and update if it is invalid // COF is processed if cat_id is not specified - void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); + void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, + bool update_base_outfit_ordering = false, + LLPointer cb = NULL); bool isOutfitLocked() { return mOutfitLocked; } @@ -263,7 +267,8 @@ class LLUpdateAppearanceOnDestroy: public LLInventoryCallback { public: LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false, - bool enforce_item_restrictions = true); + bool enforce_item_restrictions = true, + bool enforce_ordering = true); virtual ~LLUpdateAppearanceOnDestroy(); /* virtual */ void fire(const LLUUID& inv_item); @@ -271,6 +276,7 @@ private: U32 mFireCount; bool mUpdateBaseOrder; bool mEnforceItemRestrictions; + bool mEnforceOrdering; }; class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 06c614aeaa..38fa3c36e3 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1213,7 +1213,7 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS { changes["desc"] = update["desc"]; } - onItemUpdated(item_id,changes); + onItemUpdated(item_id,changes,true); } else if (cat) { @@ -1245,7 +1245,7 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS } -void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates) +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) { U32 mask = LLInventoryObserver::NONE; @@ -1275,6 +1275,12 @@ void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates) } mask |= LLInventoryObserver::INTERNAL; addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } gInventory.notifyObservers(); // do we want to be able to make this optional? } } @@ -1852,47 +1858,6 @@ void LLInventoryModel::accountForUpdate( } } - -/* -void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id) -{ - LLViewerInventoryCategory* cat = getCategory(category_id); - if(cat) - { - S32 version = cat->getVersion(); - if(LLViewerInventoryCategory::VERSION_UNKNOWN != version) - { - cat->setVersion(version + 1); - llinfos << "IncrementVersion: " << cat->getName() << " " - << cat->getVersion() << llendl; - } - else - { - llinfos << "Attempt to increment version when unknown: " - << category_id << llendl; - } - } - else - { - llinfos << "Attempt to increment category: " << category_id << llendl; - } -} -void LLInventoryModel::incrementCategorySetVersion( - const std::set& categories) -{ - if(!categories.empty()) - { - std::set::const_iterator it = categories.begin(); - std::set::const_iterator end = categories.end(); - for(; it != end; ++it) - { - incrementCategoryVersion(*it); - } - } -} -*/ - - LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( const LLUUID& cat_id) const { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 515c99c0b4..fd2481b531 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -340,7 +340,7 @@ public: void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); // Update model after an existing item gets updated on server. - void onItemUpdated(const LLUUID& item_id, const LLSD& updates); + void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version); // Update model after an existing category gets updated on server. void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 90fef3b5ed..62bcfd20a7 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -726,7 +726,9 @@ void LLViewerInventoryItem::packUpdateMessage(LLMessageSystem* msg, const LLSD& } if (updates.has("desc")) { - msg->addStringFast(_PREHASH_Description, updates["desc"].asString()); + std::string new_desc = updates["desc"].asString(); + LLInventoryItem::correctInventoryDescription(new_desc); + msg->addStringFast(_PREHASH_Description, new_desc); } else { @@ -1461,7 +1463,7 @@ void update_inventory_item( obj->packUpdateMessage(msg, updates); gAgent.sendReliableMessage(); - gInventory.onItemUpdated(item_id, updates); + gInventory.onItemUpdated(item_id, updates,false); if (cb) { cb->fire(item_id); -- cgit v1.3 From f7c9739fd9bb4355765ecff4b92e879b38302e49 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 5 Jun 2013 15:13:48 -0400 Subject: SH-3635 WIP - COF slammer works in AISv3 regions. Extensive rework of onAISUpdateReceived. --- indra/llcommon/llsdutil.cpp | 2 +- indra/llinventory/llinventory.cpp | 6 ++ indra/newview/llinventorymodel.cpp | 167 ++++++++++++++++++++++++++++++------ indra/newview/llinventorymodel.h | 2 +- indra/newview/llviewerinventory.cpp | 32 ++++++- 5 files changed, 179 insertions(+), 30 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 803417d368..562fd26658 100755 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -182,7 +182,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd) char* ll_pretty_print_sd(const LLSD& sd) { - const U32 bufferSize = 10 * 1024; + const U32 bufferSize = 100 * 1024; static char buffer[bufferSize]; std::ostringstream stream; //stream.rdbuf()->pubsetbuf(buffer, bufferSize); diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index a529aa3af3..77b837f8ac 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -50,6 +50,7 @@ static const std::string INV_DESC_LABEL("desc"); static const std::string INV_PERMISSIONS_LABEL("permissions"); static const std::string INV_SHADOW_ID_LABEL("shadow_id"); static const std::string INV_ASSET_ID_LABEL("asset_id"); +static const std::string INV_LINKED_ID_LABEL("linked_id"); static const std::string INV_SALE_INFO_LABEL("sale_info"); static const std::string INV_FLAGS_LABEL("flags"); static const std::string INV_CREATION_DATE_LABEL("created_at"); @@ -1109,6 +1110,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) { mAssetUUID = sd[w]; } + w = INV_LINKED_ID_LABEL; + if (sd.has(w)) + { + mAssetUUID = sd[w]; + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 38fa3c36e3..1a5e76183c 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1172,77 +1172,188 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS { LL_DEBUGS("Inventory") << "ais update " << context << ":" << ll_pretty_print_sd(update) << llendl; + // Track changes to descendent counts for accounting. + std::map cat_deltas; + typedef std::map > deferred_item_map_t; + deferred_item_map_t items_created; + deferred_item_map_t items_updated; + std::set objects_deleted; + + // parse _categories_removed -> objects_deleted uuid_vec_t cat_ids; parse_llsd_uuid_array(update,"_categories_removed",cat_ids); for (uuid_vec_t::const_iterator it = cat_ids.begin(); it != cat_ids.end(); ++it) { - onObjectDeletedFromServer(*it, false); + LLViewerInventoryCategory *cat = getCategory(*it); + cat_deltas[cat->getParentUUID()]--; + objects_deleted.insert(*it); } + // parse _categories_items_removed -> objects_deleted uuid_vec_t item_ids; parse_llsd_uuid_array(update,"_category_items_removed",item_ids); for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) { - onObjectDeletedFromServer(*it, false); + LLViewerInventoryItem *item = getItem(*it); + cat_deltas[item->getParentUUID()]--; + objects_deleted.insert(*it); } + // parse _broken_links_removed -> objects_deleted uuid_vec_t broken_link_ids; parse_llsd_uuid_array(update,"_broken_links_removed",broken_link_ids); for (uuid_vec_t::const_iterator it = broken_link_ids.begin(); it != broken_link_ids.end(); ++it) { - onObjectDeletedFromServer(*it, false); + LLViewerInventoryItem *item = getItem(*it); + cat_deltas[item->getParentUUID()]--; + objects_deleted.insert(*it); } - if (update.has("item_id")) + // parse _created_items + uuid_vec_t created_item_ids; + parse_llsd_uuid_array(update,"_created_items",created_item_ids); + + if (update.has("_embedded")) { - // item has been modified or possibly created (would be better if we could distinguish these cases directly) - LLUUID item_id = update["item_id"].asUUID(); - LLViewerInventoryItem *item = gInventory.getItem(item_id); - LLViewerInventoryCategory *cat = gInventory.getCategory(item_id); - if (item) + const LLSD& embedded = update["_embedded"]; + for(LLSD::map_const_iterator it = embedded.beginMap(), + end = embedded.endMap(); + it != end; ++it) { - LLSD changes; - if (update.has("name") && update["name"] != item->getName()) + const std::string& field = (*it).first; + + // parse created links + if (field == "link") { - changes["name"] = update["name"]; - } - if (update.has("desc") && update["desc"] != item->getActualDescription()) + const LLSD& links = embedded["link"]; + for(LLSD::map_const_iterator linkit = links.beginMap(), + linkend = links.endMap(); + linkit != linkend; ++linkit) + { + const LLUUID link_id((*linkit).first); + const LLSD& link_map = (*linkit).second; + uuid_vec_t::const_iterator pos = + std::find(created_item_ids.begin(), + created_item_ids.end(),link_id); + if (pos != created_item_ids.end()) + { + LLPointer new_link(new LLViewerInventoryItem); + BOOL rv = new_link->unpackMessage(link_map); + if (rv) + { + items_created[link_id] = new_link; + const LLUUID& parent_id = new_link->getParentUUID(); + cat_deltas[parent_id]++; + } + else + { + llwarns << "failed to unpack" << llendl; + } + } + else + { + LL_DEBUGS("Inventory") << "Ignoring link not in created items list " << link_id << llendl; + } + } + } + else { - changes["desc"] = update["desc"]; + llwarns << "unrecognized embedded field " << field << llendl; } - onItemUpdated(item_id,changes,true); } - else if (cat) + + } + + // Parse item update at the top level. + if (update.has("item_id")) + { + LLUUID item_id = update["item_id"].asUUID(); + LLPointer new_item(new LLViewerInventoryItem); + BOOL rv = new_item->unpackMessage(update); + if (rv) { - llerrs << "don't handle cat update yet" << llendl; + items_updated[item_id] = new_item; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + cat_deltas[new_item->getParentUUID()]; } else { - llerrs << "don't handle creation case yet" << llendl; + llerrs << "unpack failed" << llendl; } - } + // Do descendent/version accounting. + // Can remove this if/when we use the version info directly. + for (std::map::const_iterator catit = cat_deltas.begin(); + catit != cat_deltas.end(); ++catit) + { + const LLUUID cat_id(catit->first); + S32 delta = catit->second; + LLInventoryModel::LLCategoryUpdate up(cat_id, delta); + gInventory.accountForUpdate(up); + } + // TODO - how can we use this version info? Need to be sure all // changes are going through AIS first, or at least through // something with a reliable responder. -#if 0 const std::string& ucv = "_updated_category_versions"; if (update.has(ucv)) { for(LLSD::map_const_iterator it = update[ucv].beginMap(), end = update[ucv].endMap(); - it != end; ++it) + it != end; ++it) { const LLUUID id((*it).first); S32 version = (*it).second.asInteger(); + LLViewerInventoryCategory *cat = gInventory.getCategory(id); + if (cat->getVersion() != version) + { + llwarns << "Possible version mismatch, viewer " << cat->getVersion() + << " server " << version << llendl; + } } } -#endif + + // CREATE ITEMS + for (deferred_item_map_t::const_iterator create_it = items_created.begin(); + create_it != items_created.end(); ++create_it) + { + LLUUID item_id(create_it->first); + LLPointer new_item = create_it->second; + + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is create. + LL_DEBUGS("Inventory") << "created item " << item_id << llendl; + gInventory.updateItem(new_item); + } + // UPDATE ITEMS + for (deferred_item_map_t::const_iterator update_it = items_updated.begin(); + update_it != items_updated.end(); ++update_it) + { + LLUUID item_id(update_it->first); + LLPointer new_item = update_it->second; + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is update. + LL_DEBUGS("Inventory") << "updated item " << item_id << llendl; + gInventory.updateItem(new_item); + } + + // DELETE OBJECTS + for (std::set::const_iterator del_it = objects_deleted.begin(); + del_it != objects_deleted.end(); ++del_it) + { + LL_DEBUGS("Inventory") << "deleted item " << *del_it << llendl; + onObjectDeletedFromServer(*del_it, false, false); + } + } void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) @@ -1395,7 +1506,7 @@ void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bo // Update model after an item is confirmed as removed from // server. Works for categories or items. -void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links) +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version) { LLPointer obj = getObject(object_id); if(obj) @@ -1406,9 +1517,13 @@ void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool f onDescendentsPurgedFromServer(object_id, fix_broken_links); } + // From item/cat removeFromServer() - LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); - accountForUpdate(up); + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } // From purgeObject() LLPreview::hide(object_id); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index fd2481b531..a41a824906 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -334,7 +334,7 @@ public: // Update model after an item is confirmed as removed from // server. Works for categories or items. - void onObjectDeletedFromServer(const LLUUID& item_id, bool fix_broken_links = true); + void onObjectDeletedFromServer(const LLUUID& item_id, bool fix_broken_links = true, bool update_parent_version = true); // Update model after all descendents removed from server. void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index db8671d51b..0608c46051 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -493,6 +493,34 @@ private: LLSD mUpdates; }; +class SlamFolderCommand: public AISCommand +{ +public: + SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer callback): + mContents(contents), + AISCommand(callback) + { + std::string cap; + if (!getCap(cap)) + { + llwarns << "No cap found" << llendl; + return; + } + LLUUID tid; + tid.generate(); + std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); + llinfos << url << llendl; + 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); + } +private: + LLSD mContents; +}; + ///---------------------------------------------------------------------------- /// Class LLViewerInventoryItem ///---------------------------------------------------------------------------- @@ -1835,8 +1863,8 @@ void slam_inventory_folder(const LLUUID& folder_id, std::string cap; if (AISCommand::getCap(cap)) { - //LLPointer cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); - //cmd_ptr->run_command(); + LLPointer cmd_ptr = new SlamFolderCommand(folder_id, contents, cb); + cmd_ptr->run_command(); } else // no cap { -- cgit v1.3 From 6d46132ef5218cd17d8d201f16e5a7df4b1e39a6 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 10 Jun 2013 16:29:10 -0400 Subject: SH-4216 WIP - finished item/cat update and reorg of aisv3 code --- indra/llinventory/llinventory.cpp | 11 +- indra/llinventory/llinventory.h | 2 +- indra/newview/llaisapi.cpp | 1 + indra/newview/llviewerinventory.cpp | 351 +++--------------------------------- indra/newview/llviewerinventory.h | 9 +- 5 files changed, 38 insertions(+), 336 deletions(-) (limited to 'indra/llinventory/llinventory.cpp') diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 77b837f8ac..6336d02f22 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1049,11 +1049,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); -bool LLInventoryItem::fromLLSD(const LLSD& sd) +bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE); - mInventoryType = LLInventoryType::IT_NONE; - mAssetUUID.setNull(); + if (is_new) + { + // If we're adding LLSD to an existing object, need avoid + // clobbering these fields. + mInventoryType = LLInventoryType::IT_NONE; + mAssetUUID.setNull(); + } std::string w; w = INV_ITEM_ID_LABEL; diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index cc474f3d4c..b718f0f9b7 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -210,7 +210,7 @@ public: void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size); LLSD asLLSD() const; void asLLSD( LLSD& sd ) const; - bool fromLLSD(const LLSD& sd); + bool fromLLSD(const LLSD& sd, bool is_new = true); //-------------------------------------------------------------------- // Member Variables diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 6adf35efb8..393e5c0a68 100755 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -202,6 +202,7 @@ UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id, } std::string url = cap + std::string("/item/") + item_id.asString(); LL_DEBUGS("Inventory") << "url: " << url << llendl; + LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << llendl; LLCurl::ResponderPtr responder = this; LLSD headers; headers["Content-Type"] = "application/llsd+xml"; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 57d7d4fef6..55575764b9 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -259,271 +259,6 @@ public: }; LLInventoryHandler gInventoryHandler; -#if 0 // DELETE these when working in their new home - -///---------------------------------------------------------------------------- -/// Classes for AISv3 support. -///---------------------------------------------------------------------------- -class AISCommand: public LLHTTPClient::Responder -{ -public: - typedef boost::function command_func_type; - - AISCommand(LLPointer callback): - mCallback(callback) - { - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); - } - - virtual ~AISCommand() - { - } - - void run_command() - { - mCommandFunc(); - } - - void setCommandFunc(command_func_type command_func) - { - mCommandFunc = command_func; - } - - // Need to do command-specific parsing to get an id here. May or - // may not need to bother, since most LLInventoryCallbacks do - // their work in the destructor. - virtual bool getResponseUUID(const LLSD& content, LLUUID& id) - { - return false; - } - - /* virtual */ void 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); - - if (mCallback) - { - LLUUID item_id; // will default to null if parse fails. - getResponseUUID(content,item_id); - mCallback->fire(item_id); - } - } - - /*virtual*/ void httpFailure() - { - const LLSD& content = getContent(); - S32 status = getStatus(); - const std::string& reason = getReason(); - const LLSD& headers = getResponseHeaders(); - if (!content.isMap()) - { - LL_DEBUGS("Inventory") << "Malformed response contents " << content - << " status " << status << " reason " << reason << llendl; - } - else - { - LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content) - << " status " << status << " reason " << reason << llendl; - } - 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. - setCommandFunc(no_op); - } - } - - static bool getCap(std::string& cap) - { - if (gAgent.getRegion()) - { - cap = gAgent.getRegion()->getCapability("InventoryAPIv3"); - } - if (!cap.empty()) - { - return true; - } - return false; - } - -private: - command_func_type mCommandFunc; - LLPointer mRetryPolicy; - LLPointer mCallback; -}; - -class RemoveItemCommand: public AISCommand -{ -public: - RemoveItemCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - std::string url = cap + std::string("/item/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -}; - -class RemoveCategoryCommand: public AISCommand -{ -public: - RemoveCategoryCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - std::string url = cap + std::string("/category/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -}; - -class PurgeDescendentsCommand: public AISCommand -{ -public: - PurgeDescendentsCommand(const LLUUID& item_id, - LLPointer callback): - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -}; - -class UpdateItemCommand: public AISCommand -{ -public: - UpdateItemCommand(const LLUUID& item_id, - const LLSD& updates, - LLPointer callback): - mUpdates(updates), - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - std::string url = cap + std::string("/item/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -private: - LLSD mUpdates; -}; - -class UpdateCategoryCommand: public AISCommand -{ -public: - UpdateCategoryCommand(const LLUUID& item_id, - const LLSD& updates, - LLPointer callback): - mUpdates(updates), - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - std::string url = cap + std::string("/category/") + item_id.asString(); - LL_DEBUGS("Inventory") << "url: " << url << llendl; - 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); - } -private: - LLSD mUpdates; -}; - -class SlamFolderCommand: public AISCommand -{ -public: - SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer callback): - mContents(contents), - AISCommand(callback) - { - std::string cap; - if (!getCap(cap)) - { - llwarns << "No cap found" << llendl; - return; - } - LLUUID tid; - tid.generate(); - std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); - llinfos << url << llendl; - 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); - } -private: - LLSD mContents; -}; -#endif - ///---------------------------------------------------------------------------- /// Class LLViewerInventoryItem ///---------------------------------------------------------------------------- @@ -718,23 +453,9 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_ { mTransactionID = transaction_id; } -// virtual -void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const -{ - static const LLSD updates; - packUpdateMessage(msg,updates); -} -void LLViewerInventoryItem::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const +void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const { - for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it) - { - if ((it->first != "desc") && (it->first != "name")) - { - llerrs << "unhandled field: " << it->first << llendl; - } - } - msg->addUUIDFast(_PREHASH_ItemID, mUUID); msg->addUUIDFast(_PREHASH_FolderID, mParentUUID); mPermissions.packMessage(msg); @@ -745,26 +466,8 @@ void LLViewerInventoryItem::packUpdateMessage(LLMessageSystem* msg, const LLSD& msg->addS8Fast(_PREHASH_InvType, type); msg->addU32Fast(_PREHASH_Flags, mFlags); mSaleInfo.packMessage(msg); - if (updates.has("name")) - { - std::string new_name = updates["name"].asString(); - LLInventoryObject::correctInventoryName(new_name); - msg->addStringFast(_PREHASH_Name, new_name); - } - else - { - msg->addStringFast(_PREHASH_Name, mName); - } - if (updates.has("desc")) - { - std::string new_desc = updates["desc"].asString(); - LLInventoryItem::correctInventoryDescription(new_desc); - msg->addStringFast(_PREHASH_Description, new_desc); - } - else - { - msg->addStringFast(_PREHASH_Description, mDescription); - } + msg->addStringFast(_PREHASH_Name, mName); + msg->addStringFast(_PREHASH_Description, mDescription); msg->addS32Fast(_PREHASH_CreationDate, mCreationDate); U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); @@ -881,30 +584,13 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego } -void LLViewerInventoryCategory::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const +void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const { - for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it) - { - if (it->first != "name") - { - llerrs << "unhandled field: " << it->first << llendl; - } - } - msg->addUUIDFast(_PREHASH_FolderID, mUUID); msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); S8 type = static_cast(mPreferredType); msg->addS8Fast(_PREHASH_Type, type); - if (updates.has("name")) - { - std::string new_name = updates["name"].asString(); - LLInventoryObject::correctInventoryName(new_name); - msg->addStringFast(_PREHASH_Name, new_name); - } - else - { - msg->addStringFast(_PREHASH_Name, mName); - } + msg->addStringFast(_PREHASH_Name, mName); } void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const @@ -1475,10 +1161,16 @@ void update_inventory_item( LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; if(obj) { + LLPointer new_item(new LLViewerInventoryItem); + new_item->copyViewerItem(obj); + new_item->fromLLSD(updates,false); + std::string cap; if (AISCommand::getCap(cap)) { - LLPointer cmd_ptr = new UpdateItemCommand(item_id, updates, cb); + LLSD new_llsd; + new_item->asLLSD(new_llsd); + LLPointer cmd_ptr = new UpdateItemCommand(item_id, new_llsd, cb); cmd_ptr->run_command(); } else // no cap @@ -1488,13 +1180,15 @@ void update_inventory_item( msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, obj->getTransactionID()); + msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); msg->nextBlockFast(_PREHASH_InventoryData); msg->addU32Fast(_PREHASH_CallbackID, 0); - obj->packUpdateMessage(msg, updates); + new_item->packMessage(msg); gAgent.sendReliableMessage(); - gInventory.onItemUpdated(item_id, updates,true); + LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(new_item); if (cb) { cb->fire(item_id); @@ -1518,11 +1212,14 @@ void update_inventory_category( return; } + LLPointer new_cat = new LLViewerInventoryCategory(obj); + new_cat->fromLLSD(updates); //std::string cap; // FIXME - restore this once the back-end work has been done. if (0) // if (AISCommand::getCap(cap)) { - LLPointer cmd_ptr = new UpdateCategoryCommand(cat_id, updates, cb); + LLSD new_llsd = new_cat->asLLSD(); + LLPointer cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); cmd_ptr->run_command(); } else // no cap @@ -1533,10 +1230,12 @@ void update_inventory_category( msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_FolderData); - obj->packUpdateMessage(msg, updates); + new_cat->packMessage(msg); gAgent.sendReliableMessage(); - gInventory.onCategoryUpdated(cat_id, updates); + LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateCategory(new_cat); if (cb) { cb->fire(cat_id); diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 9af71dfc9c..032efd9542 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -122,7 +122,7 @@ public: virtual void updateServer(BOOL is_new) const; void fetchFromServer(void) const; - //virtual void packMessage(LLMessageSystem* msg) const; + virtual void packMessage(LLMessageSystem* msg) const; virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); virtual BOOL unpackMessage(LLSD item); virtual BOOL importFile(LLFILE* fp); @@ -138,9 +138,6 @@ public: void setComplete(BOOL complete) { mIsComplete = complete; } //void updateAssetOnServer() const; - virtual void packMessage(LLMessageSystem* msg) const; - // Contents of updates will take precedence over fields of item where they differ. - void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const; virtual void setTransactionID(const LLTransactionID& transaction_id); struct comparePointers { @@ -202,6 +199,8 @@ public: virtual void updateParentOnServer(BOOL restamp_children) const; virtual void updateServer(BOOL is_new) const; + virtual void packMessage(LLMessageSystem* msg) const; + const LLUUID& getOwnerID() const { return mOwnerID; } // Version handling @@ -226,8 +225,6 @@ public: void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); - void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const; - private: friend class LLInventoryModel; void localizeName(); // intended to be called from the LLInventoryModel -- cgit v1.3