diff options
-rwxr-xr-x | indra/llinventory/llinventory.cpp | 2 | ||||
-rwxr-xr-x | indra/llinventory/llinventory.h | 4 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclient.cpp | 12 | ||||
-rwxr-xr-x | indra/llmessage/llhttpclient.h | 8 | ||||
-rwxr-xr-x[-rw-r--r--] | indra/llmessage/llhttpconstants.h | 37 | ||||
-rwxr-xr-x | indra/llmessage/llurlrequest.cpp | 11 | ||||
-rwxr-xr-x | indra/newview/llappearancemgr.cpp | 4 | ||||
-rwxr-xr-x | indra/newview/llinventorybridge.cpp | 10 | ||||
-rwxr-xr-x | indra/newview/llinventoryfunctions.cpp | 9 | ||||
-rwxr-xr-x | indra/newview/llinventorymodel.cpp | 93 | ||||
-rwxr-xr-x | indra/newview/llinventorymodel.h | 6 | ||||
-rwxr-xr-x | indra/newview/llviewerinventory.cpp | 510 | ||||
-rwxr-xr-x | indra/newview/llviewerinventory.h | 14 |
13 files changed, 523 insertions, 197 deletions
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 index 8cc3459654..aa947af414 100644..100755 --- 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<LLViewerInventoryItem> 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<LLViewerInventoryCategory> 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<LLViewerInventoryItem> 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<LLViewerInventoryCategory> 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 @@ -260,6 +260,240 @@ LLInventoryHandler gInventoryHandler; ///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- +class AISCommand: public LLHTTPClient::Responder +{ +public: + typedef boost::function<void()> command_func_type; + + AISCommand(LLPointer<LLInventoryCallback> 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<LLHTTPRetryPolicy> mRetryPolicy; + LLPointer<LLInventoryCallback> mCallback; +}; + +class RemoveItemCommand: public AISCommand +{ +public: + RemoveItemCommand(const LLUUID& item_id, + LLPointer<LLInventoryCallback> 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<LLInventoryCallback> 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<LLInventoryCallback> 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<LLInventoryCallback> 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<LLInventoryCallback> 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<S8>(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<LLInventoryCallback> cb) { -public: - typedef boost::function<void()> command_func_type; - - AISCommand(LLPointer<LLInventoryCallback> 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<LLViewerInventoryItem> 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<AISCommand> 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<LLHTTPRetryPolicy> mRetryPolicy; - LLPointer<LLInventoryCallback> mCallback; -}; - -class RemoveItemCommand: public AISCommand +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb) { -public: - RemoveItemCommand(const LLUUID& item_id, - LLPointer<LLInventoryCallback> callback): - AISCommand(callback) + LLPointer<LLViewerInventoryCategory> 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<LLInventoryCallback> 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<AISCommand> 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<LLInventoryCallback> 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<LLInventoryCallback> cb); +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb); + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer<LLInventoryCallback> cb); + void remove_inventory_item( const LLUUID& item_id, LLPointer<LLInventoryCallback> cb); |