SL-18629 Replacing UDP creation messages with callback based AIS

master
Andrey Kleshchev 2023-03-10 00:12:16 +02:00 committed by akleshchev
parent 811da7dbb1
commit ff6ff01c6a
8 changed files with 370 additions and 181 deletions

View File

@ -93,6 +93,7 @@ void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, c
if (cap.empty())
{
LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
callback(LLUUID::null);
return;
}
@ -485,13 +486,17 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
{
LLUUID id(LLUUID::null);
if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
if (type == COPYLIBRARYCATEGORY)
{
id = result["category_id"];
if (result.has("category_id"))
{
id = result["category_id"];
} //else signal failure
callback(id);
}
if (type == CREATEINVENTORY)
{
bool informed_caller = false;
if (result.has("_created_categories"))
{
LLSD& cats = result["_created_categories"];
@ -500,6 +505,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
{
LLUUID cat_id = *cat_iter;
callback(cat_id);
informed_caller = true;
}
}
if (result.has("_created_items"))
@ -510,8 +516,15 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
{
LLUUID item_id = *item_iter;
callback(item_id);
informed_caller = true;
}
}
if (!informed_caller)
{
// signal failure with null id
callback(id);
}
}
}

View File

@ -896,8 +896,11 @@ void LLFloaterMarketplaceValidation::onOpen(const LLSD& key)
// Validates the folder
if (cat_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
cat_id,
NULL,
boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3),
false);
}
// Handle the listing folder being processed

View File

@ -2901,11 +2901,16 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
if (!validate_marketplacelistings(cat,NULL))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[version_folder_id](bool result)
{
LLMarketplaceData::instance().activateListing(version_folder_id,false);
if (!result)
{
LLMarketplaceData::instance().activateListing(version_folder_id, false);
}
}
);
}
// In all cases, update the listing we moved from so suffix are updated
update_marketplace_category(from_folder_uuid);
@ -3371,18 +3376,26 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
if (depth_nesting_in_marketplace(mUUID) == 1)
{
LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID);
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
mMessage = "";
if (!validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[this, version_folder_id](bool result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().activateListing(mUUID,true);
}
// todo: might need to ensure bridge/mUUID exists or this will cause crashes
if (!result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().activateListing(mUUID, true);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3)
);
}
return;
}
@ -3390,18 +3403,27 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
{
if (depth_nesting_in_marketplace(mUUID) == 2)
{
LLInventoryCategory* category = gInventory.getCategory(mUUID);
mMessage = "";
if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
}
else
{
LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
}
if (!result)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantFolderActivationFailed", subs);
}
else
{
LLInventoryCategory* category = gInventory.getCategory(mUUID);
LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
false,
2);
}
return;
}
@ -3424,29 +3446,44 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("marketplace_create_listing" == action)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID);
mMessage = "";
bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false);
if (!validates)
// first run vithout fix_hierarchy, second run with fix_hierarchy
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
mMessage = "";
validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true);
if (validates)
if (!result)
{
LLNotificationsUtil::add("MerchantForceValidateListing");
mMessage = "";
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
mUUID,
[this](bool result)
{
if (result)
{
LLNotificationsUtil::add("MerchantForceValidateListing");
LLMarketplaceData::instance().createListing(mUUID);
}
else
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
true);
}
}
else
{
LLMarketplaceData::instance().createListing(mUUID);
}
},
boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),
false);
if (!validates)
{
LLSD subs;
subs["[ERROR_CODE]"] = mMessage;
LLNotificationsUtil::add("MerchantListingFailed", subs);
}
else
{
LLMarketplaceData::instance().createListing(mUUID);
}
return;
}
else if ("marketplace_disassociate_listing" == action)
@ -5296,11 +5333,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid);
if (version_folder_id.notNull())
{
LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id);
if (!validate_marketplacelistings(cat,NULL))
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(
version_folder_id,
[version_folder_id](bool result)
{
LLMarketplaceData::instance().activateListing(version_folder_id,false);
}
if (!result)
{
LLMarketplaceData::instance().activateListing(version_folder_id, false);
}
});
}
}

View File

@ -1492,7 +1492,7 @@ bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUU
// Reparent the folder
gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false);
// Check the destination folder recursively for no copy items and promote the including folders if any
validate_marketplacelistings(dest_cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(dest_folder);
}
// Update the modified folders
@ -1517,32 +1517,23 @@ bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCa
return cat1->getName().compare(cat2->getName()) < 0;
}
void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level)
{
LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL;
}
// Make all relevant business logic checks on the marketplace listings starting with the folder as argument.
// This function does no deletion of listings but a mere audit and raises issues to the user (through the
// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised.
// optional callback cb).
// The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders.
bool validate_marketplacelistings(
// @pending_callbacks - how many callbacks we are waiting for, must be inited before use
// @result - true if things validate, false if issues are raised, must be inited before use
typedef boost::function<void(S32 pending_callbacks, bool result)> validation_result_callback_t;
void validate_marketplacelistings(
LLInventoryCategory* cat,
validation_callback_t cb,
validation_result_callback_t cb_result,
LLMarketplaceValidator::validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth,
bool notify_observers)
bool notify_observers,
S32 &pending_callbacks,
bool &result)
{
#if 0
// Used only for debug
if (!cb)
{
cb = boost::bind(&dump_trace, _1, _2, _3);
}
#endif
// Folder is valid unless issue is raised
bool result = true;
// Get the type and the depth of the folder
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (cat);
const LLFolderType::EType folder_type = cat->getPreferredType();
@ -1574,10 +1565,10 @@ bool validate_marketplacelistings(
if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy))
{
result = false;
if (cb)
if (cb_msg)
{
message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1587,26 +1578,42 @@ bool validate_marketplacelistings(
{
if (fix_hierarchy)
{
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
// Nest the stock folder one level deeper in a normal folder and restart from there
pending_callbacks++;
LLUUID parent_uuid = cat->getParentUUID();
LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName());
LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid);
gInventory.changeCategoryParent(viewer_cat, folder_uuid, false);
result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1, notify_observers);
return result;
LLUUID cat_uuid = cat->getUUID();
gInventory.createNewCategory(parent_uuid,
LLFolderType::FT_NONE,
cat->getName(),
[cat_uuid, cb_result, cb_msg, fix_hierarchy, depth, notify_observers](const LLUUID &new_cat_id)
{
LLInventoryCategory * move_cat = gInventory.getCategory(cat_uuid);
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *)(move_cat);
LLInventoryCategory * new_cat = gInventory.getCategory(new_cat_id);
gInventory.changeCategoryParent(viewer_cat, new_cat_id, false);
S32 pending = 0;
bool result = true;
// notify_observers probably should be true in such case?
validate_marketplacelistings(new_cat, cb_result, cb_msg, fix_hierarchy, depth + 1, notify_observers, pending, result);
cb_result(pending, result);
}
);
result = false;
return;
}
else
{
result = false;
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1637,10 +1644,10 @@ bool validate_marketplacelistings(
if (!can_move_to_marketplace(item, error_msg, false))
{
has_bad_items = true;
if (cb && fix_hierarchy)
if (cb_msg && fix_hierarchy)
{
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
continue;
}
@ -1671,35 +1678,35 @@ bool validate_marketplacelistings(
if (depth == 2)
{
// If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist)
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2))
{
// If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock)
if (cb)
if (cb_msg)
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else if (cb)
else if (cb_msg)
{
// We warn if there's nothing in a regular folder (may be it's an under construction listing)
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
}
else
{
// Done with that folder : Print out the folder name unless we already found an error here
if (cb && result && (depth >= 1))
if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
}
@ -1707,10 +1714,10 @@ bool validate_marketplacelistings(
else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0))))
{
// Done with that folder : Print out the folder name unless we already found an error here
if (cb && result && (depth >= 1))
if (cb_msg && result && (depth >= 1))
{
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
else
@ -1732,11 +1739,11 @@ bool validate_marketplacelistings(
while (items_vector_it != items_vector.end())
{
// Create a new folder
LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
const LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID());
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back());
std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName());
LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK);
if (cb)
if (cb_msg)
{
std::string message = "";
if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK)
@ -1747,24 +1754,31 @@ bool validate_marketplacelistings(
{
message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version");
}
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
std::vector<LLUUID> &uuid_vector = items_vector_it->second;
pending_callbacks++;
std::vector<LLUUID> uuid_vector = items_vector_it->second; // needs to be a copy for lambda
gInventory.createNewCategory(
parent_uuid,
new_folder_type,
folder_name,
[uuid_vector, cb, indent, depth, parent_uuid, notify_observers](const LLUUID &new_category_id)
[uuid_vector, cb_result, cb_msg, depth, parent_uuid, notify_observers](const LLUUID &new_category_id)
{
// Move each item to the new folder
std::vector<LLUUID>::reverse_iterator iter = uuid_vector.rbegin();
std::vector<LLUUID>::const_reverse_iterator iter = uuid_vector.rbegin();
while (iter != uuid_vector.rend())
{
LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(*iter);
if (cb)
if (cb_msg)
{
std::string indent;
for (int i = 1; i < depth; i++)
{
indent += " ";
}
std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move");
cb(message, depth, LLError::LEVEL_WARN);
cb_msg(message, depth, LLError::LEVEL_WARN);
}
gInventory.changeItemParent(viewer_inv_item, new_category_id, true);
iter++;
@ -1777,6 +1791,7 @@ bool validate_marketplacelistings(
{
gInventory.notifyObservers();
}
cb_result(0, true);
}
);
items_vector_it++;
@ -1792,11 +1807,11 @@ bool validate_marketplacelistings(
{
LLViewerInventoryCategory * viewer_cat = (LLViewerInventoryCategory *) (*iter);
gInventory.changeCategoryParent(viewer_cat, parent_uuid, false);
result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth, false);
validate_marketplacelistings(viewer_cat, cb_result, cb_msg, fix_hierarchy, depth, false, pending_callbacks, result);
}
}
}
else if (cb)
else if (cb_msg)
{
// We are not fixing the hierarchy but reporting problems, report everything we can find
// Print the folder name
@ -1807,20 +1822,20 @@ bool validate_marketplacelistings(
// Report if a stock folder contains a mix of items
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0))
{
// Report if a stock folder contains subfolders
result = false;
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else
{
// Simply print the folder name
std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log");
cb(message,depth,LLError::LEVEL_INFO);
cb_msg(message,depth,LLError::LEVEL_INFO);
}
}
// Scan each item and report if there's a problem
@ -1835,21 +1850,21 @@ bool validate_marketplacelistings(
// Report items that shouldn't be there to start with
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg;
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK))
{
// Report stock items that are misplaced
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
else if (depth == 1)
{
// Report items not wrapped in version folder
result = false;
std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item");
cb(message,depth,LLError::LEVEL_ERROR);
cb_msg(message,depth,LLError::LEVEL_ERROR);
}
}
}
@ -1858,17 +1873,18 @@ bool validate_marketplacelistings(
if (viewer_cat->getDescendentCount() == 0)
{
// Remove the current folder if it ends up empty
if (cb)
if (cb_msg)
{
std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete");
cb(message,depth,LLError::LEVEL_WARN);
cb_msg(message,depth,LLError::LEVEL_WARN);
}
gInventory.removeCategory(cat->getUUID());
if (notify_observers)
{
gInventory.notifyObservers();
}
return result && !has_bad_items;
result &=!has_bad_items;
return;
}
}
@ -1881,15 +1897,15 @@ bool validate_marketplacelistings(
for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++)
{
LLInventoryCategory* category = *iter;
result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1, false);
validate_marketplacelistings(category, cb_result, cb_msg, fix_hierarchy, depth + 1, false, pending_callbacks, result);
}
update_marketplace_category(cat->getUUID(), true, true);
if (notify_observers)
{
gInventory.notifyObservers();
}
return result && !has_bad_items;
result &= !has_bad_items;
}
void change_item_parent(const LLUUID& item_id, const LLUUID& new_parent_id)
@ -1989,9 +2005,92 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
inventory_func_type func = boost::bind(&move_items_to_folder, _1, selected_uuids);
gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
}
///----------------------------------------------------------------------------
/// LLMarketplaceValidator implementations
///----------------------------------------------------------------------------
LLMarketplaceValidator::LLMarketplaceValidator()
{
}
LLMarketplaceValidator::~LLMarketplaceValidator()
{
}
void LLMarketplaceValidator::validateMarketplaceListings(
const LLUUID &category_id,
LLMarketplaceValidator::validation_done_callback_t cb_done,
LLMarketplaceValidator::validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth)
{
mValidationQueue.emplace(category_id, cb_done, cb_msg, fix_hierarchy, depth);
if (!mValidationInProgress)
{
start();
}
}
void LLMarketplaceValidator::start()
{
if (mValidationQueue.empty())
{
mValidationInProgress = false;
return;
}
mValidationInProgress = true;
mPendingCallbacks = 1; // do '1' in case something decides ro callback immediately
const ValidationRequest &first = mValidationQueue.front();
LLViewerInventoryCategory* cat = gInventory.getCategory(first.mCategoryId);
validation_result_callback_t result_callback = [](S32 pending, bool result)
{
LLMarketplaceValidator* validator = LLMarketplaceValidator::getInstance();
validator->mPendingCallbacks--; // we just got a callback
validator->mPendingCallbacks += pending;
validator->mPendingResult &= result;
if (validator->mPendingCallbacks <= 0)
{
llassert(validator->mPendingCallbacks == 0); // shouldn't be below 0
const ValidationRequest &first = validator->mValidationQueue.front();
if (first.mCbDone)
{
first.mCbDone(validator->mPendingResult);
}
validator->mValidationQueue.pop(); // done;
validator->start();
}
};
validate_marketplacelistings(
cat,
result_callback,
first.mCbMsg,
first.mFixHierarchy,
first.mDepth,
true,
mPendingCallbacks,
mPendingResult);
result_callback(mPendingCallbacks, mPendingResult);
}
LLMarketplaceValidator::ValidationRequest::ValidationRequest(
LLUUID category_id,
validation_done_callback_t cb_done,
validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth)
: mCategoryId(category_id)
, mCbDone(cb_done)
, mCbMsg(cb_msg)
, mFixHierarchy(fix_hierarchy)
, mDepth(depth)
{}
///----------------------------------------------------------------------------
/// LLInventoryCollectFunctor implementations
///----------------------------------------------------------------------------

View File

@ -81,13 +81,12 @@ void copy_inventory_category_content(const LLUUID& new_cat_uuid, LLInventoryMode
// Generates a string containing the path to the item specified by item_id.
void append_path(const LLUUID& id, std::string& path);
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_callback_t;
bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false);
bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false);
bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false);
bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false);
bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1, bool notify_observers = true);
S32 depth_nesting_in_marketplace(LLUUID cur_uuid);
LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth);
S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false);
@ -102,6 +101,50 @@ bool is_only_items_selected(const uuid_vec_t& selected_uuids);
** **
*******************************************************************************/
class LLMarketplaceValidator: public LLSingleton<LLMarketplaceValidator>
{
LLSINGLETON(LLMarketplaceValidator);
~LLMarketplaceValidator();
LOG_CLASS(LLMarketplaceValidator);
public:
typedef boost::function<void(std::string& validation_message, S32 depth, LLError::ELevel log_level)> validation_msg_callback_t;
typedef boost::function<void(bool result)> validation_done_callback_t;
void validateMarketplaceListings(
const LLUUID &category_id,
validation_done_callback_t cb_done = NULL,
validation_msg_callback_t cb_msg = NULL,
bool fix_hierarchy = true,
S32 depth = -1);
private:
void start();
class ValidationRequest
{
public:
ValidationRequest(
LLUUID category_id,
validation_done_callback_t cb_done,
validation_msg_callback_t cb_msg,
bool fix_hierarchy,
S32 depth);
LLUUID mCategoryId;
validation_done_callback_t mCbDone;
validation_msg_callback_t mCbMsg;
bool mFixHierarchy;
S32 mDepth;
};
bool mValidationInProgress;
S32 mPendingCallbacks;
bool mPendingResult;
// todo: might be a good idea to memorize requests by id and
// filter out ones that got multiple validation requests
std::queue<ValidationRequest> mValidationQueue;
};
/********************************************************************************
** **
** INVENTORY COLLECTOR FUNCTIONS

View File

@ -954,27 +954,23 @@ const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::ETyp
// Convenience function to create a new category. You could call
// updateCategory() with a newly generated UUID category, but this
// version will take care of details like what the name should be
// based on preferred type. Returns the UUID of the new category.
//
// On failure, returns a null UUID.
// FIXME: callers do not check for or handle a null results currently.
LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
// based on preferred type.
void LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& pname,
inventory_func_type callback)
{
LLUUID id; // Initially null.
if (!isInventoryUsable())
{
LL_WARNS(LOG_INV) << "Inventory is not usable; can't create requested category of type "
<< preferred_type << LL_ENDL;
return id;
return;
}
if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
{
LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL;
return id;
return;
}
if (preferred_type != LLFolderType::FT_NONE)
@ -990,24 +986,53 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
{
name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
}
#ifdef USE_AIS_FOR_NC
// D567 currently this doesn't really work due to limitations in
// AIS3, also violates the common caller assumption that we can
// assign the id and return immediately.
if (callback)
// D567 currently this doesn't really work due to limitations in
// AIS3, also violates the common caller assumption that we can
// assign the id and return immediately.
if (callback && AISAPI::isAvailable())
{
// D567 note that we no longer assign the UUID in the viewer, so various workflows need to change.
LLSD new_inventory = LLSD::emptyMap();
new_inventory["categories"] = LLSD::emptyArray();
LLViewerInventoryCategory cat(LLUUID::null, parent_id, preferred_type, name, gAgent.getID());
LLSD cat_sd = cat.asLLSD();
new_inventory["categories"].append(cat_sd);
AISAPI::CreateInventory(parent_id, new_inventory, callback);
AISAPI::CreateInventory(
parent_id,
new_inventory,
[this, callback, parent_id, preferred_type, name] (const LLUUID& new_category)
{
if (new_category.isNull())
{
callback(new_category);
return;
}
return LLUUID::null;
LLViewerInventoryCategory* folderp = gInventory.getCategory(new_category);
if (!folderp)
{
// Add the category to the internal representation
LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
new_category,
parent_id,
preferred_type,
name,
gAgent.getID());
LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
accountForUpdate(update);
cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
cat->setDescendentCount(0);
updateCategory(cat);
}
callback(new_category);
});
return;
}
#else
#endif
LLViewerRegion* viewer_region = gAgent.getRegion();
std::string url;
if ( viewer_region )
@ -1016,7 +1041,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
if (!url.empty() && callback)
{
//Let's use the new capability.
LLUUID id;
id.generate();
LLSD request, body;
body["folder_id"] = id;
@ -1030,48 +1055,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
LL_DEBUGS(LOG_INV) << "Creating category via request: " << ll_pretty_print_sd(request) << LL_ENDL;
LLCoros::instance().launch("LLInventoryModel::createNewCategoryCoro",
boost::bind(&LLInventoryModel::createNewCategoryCoro, this, url, body, callback));
return LLUUID::null;
}
#endif
if (!gMessageSystem)
{
return LLUUID::null;
}
// D567 FIXME this UDP code path needs to be removed. Requires
// reworking many of the callers to use callbacks rather than
// assuming instant success.
// Add the category to the internal representation
LL_WARNS() << "D567 need to remove this usage" << LL_ENDL;
id.generate();
LLPointer<LLViewerInventoryCategory> cat =
new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1
cat->setDescendentCount(0);
LLCategoryUpdate update(cat->getParentUUID(), 1);
accountForUpdate(update);
updateCategory(cat);
LL_DEBUGS(LOG_INV) << "Creating category via UDP message CreateInventoryFolder, type " << preferred_type << LL_ENDL;
// Create the category on the server. We do this to prevent people
// from munging their protected folders.
LLMessageSystem* msg = gMessageSystem;
msg->newMessage("CreateInventoryFolder");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlock("FolderData");
cat->packMessage(msg);
gAgent.sendReliableMessage();
// return the folder id of the newly created folder
return id;
}
void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inventory_func_type callback)
@ -1095,12 +1079,20 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv
if (!status)
{
LL_WARNS() << "HTTP failure attempting to create category." << LL_ENDL;
if (callback)
{
callback(LLUUID::null);
}
return;
}
if (!result.has("folder_id"))
{
LL_WARNS() << "Malformed response contents" << ll_pretty_print_sd(result) << LL_ENDL;
if (callback)
{
callback(LLUUID::null);
}
return;
}

View File

@ -477,7 +477,7 @@ public:
public:
// Returns the UUID of the new category. If you want to use the default
// name based on type, pass in a NULL to the 'name' parameter.
LLUUID createNewCategory(const LLUUID& parent_id,
void createNewCategory(const LLUUID& parent_id,
LLFolderType::EType preferred_type,
const std::string& name,
inventory_func_type callback = NULL);

View File

@ -700,10 +700,9 @@ void LLMarketplaceInventoryObserver::onIdleProcessQueue(void *userdata)
// If it's a folder known to the marketplace, let's check it's in proper shape
if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it))
{
LLInventoryCategory* cat = (LLInventoryCategory*)(obj);
// can trigger notifyObservers
// can cause more structural changes
validate_marketplacelistings(cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(obj->getUUID());
}
}
else
@ -1848,8 +1847,7 @@ void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32
if (found->second <= 0)
{
mValidationWaitingList.erase(found);
LLInventoryCategory *cat = gInventory.getCategory(folder_id);
validate_marketplacelistings(cat);
LLMarketplaceValidator::getInstance()->validateMarketplaceListings(folder_id);
update_marketplace_category(folder_id);
gInventory.notifyObservers();
}