diff options
| author | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2013-05-24 08:53:21 -0400 | 
|---|---|---|
| committer | Brad Payne (Vir Linden) <vir@lindenlab.com> | 2013-05-24 08:53:21 -0400 | 
| commit | 6c56c77ec575141963c5de8dfa228253fe175bc3 (patch) | |
| tree | 65ec3b7388af37390fe73ca4b3eb23d10ef92c3a /indra | |
| parent | b0303445f1af83057e4d27d763f7b860f20f0143 (diff) | |
SH-4027 WIP - initial implementation of item update via AIS.
Diffstat (limited to 'indra')
| -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); | 
