Adding support for COPY methods to httpclient. Implementing viewer-side use of AISv3 COPY library folder operation. (SH-4304)
parent
d079f0dcdc
commit
a85fa3b10a
|
|
@ -631,6 +631,19 @@ void LLHTTPClient::move(
|
|||
request(url, HTTP_MOVE, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
// static
|
||||
void LLHTTPClient::copy(
|
||||
const std::string& url,
|
||||
const std::string& destination,
|
||||
ResponderPtr responder,
|
||||
const LLSD& hdrs,
|
||||
const F32 timeout)
|
||||
{
|
||||
LLSD headers = hdrs;
|
||||
headers[HTTP_OUT_HEADER_DESTINATION] = destination;
|
||||
request(url, HTTP_COPY, NULL, responder, timeout, headers);
|
||||
}
|
||||
|
||||
|
||||
void LLHTTPClient::setPump(LLPumpIO& pump)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public:
|
|||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
///< sends a DELETE method, but we can't call it delete in c++
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send a MOVE webdav method
|
||||
*
|
||||
|
|
@ -136,6 +136,22 @@ public:
|
|||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
/**
|
||||
* @brief Send a COPY webdav method
|
||||
*
|
||||
* @param url The complete serialized (and escaped) url to get.
|
||||
* @param destination The complete serialized destination url.
|
||||
* @param responder The responder that will handle the result.
|
||||
* @param headers A map of key:value headers to pass to the request
|
||||
* @param timeout The number of seconds to give the server to respond.
|
||||
*/
|
||||
static void copy(
|
||||
const std::string& url,
|
||||
const std::string& destination,
|
||||
ResponderPtr responder,
|
||||
const LLSD& headers = LLSD(),
|
||||
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
|
||||
|
||||
//@}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ const std::string HTTP_VERB_POST("POST");
|
|||
const std::string HTTP_VERB_DELETE("DELETE");
|
||||
const std::string HTTP_VERB_MOVE("MOVE");
|
||||
const std::string HTTP_VERB_OPTIONS("OPTIONS");
|
||||
const std::string HTTP_VERB_PATCH("PATCH");
|
||||
const std::string HTTP_VERB_COPY("COPY");
|
||||
|
||||
const std::string& httpMethodAsVerb(EHTTPMethod method)
|
||||
{
|
||||
|
|
@ -145,7 +147,9 @@ const std::string& httpMethodAsVerb(EHTTPMethod method)
|
|||
HTTP_VERB_POST,
|
||||
HTTP_VERB_DELETE,
|
||||
HTTP_VERB_MOVE,
|
||||
HTTP_VERB_OPTIONS
|
||||
HTTP_VERB_OPTIONS,
|
||||
HTTP_VERB_PATCH,
|
||||
HTTP_VERB_COPY
|
||||
};
|
||||
if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ enum EHTTPMethod
|
|||
HTTP_MOVE, // Caller will need to set 'Destination' header
|
||||
HTTP_OPTIONS,
|
||||
HTTP_PATCH,
|
||||
HTTP_COPY,
|
||||
HTTP_METHOD_COUNT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -516,13 +516,19 @@ bool LLURLRequest::configure()
|
|||
break;
|
||||
|
||||
case HTTP_DELETE:
|
||||
// Set the handle for an http post
|
||||
// Set the handle for an http delete
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_COPY:
|
||||
// Set the handle for an http copy
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY");
|
||||
rv = true;
|
||||
break;
|
||||
|
||||
case HTTP_MOVE:
|
||||
// Set the handle for an http post
|
||||
// Set the handle for an http move
|
||||
mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");
|
||||
// *NOTE: should we check for the Destination header?
|
||||
rv = true;
|
||||
|
|
|
|||
|
|
@ -40,14 +40,25 @@
|
|||
|
||||
// AISCommand - base class for retry-able HTTP requests using the AISv3 cap.
|
||||
AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback):
|
||||
mCommandFunc(NULL),
|
||||
mCallback(callback)
|
||||
{
|
||||
mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
|
||||
}
|
||||
|
||||
void AISCommand::run_command()
|
||||
bool AISCommand::run_command()
|
||||
{
|
||||
mCommandFunc();
|
||||
if (NULL == mCommandFunc)
|
||||
{
|
||||
// This may happen if a command failed to initiate itself.
|
||||
LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCommandFunc();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AISCommand::setCommandFunc(command_func_type command_func)
|
||||
|
|
@ -80,9 +91,9 @@ void AISCommand::httpSuccess()
|
|||
|
||||
if (mCallback)
|
||||
{
|
||||
LLUUID item_id; // will default to null if parse fails.
|
||||
getResponseUUID(content,item_id);
|
||||
mCallback->fire(item_id);
|
||||
LLUUID id; // will default to null if parse fails.
|
||||
getResponseUUID(content,id);
|
||||
mCallback->fire(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,12 +107,12 @@ void AISCommand::httpFailure()
|
|||
if (!content.isMap())
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Malformed response contents " << content
|
||||
<< " status " << status << " reason " << reason << llendl;
|
||||
<< " status " << status << " reason " << reason << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content)
|
||||
<< " status " << status << " reason " << reason << llendl;
|
||||
<< " status " << status << " reason " << reason << LL_ENDL;
|
||||
}
|
||||
mRetryPolicy->onFailure(status, headers);
|
||||
F32 seconds_to_wait;
|
||||
|
|
@ -113,12 +124,23 @@ void AISCommand::httpFailure()
|
|||
{
|
||||
// Command func holds a reference to self, need to release it
|
||||
// after a success or final failure.
|
||||
// *TODO: Notify user? This seems bad.
|
||||
setCommandFunc(no_op);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
bool AISCommand::getCap(std::string& cap)
|
||||
bool AISCommand::isAPIAvailable()
|
||||
{
|
||||
if (gAgent.getRegion())
|
||||
{
|
||||
return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
bool AISCommand::getInvCap(std::string& cap)
|
||||
{
|
||||
if (gAgent.getRegion())
|
||||
{
|
||||
|
|
@ -131,18 +153,39 @@ bool AISCommand::getCap(std::string& cap)
|
|||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
bool AISCommand::getLibCap(std::string& cap)
|
||||
{
|
||||
if (gAgent.getRegion())
|
||||
{
|
||||
cap = gAgent.getRegion()->getCapability("LibraryAPIv3");
|
||||
}
|
||||
if (!cap.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
void AISCommand::getCapabilityNames(LLSD& capabilityNames)
|
||||
{
|
||||
capabilityNames.append("InventoryAPIv3");
|
||||
capabilityNames.append("LibraryAPIv3");
|
||||
}
|
||||
|
||||
RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id,
|
||||
LLPointer<LLInventoryCallback> callback):
|
||||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
std::string url = cap + std::string("/item/") + item_id.asString();
|
||||
LL_DEBUGS("Inventory") << "url: " << url << llendl;
|
||||
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
|
||||
LLHTTPClient::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||
|
|
@ -155,13 +198,13 @@ RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,
|
|||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
std::string url = cap + std::string("/category/") + item_id.asString();
|
||||
LL_DEBUGS("Inventory") << "url: " << url << llendl;
|
||||
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
|
||||
LLHTTPClient::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||
|
|
@ -174,13 +217,13 @@ PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,
|
|||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
|
||||
LL_DEBUGS("Inventory") << "url: " << url << llendl;
|
||||
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
|
||||
LLCurl::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||
|
|
@ -195,14 +238,14 @@ UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,
|
|||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
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;
|
||||
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
|
||||
LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL;
|
||||
LLCurl::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
headers["Content-Type"] = "application/llsd+xml";
|
||||
|
|
@ -218,13 +261,13 @@ UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& item_id,
|
|||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
std::string url = cap + std::string("/category/") + item_id.asString();
|
||||
LL_DEBUGS("Inventory") << "url: " << url << llendl;
|
||||
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
|
||||
LLCurl::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
headers["Content-Type"] = "application/llsd+xml";
|
||||
|
|
@ -238,7 +281,7 @@ SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& conten
|
|||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getCap(cap))
|
||||
if (!getInvCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
|
|
@ -255,92 +298,106 @@ SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& conten
|
|||
setCommandFunc(cmd);
|
||||
}
|
||||
|
||||
CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id,
|
||||
const LLUUID& dest_id,
|
||||
LLPointer<LLInventoryCallback> callback):
|
||||
AISCommand(callback)
|
||||
{
|
||||
std::string cap;
|
||||
if (!getLibCap(cap))
|
||||
{
|
||||
llwarns << "No cap found" << llendl;
|
||||
return;
|
||||
}
|
||||
LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL;
|
||||
LLUUID tid;
|
||||
tid.generate();
|
||||
std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString();
|
||||
llinfos << url << llendl;
|
||||
LLCurl::ResponderPtr responder = this;
|
||||
LLSD headers;
|
||||
F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||
command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout);
|
||||
setCommandFunc(cmd);
|
||||
}
|
||||
|
||||
bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id)
|
||||
{
|
||||
if (content.has("category_id"))
|
||||
{
|
||||
id = content["category_id"];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AISUpdate::AISUpdate(const LLSD& update)
|
||||
{
|
||||
parseUpdate(update);
|
||||
}
|
||||
|
||||
void AISUpdate::clearParseResults()
|
||||
{
|
||||
mCatDescendentDeltas.clear();
|
||||
mCatDescendentsKnown.clear();
|
||||
mCatVersionsUpdated.clear();
|
||||
mItemsCreated.clear();
|
||||
mItemsUpdated.clear();
|
||||
mCategoriesCreated.clear();
|
||||
mCategoriesUpdated.clear();
|
||||
mObjectsDeletedIds.clear();
|
||||
mItemIds.clear();
|
||||
mCategoryIds.clear();
|
||||
}
|
||||
|
||||
void AISUpdate::parseUpdate(const LLSD& update)
|
||||
{
|
||||
// parse _categories_removed -> mObjectsDeleted
|
||||
uuid_vec_t cat_ids;
|
||||
clearParseResults();
|
||||
parseMeta(update);
|
||||
parseContent(update);
|
||||
}
|
||||
|
||||
void AISUpdate::parseMeta(const LLSD& update)
|
||||
{
|
||||
// parse _categories_removed -> mObjectsDeletedIds
|
||||
uuid_list_t cat_ids;
|
||||
parseUUIDArray(update,"_categories_removed",cat_ids);
|
||||
for (uuid_vec_t::const_iterator it = cat_ids.begin();
|
||||
for (uuid_list_t::const_iterator it = cat_ids.begin();
|
||||
it != cat_ids.end(); ++it)
|
||||
{
|
||||
LLViewerInventoryCategory *cat = gInventory.getCategory(*it);
|
||||
mCatDeltas[cat->getParentUUID()]--;
|
||||
mObjectsDeleted.insert(*it);
|
||||
mCatDescendentDeltas[cat->getParentUUID()]--;
|
||||
mObjectsDeletedIds.insert(*it);
|
||||
}
|
||||
|
||||
// parse _categories_items_removed -> mObjectsDeleted
|
||||
uuid_vec_t item_ids;
|
||||
// parse _categories_items_removed -> mObjectsDeletedIds
|
||||
uuid_list_t item_ids;
|
||||
parseUUIDArray(update,"_category_items_removed",item_ids);
|
||||
for (uuid_vec_t::const_iterator it = item_ids.begin();
|
||||
parseUUIDArray(update,"_removed_items",item_ids);
|
||||
for (uuid_list_t::const_iterator it = item_ids.begin();
|
||||
it != item_ids.end(); ++it)
|
||||
{
|
||||
LLViewerInventoryItem *item = gInventory.getItem(*it);
|
||||
mCatDeltas[item->getParentUUID()]--;
|
||||
mObjectsDeleted.insert(*it);
|
||||
mCatDescendentDeltas[item->getParentUUID()]--;
|
||||
mObjectsDeletedIds.insert(*it);
|
||||
}
|
||||
|
||||
// parse _broken_links_removed -> mObjectsDeleted
|
||||
uuid_vec_t broken_link_ids;
|
||||
// parse _broken_links_removed -> mObjectsDeletedIds
|
||||
uuid_list_t broken_link_ids;
|
||||
parseUUIDArray(update,"_broken_links_removed",broken_link_ids);
|
||||
for (uuid_vec_t::const_iterator it = broken_link_ids.begin();
|
||||
for (uuid_list_t::const_iterator it = broken_link_ids.begin();
|
||||
it != broken_link_ids.end(); ++it)
|
||||
{
|
||||
LLViewerInventoryItem *item = gInventory.getItem(*it);
|
||||
mCatDeltas[item->getParentUUID()]--;
|
||||
mObjectsDeleted.insert(*it);
|
||||
mCatDescendentDeltas[item->getParentUUID()]--;
|
||||
mObjectsDeletedIds.insert(*it);
|
||||
}
|
||||
|
||||
// parse _created_items
|
||||
parseUUIDArray(update,"_created_items",mItemsCreatedIds);
|
||||
parseUUIDArray(update,"_created_items",mItemIds);
|
||||
|
||||
if (update.has("_embedded"))
|
||||
{
|
||||
const LLSD& embedded = update["_embedded"];
|
||||
for(LLSD::map_const_iterator it = embedded.beginMap(),
|
||||
end = embedded.endMap();
|
||||
it != end; ++it)
|
||||
{
|
||||
const std::string& field = (*it).first;
|
||||
|
||||
// parse created links
|
||||
if (field == "link")
|
||||
{
|
||||
const LLSD& links = embedded["link"];
|
||||
parseCreatedLinks(links);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse item update at the top level.
|
||||
if (update.has("item_id"))
|
||||
{
|
||||
LLUUID item_id = update["item_id"].asUUID();
|
||||
LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
|
||||
LLViewerInventoryItem *curr_item = gInventory.getItem(item_id);
|
||||
if (curr_item)
|
||||
{
|
||||
// Default to current values where not provided.
|
||||
new_item->copyViewerItem(curr_item);
|
||||
}
|
||||
BOOL rv = new_item->unpackMessage(update);
|
||||
if (rv)
|
||||
{
|
||||
mItemsUpdated[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.
|
||||
mCatDeltas[new_item->getParentUUID()];
|
||||
}
|
||||
else
|
||||
{
|
||||
llerrs << "unpack failed" << llendl;
|
||||
}
|
||||
}
|
||||
// parse _created_categories
|
||||
parseUUIDArray(update,"_created_categories",mCategoryIds);
|
||||
|
||||
// Parse updated category versions.
|
||||
const std::string& ucv = "_updated_category_versions";
|
||||
|
|
@ -352,49 +409,224 @@ void AISUpdate::parseUpdate(const LLSD& update)
|
|||
{
|
||||
const LLUUID id((*it).first);
|
||||
S32 version = (*it).second.asInteger();
|
||||
mCatVersions[id] = version;
|
||||
mCatVersionsUpdated[id] = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids)
|
||||
void AISUpdate::parseContent(const LLSD& update)
|
||||
{
|
||||
if (update.has("linked_id"))
|
||||
{
|
||||
parseLink(update);
|
||||
}
|
||||
else if (update.has("item_id"))
|
||||
{
|
||||
parseItem(update);
|
||||
}
|
||||
|
||||
if (update.has("category_id"))
|
||||
{
|
||||
parseCategory(update);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (update.has("_embedded"))
|
||||
{
|
||||
parseEmbedded(update["_embedded"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseItem(const LLSD& item_map)
|
||||
{
|
||||
LLUUID item_id = item_map["item_id"].asUUID();
|
||||
LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
|
||||
LLViewerInventoryItem *curr_item = gInventory.getItem(item_id);
|
||||
if (curr_item)
|
||||
{
|
||||
// Default to current values where not provided.
|
||||
new_item->copyViewerItem(curr_item);
|
||||
}
|
||||
BOOL rv = new_item->unpackMessage(item_map);
|
||||
if (rv)
|
||||
{
|
||||
if (curr_item)
|
||||
{
|
||||
mItemsUpdated[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.
|
||||
mCatDescendentDeltas[new_item->getParentUUID()];
|
||||
}
|
||||
else
|
||||
{
|
||||
mItemsCreated[item_id] = new_item;
|
||||
mCatDescendentDeltas[new_item->getParentUUID()]++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// *TODO: Wow, harsh. Should we just complain and get out?
|
||||
llerrs << "unpack failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseLink(const LLSD& link_map)
|
||||
{
|
||||
LLUUID item_id = link_map["item_id"].asUUID();
|
||||
LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
|
||||
LLViewerInventoryItem *curr_link = gInventory.getItem(item_id);
|
||||
if (curr_link)
|
||||
{
|
||||
// Default to current values where not provided.
|
||||
new_link->copyViewerItem(curr_link);
|
||||
}
|
||||
BOOL rv = new_link->unpackMessage(link_map);
|
||||
if (rv)
|
||||
{
|
||||
const LLUUID& parent_id = new_link->getParentUUID();
|
||||
if (curr_link)
|
||||
{
|
||||
mItemsUpdated[item_id] = new_link;
|
||||
// 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.
|
||||
mCatDescendentDeltas[parent_id];
|
||||
}
|
||||
else
|
||||
{
|
||||
LLPermissions default_perms;
|
||||
default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null);
|
||||
default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE);
|
||||
new_link->setPermissions(default_perms);
|
||||
LLSaleInfo default_sale_info;
|
||||
new_link->setSaleInfo(default_sale_info);
|
||||
//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL;
|
||||
mItemsCreated[item_id] = new_link;
|
||||
mCatDescendentDeltas[parent_id]++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// *TODO: Wow, harsh. Should we just complain and get out?
|
||||
llerrs << "unpack failed" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AISUpdate::parseCategory(const LLSD& category_map)
|
||||
{
|
||||
LLUUID category_id = category_map["category_id"].asUUID();
|
||||
|
||||
// Check descendent count first, as it may be needed
|
||||
// to populate newly created categories
|
||||
if (category_map.has("_embedded"))
|
||||
{
|
||||
parseDescendentCount(category_id, category_map["_embedded"]);
|
||||
}
|
||||
|
||||
LLPointer<LLViewerInventoryCategory> new_cat(new LLViewerInventoryCategory(category_id));
|
||||
LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id);
|
||||
if (curr_cat)
|
||||
{
|
||||
// Default to current values where not provided.
|
||||
new_cat->copyViewerCategory(curr_cat);
|
||||
}
|
||||
BOOL rv = new_cat->unpackMessage(category_map);
|
||||
// *NOTE: unpackMessage does not unpack version or descendent count.
|
||||
//if (category_map.has("version"))
|
||||
//{
|
||||
// mCatVersionsUpdated[category_id] = category_map["version"].asInteger();
|
||||
//}
|
||||
if (rv)
|
||||
{
|
||||
if (curr_cat)
|
||||
{
|
||||
mCategoriesUpdated[category_id] = new_cat;
|
||||
// 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.
|
||||
mCatDescendentDeltas[new_cat->getParentUUID()];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set version/descendents for newly created categories.
|
||||
if (category_map.has("version"))
|
||||
{
|
||||
S32 version = category_map["version"].asInteger();
|
||||
LL_DEBUGS("Inventory") << "Setting version to " << version
|
||||
<< " for new category " << category_id << LL_ENDL;
|
||||
new_cat->setVersion(version);
|
||||
}
|
||||
uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id);
|
||||
if (mCatDescendentsKnown.end() != lookup_it)
|
||||
{
|
||||
S32 descendent_count = lookup_it->second;
|
||||
LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count
|
||||
<< " for new category " << category_id << LL_ENDL;
|
||||
new_cat->setDescendentCount(descendent_count);
|
||||
}
|
||||
mCategoriesCreated[category_id] = new_cat;
|
||||
mCatDescendentDeltas[new_cat->getParentUUID()]++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// *TODO: Wow, harsh. Should we just complain and get out?
|
||||
llerrs << "unpack failed" << llendl;
|
||||
}
|
||||
|
||||
// Check for more embedded content.
|
||||
if (category_map.has("_embedded"))
|
||||
{
|
||||
parseEmbedded(category_map["_embedded"]);
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded)
|
||||
{
|
||||
// We can only determine true descendent count if this contains all descendent types.
|
||||
if (embedded.has("category") &&
|
||||
embedded.has("link") &&
|
||||
embedded.has("item"))
|
||||
{
|
||||
mCatDescendentsKnown[category_id] = embedded["category"].size();
|
||||
mCatDescendentsKnown[category_id] += embedded["link"].size();
|
||||
mCatDescendentsKnown[category_id] += embedded["item"].size();
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseEmbedded(const LLSD& embedded)
|
||||
{
|
||||
if (embedded.has("link"))
|
||||
{
|
||||
parseEmbeddedLinks(embedded["link"]);
|
||||
}
|
||||
if (embedded.has("item"))
|
||||
{
|
||||
parseEmbeddedItems(embedded["item"]);
|
||||
}
|
||||
if (embedded.has("category"))
|
||||
{
|
||||
parseEmbeddedCategories(embedded["category"]);
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids)
|
||||
{
|
||||
ids.clear();
|
||||
if (content.has(name))
|
||||
{
|
||||
for(LLSD::array_const_iterator it = content[name].beginArray(),
|
||||
end = content[name].endArray();
|
||||
it != end; ++it)
|
||||
{
|
||||
ids.push_back((*it).asUUID());
|
||||
ids.insert((*it).asUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseLink(const LLUUID& link_id, const LLSD& link_map)
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem);
|
||||
BOOL rv = new_link->unpackMessage(link_map);
|
||||
if (rv)
|
||||
{
|
||||
LLPermissions default_perms;
|
||||
default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null);
|
||||
default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE);
|
||||
new_link->setPermissions(default_perms);
|
||||
LLSaleInfo default_sale_info;
|
||||
new_link->setSaleInfo(default_sale_info);
|
||||
//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << llendl;
|
||||
mItemsCreated[link_id] = new_link;
|
||||
const LLUUID& parent_id = new_link->getParentUUID();
|
||||
mCatDeltas[parent_id]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "failed to parse" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseCreatedLinks(const LLSD& links)
|
||||
void AISUpdate::parseEmbeddedLinks(const LLSD& links)
|
||||
{
|
||||
for(LLSD::map_const_iterator linkit = links.beginMap(),
|
||||
linkend = links.endMap();
|
||||
|
|
@ -402,47 +634,134 @@ void AISUpdate::parseCreatedLinks(const LLSD& links)
|
|||
{
|
||||
const LLUUID link_id((*linkit).first);
|
||||
const LLSD& link_map = (*linkit).second;
|
||||
uuid_vec_t::const_iterator pos =
|
||||
std::find(mItemsCreatedIds.begin(),
|
||||
mItemsCreatedIds.end(),link_id);
|
||||
if (pos != mItemsCreatedIds.end())
|
||||
if (mItemIds.end() == mItemIds.find(link_id))
|
||||
{
|
||||
parseLink(link_id,link_map);
|
||||
LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Ignoring link not in created items list " << link_id << llendl;
|
||||
parseLink(link_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseEmbeddedItems(const LLSD& items)
|
||||
{
|
||||
// Special case: this may be a single item (_embedded in a link)
|
||||
if (items.has("item_id"))
|
||||
{
|
||||
if (mItemIds.end() != mItemIds.find(items["item_id"].asUUID()))
|
||||
{
|
||||
parseContent(items);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(LLSD::map_const_iterator itemit = items.beginMap(),
|
||||
itemend = items.endMap();
|
||||
itemit != itemend; ++itemit)
|
||||
{
|
||||
const LLUUID item_id((*itemit).first);
|
||||
const LLSD& item_map = (*itemit).second;
|
||||
if (mItemIds.end() == mItemIds.find(item_id))
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
parseItem(item_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
|
||||
{
|
||||
for(LLSD::map_const_iterator categoryit = categories.beginMap(),
|
||||
categoryend = categories.endMap();
|
||||
categoryit != categoryend; ++categoryit)
|
||||
{
|
||||
const LLUUID category_id((*categoryit).first);
|
||||
const LLSD& category_map = (*categoryit).second;
|
||||
if (mCategoryIds.end() == mCategoryIds.find(category_id))
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
parseCategory(category_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISUpdate::doUpdate()
|
||||
{
|
||||
// Do descendent/version accounting.
|
||||
// Can remove this if/when we use the version info directly.
|
||||
for (std::map<LLUUID,S32>::const_iterator catit = mCatDeltas.begin();
|
||||
catit != mCatDeltas.end(); ++catit)
|
||||
// Do version/descendent accounting.
|
||||
for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin();
|
||||
catit != mCatDescendentDeltas.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.
|
||||
for (uuid_int_map_t::iterator ucv_it = mCatVersions.begin();
|
||||
ucv_it != mCatVersions.end(); ++ucv_it)
|
||||
{
|
||||
const LLUUID id = ucv_it->first;
|
||||
S32 version = ucv_it->second;
|
||||
LLViewerInventoryCategory *cat = gInventory.getCategory(id);
|
||||
if (cat->getVersion() != version)
|
||||
// Don't account for update if we just created this category.
|
||||
if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end())
|
||||
{
|
||||
llwarns << "Possible version mismatch for category " << cat->getName()
|
||||
<< ", viewer version " << cat->getVersion()
|
||||
<< " server version " << version << llendl;
|
||||
LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't account for update unless AIS told us it updated that category.
|
||||
if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end())
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we have a known descendent count, set that now.
|
||||
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
|
||||
if (cat)
|
||||
{
|
||||
S32 descendent_delta = catit->second;
|
||||
S32 old_count = cat->getDescendentCount();
|
||||
LL_DEBUGS("Inventory") << "Updating descendent count for " << cat_id
|
||||
<< " with delta " << descendent_delta << " from "
|
||||
<< old_count << " to " << (old_count+descendent_delta) << LL_ENDL;
|
||||
LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta);
|
||||
gInventory.accountForUpdate(up);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE CATEGORIES
|
||||
for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin();
|
||||
create_it != mCategoriesCreated.end(); ++create_it)
|
||||
{
|
||||
LLUUID category_id(create_it->first);
|
||||
LLPointer<LLViewerInventoryCategory> new_category = create_it->second;
|
||||
|
||||
gInventory.updateCategory(new_category);
|
||||
LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL;
|
||||
}
|
||||
|
||||
// UPDATE CATEGORIES
|
||||
for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin();
|
||||
update_it != mCategoriesUpdated.end(); ++update_it)
|
||||
{
|
||||
LLUUID category_id(update_it->first);
|
||||
LLPointer<LLViewerInventoryCategory> new_category = update_it->second;
|
||||
// Since this is a copy of the category *before* the accounting update, above,
|
||||
// we need to transfer back the updated version/descendent count.
|
||||
LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID());
|
||||
if (NULL == curr_cat)
|
||||
{
|
||||
LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_category->setVersion(curr_cat->getVersion());
|
||||
new_category->setDescendentCount(curr_cat->getDescendentCount());
|
||||
gInventory.updateCategory(new_category);
|
||||
LL_DEBUGS("Inventory") << "updated category " << category_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -456,7 +775,7 @@ void AISUpdate::doUpdate()
|
|||
// 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;
|
||||
LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;
|
||||
gInventory.updateItem(new_item);
|
||||
}
|
||||
|
||||
|
|
@ -469,19 +788,36 @@ void AISUpdate::doUpdate()
|
|||
// 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;
|
||||
//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << llendl;
|
||||
LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL;
|
||||
//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL;
|
||||
gInventory.updateItem(new_item);
|
||||
}
|
||||
|
||||
// DELETE OBJECTS
|
||||
for (std::set<LLUUID>::const_iterator del_it = mObjectsDeleted.begin();
|
||||
del_it != mObjectsDeleted.end(); ++del_it)
|
||||
for (std::set<LLUUID>::const_iterator del_it = mObjectsDeletedIds.begin();
|
||||
del_it != mObjectsDeletedIds.end(); ++del_it)
|
||||
{
|
||||
LL_DEBUGS("Inventory") << "deleted item " << *del_it << llendl;
|
||||
LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL;
|
||||
gInventory.onObjectDeletedFromServer(*del_it, false, false, false);
|
||||
}
|
||||
|
||||
// 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.
|
||||
for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin();
|
||||
ucv_it != mCatVersionsUpdated.end(); ++ucv_it)
|
||||
{
|
||||
const LLUUID id = ucv_it->first;
|
||||
S32 version = ucv_it->second;
|
||||
LLViewerInventoryCategory *cat = gInventory.getCategory(id);
|
||||
if (cat->getVersion() != version)
|
||||
{
|
||||
llwarns << "Possible version mismatch for category " << cat->getName()
|
||||
<< ", viewer version " << cat->getVersion()
|
||||
<< " server version " << version << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
gInventory.notifyObservers();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "llcurl.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llhttpretrypolicy.h"
|
||||
|
|
@ -46,7 +45,7 @@ public:
|
|||
|
||||
virtual ~AISCommand() {}
|
||||
|
||||
void run_command();
|
||||
bool run_command();
|
||||
|
||||
void setCommandFunc(command_func_type command_func);
|
||||
|
||||
|
|
@ -54,13 +53,17 @@ public:
|
|||
// LLInventoryCallback::fire(). May or may not need to bother,
|
||||
// since most LLInventoryCallbacks do their work in the
|
||||
// destructor.
|
||||
virtual bool getResponseUUID(const LLSD& content, LLUUID& id);
|
||||
|
||||
/* virtual */ void httpSuccess();
|
||||
/* virtual */ void httpFailure();
|
||||
|
||||
/*virtual*/ void httpFailure();
|
||||
static bool isAPIAvailable();
|
||||
static bool getInvCap(std::string& cap);
|
||||
static bool getLibCap(std::string& cap);
|
||||
static void getCapabilityNames(LLSD& capabilityNames);
|
||||
|
||||
static bool getCap(std::string& cap);
|
||||
protected:
|
||||
virtual bool getResponseUUID(const LLSD& content, LLUUID& id);
|
||||
|
||||
private:
|
||||
command_func_type mCommandFunc;
|
||||
|
|
@ -118,26 +121,52 @@ private:
|
|||
LLSD mContents;
|
||||
};
|
||||
|
||||
class CopyLibraryCategoryCommand: public AISCommand
|
||||
{
|
||||
public:
|
||||
CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback);
|
||||
|
||||
protected:
|
||||
/* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id);
|
||||
};
|
||||
|
||||
class AISUpdate
|
||||
{
|
||||
public:
|
||||
AISUpdate(const LLSD& update);
|
||||
void parseUpdate(const LLSD& update);
|
||||
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids);
|
||||
void parseLink(const LLUUID& link_id, const LLSD& link_map);
|
||||
void parseCreatedLinks(const LLSD& links);
|
||||
void parseMeta(const LLSD& update);
|
||||
void parseContent(const LLSD& update);
|
||||
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
|
||||
void parseLink(const LLSD& link_map);
|
||||
void parseItem(const LLSD& link_map);
|
||||
void parseCategory(const LLSD& link_map);
|
||||
void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded);
|
||||
void parseEmbedded(const LLSD& embedded);
|
||||
void parseEmbeddedLinks(const LLSD& links);
|
||||
void parseEmbeddedItems(const LLSD& links);
|
||||
void parseEmbeddedCategories(const LLSD& links);
|
||||
void doUpdate();
|
||||
private:
|
||||
void clearParseResults();
|
||||
|
||||
typedef std::map<LLUUID,S32> uuid_int_map_t;
|
||||
uuid_int_map_t mCatDeltas;
|
||||
uuid_int_map_t mCatVersions;
|
||||
uuid_int_map_t mCatDescendentDeltas;
|
||||
uuid_int_map_t mCatDescendentsKnown;
|
||||
uuid_int_map_t mCatVersionsUpdated;
|
||||
|
||||
typedef std::map<LLUUID,LLPointer<LLViewerInventoryItem> > deferred_item_map_t;
|
||||
deferred_item_map_t mItemsCreated;
|
||||
deferred_item_map_t mItemsUpdated;
|
||||
typedef std::map<LLUUID,LLPointer<LLViewerInventoryCategory> > deferred_category_map_t;
|
||||
deferred_category_map_t mCategoriesCreated;
|
||||
deferred_category_map_t mCategoriesUpdated;
|
||||
|
||||
std::set<LLUUID> mObjectsDeleted;
|
||||
uuid_vec_t mItemsCreatedIds;
|
||||
// These keep track of uuid's mentioned in meta values.
|
||||
// Useful for filtering out which content we are interested in.
|
||||
uuid_list_t mObjectsDeletedIds;
|
||||
uuid_list_t mItemIds;
|
||||
uuid_list_t mCategoryIds;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -435,6 +435,50 @@ private:
|
|||
|
||||
S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0;
|
||||
|
||||
class LLWearCategoryAfterCopy: public LLInventoryCallback
|
||||
{
|
||||
public:
|
||||
LLWearCategoryAfterCopy(bool append):
|
||||
mAppend(append)
|
||||
{}
|
||||
|
||||
// virtual
|
||||
void fire(const LLUUID& id)
|
||||
{
|
||||
// Wear the inventory category.
|
||||
LLInventoryCategory* cat = gInventory.getCategory(id);
|
||||
LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend);
|
||||
}
|
||||
|
||||
private:
|
||||
bool mAppend;
|
||||
};
|
||||
|
||||
class LLTrackPhaseWrapper : public LLInventoryCallback
|
||||
{
|
||||
public:
|
||||
LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL):
|
||||
mTrackingPhase(phase_name),
|
||||
mCB(cb)
|
||||
{
|
||||
selfStartPhase(mTrackingPhase);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void fire(const LLUUID& id)
|
||||
{
|
||||
selfStopPhase(mTrackingPhase);
|
||||
if (mCB)
|
||||
{
|
||||
mCB->fire(id);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string mTrackingPhase;
|
||||
LLPointer<LLInventoryCallback> mCB;
|
||||
};
|
||||
|
||||
LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions,
|
||||
bool enforce_ordering,
|
||||
nullary_func_t post_update_func
|
||||
|
|
@ -2244,10 +2288,31 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
|
|||
LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName()
|
||||
<< " )" << LL_ENDL;
|
||||
|
||||
selfStartPhase("wear_inventory_category_fetch");
|
||||
callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
|
||||
&LLAppearanceMgr::instance(),
|
||||
category->getUUID(), copy, append));
|
||||
// If we are copying from library, attempt to use AIS to copy the category.
|
||||
bool ais_ran=false;
|
||||
if (copy && AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLUUID parent_id;
|
||||
parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
|
||||
if (parent_id.isNull())
|
||||
{
|
||||
parent_id = gInventory.getRootFolderID();
|
||||
}
|
||||
|
||||
LLPointer<LLInventoryCallback> copy_cb = new LLWearCategoryAfterCopy(append);
|
||||
LLPointer<LLInventoryCallback> track_cb = new LLTrackPhaseWrapper(
|
||||
std::string("wear_inventory_category_callback"), copy_cb);
|
||||
LLPointer<AISCommand> cmd_ptr = new CopyLibraryCategoryCommand(category->getUUID(), parent_id, track_cb);
|
||||
ais_ran=cmd_ptr->run_command();
|
||||
}
|
||||
|
||||
if (!ais_ran)
|
||||
{
|
||||
selfStartPhase("wear_inventory_category_fetch");
|
||||
callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
|
||||
&LLAppearanceMgr::instance(),
|
||||
category->getUUID(), copy, append));
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLAppearanceMgr::getActiveCopyOperations() const
|
||||
|
|
@ -3544,8 +3609,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo
|
|||
|
||||
// First, make a folder in the My Outfits directory.
|
||||
const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
// cap-based category creation was buggy until recently. use
|
||||
// existence of AIS as an indicator the fix is present. Does
|
||||
|
|
|
|||
|
|
@ -1718,7 +1718,6 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
|
|||
LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);
|
||||
if(cat)
|
||||
{
|
||||
bool accounted = false;
|
||||
S32 version = cat->getVersion();
|
||||
if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)
|
||||
{
|
||||
|
|
@ -1733,22 +1732,27 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
|
|||
}
|
||||
if(descendents_server == descendents_actual)
|
||||
{
|
||||
accounted = true;
|
||||
descendents_actual += update.mDescendentDelta;
|
||||
cat->setDescendentCount(descendents_actual);
|
||||
cat->setVersion(++version);
|
||||
lldebugs << "accounted: '" << cat->getName() << "' "
|
||||
LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' "
|
||||
<< version << " with " << descendents_actual
|
||||
<< " descendents." << llendl;
|
||||
<< " descendents." << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error condition, this means that the category did not register that
|
||||
// it got new descendents (perhaps because it is still being loaded)
|
||||
// which means its descendent count will be wrong.
|
||||
llwarns << "Accounting failed for '" << cat->getName() << "' version:"
|
||||
<< version << " due to mismatched descendent count: server == "
|
||||
<< descendents_server << ", viewer == " << descendents_actual << llendl;
|
||||
}
|
||||
}
|
||||
if(!accounted)
|
||||
else
|
||||
{
|
||||
// Error condition, this means that the category did not register that
|
||||
// it got new descendents (perhaps because it is still being loaded)
|
||||
// which means its descendent count will be wrong.
|
||||
llwarns << "Accounting failed for '" << cat->getName() << "' version:"
|
||||
<< version << llendl;
|
||||
llwarns << "Accounting failed for '" << cat->getName() << "' version: unknown ("
|
||||
<< version << ")" << llendl;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -430,7 +430,7 @@ void LLViewerInventoryItem::fetchFromServer(void) const
|
|||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLViewerInventoryItem::unpackMessage(LLSD item)
|
||||
BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item)
|
||||
{
|
||||
BOOL rv = LLInventoryItem::fromLLSD(item);
|
||||
|
||||
|
|
@ -866,6 +866,21 @@ void LLViewerInventoryCategory::localizeName()
|
|||
LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category)
|
||||
{
|
||||
BOOL rv = LLInventoryCategory::fromLLSD(category);
|
||||
localizeName();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
|
||||
{
|
||||
LLInventoryCategory::unpackMessage(msg, block, block_num);
|
||||
localizeName();
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Local function definitions
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
@ -1159,24 +1174,22 @@ void update_inventory_item(
|
|||
const LLSD& updates,
|
||||
LLPointer<LLInventoryCallback> cb)
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
|
||||
if(obj)
|
||||
bool ais_ran = false;
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
|
||||
new_item->copyViewerItem(obj);
|
||||
new_item->fromLLSD(updates,false);
|
||||
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
{
|
||||
LLSD new_llsd;
|
||||
new_item->asLLSD(new_llsd);
|
||||
LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, new_llsd, cb);
|
||||
cmd_ptr->run_command();
|
||||
}
|
||||
else // no cap
|
||||
LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
|
||||
ais_ran = cmd_ptr->run_command();
|
||||
}
|
||||
if (!ais_ran)
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
|
||||
LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
|
||||
if(obj)
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
|
||||
new_item->copyViewerItem(obj);
|
||||
new_item->fromLLSD(updates,false);
|
||||
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_UpdateInventoryItem);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
|
|
@ -1216,9 +1229,8 @@ void update_inventory_category(
|
|||
|
||||
LLPointer<LLViewerInventoryCategory> 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))
|
||||
if (0) // if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLSD new_llsd = new_cat->asLLSD();
|
||||
LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb);
|
||||
|
|
@ -1254,8 +1266,7 @@ void remove_inventory_item(
|
|||
LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
|
||||
if(obj)
|
||||
{
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb);
|
||||
cmd_ptr->run_command();
|
||||
|
|
@ -1325,8 +1336,7 @@ void remove_inventory_category(
|
|||
LLNotificationsUtil::add("CannotRemoveProtectedCategories");
|
||||
return;
|
||||
}
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb);
|
||||
cmd_ptr->run_command();
|
||||
|
|
@ -1429,8 +1439,7 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
|
|||
}
|
||||
else
|
||||
{
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);
|
||||
cmd_ptr->run_command();
|
||||
|
|
@ -1564,8 +1573,7 @@ void slam_inventory_folder(const LLUUID& folder_id,
|
|||
const LLSD& contents,
|
||||
LLPointer<LLInventoryCallback> cb)
|
||||
{
|
||||
std::string cap;
|
||||
if (AISCommand::getCap(cap))
|
||||
if (AISCommand::isAPIAvailable())
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id
|
||||
<< " new contents: " << ll_pretty_print_sd(contents) << llendl;
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ public:
|
|||
|
||||
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 unpackMessage(const LLSD& item);
|
||||
virtual BOOL importFile(LLFILE* fp);
|
||||
virtual BOOL importLegacyStream(std::istream& input_stream);
|
||||
|
||||
|
|
@ -224,6 +224,8 @@ public:
|
|||
bool importFileLocal(LLFILE* fp);
|
||||
void determineFolderType();
|
||||
void changeType(LLFolderType::EType new_folder_type);
|
||||
virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
|
||||
virtual BOOL unpackMessage(const LLSD& category);
|
||||
|
||||
private:
|
||||
friend class LLInventoryModel;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
// linden libraries
|
||||
#include "indra_constants.h"
|
||||
#include "llaisapi.h"
|
||||
#include "llavatarnamecache.h" // name lookup cap url
|
||||
#include "llfloaterreg.h"
|
||||
#include "llmath.h"
|
||||
|
|
@ -1645,7 +1646,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
|||
capabilityNames.append("FetchInventory2");
|
||||
capabilityNames.append("FetchInventoryDescendents2");
|
||||
capabilityNames.append("IncrementCOFVersion");
|
||||
capabilityNames.append("InventoryAPIv3");
|
||||
AISCommand::getCapabilityNames(capabilityNames);
|
||||
}
|
||||
|
||||
capabilityNames.append("GetDisplayNames");
|
||||
|
|
@ -1893,6 +1894,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
|
|||
return iter->second;
|
||||
}
|
||||
|
||||
bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const
|
||||
{
|
||||
if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))
|
||||
{
|
||||
llwarns << "isCapabilityAvailable called before caps received for " << name << llendl;
|
||||
}
|
||||
|
||||
CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
|
||||
if(iter == mImpl->mCapabilities.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLViewerRegion::capabilitiesReceived() const
|
||||
{
|
||||
return mCapabilitiesReceived;
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ public:
|
|||
S32 getNumSeedCapRetries();
|
||||
void setCapability(const std::string& name, const std::string& url);
|
||||
void setCapabilityDebug(const std::string& name, const std::string& url);
|
||||
bool isCapabilityAvailable(const std::string& name) const;
|
||||
// implements LLCapabilityProvider
|
||||
virtual std::string getCapability(const std::string& name) const;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue