Add support for RequestTaskInventory capability
The viewer now prefers to load inventory via the capability rather than over the deprecated Xfer system, though both are still supported. # Conflicts: # indra/newview/llviewerobject.hmaster
parent
4f67df346b
commit
6fd4f13c47
|
|
@ -2917,6 +2917,17 @@ void LLViewerObject::fetchInventoryFromServer()
|
|||
delete mInventory;
|
||||
mInventory = NULL;
|
||||
|
||||
// This will get reset by doInventoryCallback or processTaskInv
|
||||
mInvRequestState = INVENTORY_REQUEST_PENDING;
|
||||
|
||||
if (mRegionp && !mRegionp->getCapability("RequestTaskInventory").empty())
|
||||
{
|
||||
LLCoros::instance().launch("LLViewerObject::fetchInventoryFromCapCoro()",
|
||||
boost::bind(&LLViewerObject::fetchInventoryFromCapCoro, mID));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Using old task inventory path!" << LL_ENDL;
|
||||
// Results in processTaskInv
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_RequestTaskInventory);
|
||||
|
|
@ -2926,15 +2937,13 @@ void LLViewerObject::fetchInventoryFromServer()
|
|||
msg->nextBlockFast(_PREHASH_InventoryData);
|
||||
msg->addU32Fast(_PREHASH_LocalID, mLocalID);
|
||||
msg->sendReliable(mRegionp->getHost());
|
||||
|
||||
// This will get reset by doInventoryCallback or processTaskInv
|
||||
mInvRequestState = INVENTORY_REQUEST_PENDING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds)
|
||||
{
|
||||
// unless already waiting, drop previous request and shedule an update
|
||||
// unless already waiting, drop previous request and schedule an update
|
||||
if (mInvRequestState != INVENTORY_REQUEST_WAIT)
|
||||
{
|
||||
if (mInvRequestXFerId != 0)
|
||||
|
|
@ -2965,6 +2974,80 @@ void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLViewerObject::fetchInventoryFromCapCoro(const LLUUID task_inv)
|
||||
{
|
||||
LLViewerObject *obj = gObjectList.findObject(task_inv);
|
||||
if (obj)
|
||||
{
|
||||
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
|
||||
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TaskInventoryRequest", httpPolicy));
|
||||
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||
std::string url = obj->mRegionp->getCapability("RequestTaskInventory") + "?task_id=" + obj->mID.asString();
|
||||
// If we already have a copy of the inventory then add it so the server won't re-send something we already have.
|
||||
// We expect this case to crop up in the case of failed inventory mutations, but it might happen otherwise as well.
|
||||
if (obj->mInventorySerialNum && obj->mInventory)
|
||||
url += "&inventory_serial=" + std::to_string(obj->mInventorySerialNum);
|
||||
|
||||
obj->mInvRequestState = INVENTORY_XFER;
|
||||
LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
|
||||
|
||||
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||
|
||||
// Object may have gone away while we were suspended, double-check that it still exists
|
||||
obj = gObjectList.findObject(task_inv);
|
||||
if (!obj)
|
||||
{
|
||||
LL_WARNS() << "Object " << task_inv << " went away while fetching inventory, dropping result" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
bool potentially_stale = false;
|
||||
if (status)
|
||||
{
|
||||
// Dealing with inventory serials is kind of funky. They're monotonically increasing and 16 bits,
|
||||
// so we expect them to overflow, but we can use inv serial < expected serial as a signal that we may
|
||||
// have mutated the task inventory since we kicked off the request, and those mutations may have not
|
||||
// been taken into account yet. Of course, those mutations may have actually failed which would result
|
||||
// in the inv serial never increasing.
|
||||
//
|
||||
// When we detect this case, set the expected inv serial to the inventory serial we actually received
|
||||
// and kick off a re-request after a slight delay.
|
||||
S16 serial = (S16)result["inventory_serial"].asInteger();
|
||||
potentially_stale = serial < obj->mExpectedInventorySerialNum;
|
||||
LL_INFOS() << "Inventory loaded for " << task_inv << LL_ENDL;
|
||||
obj->mInventorySerialNum = serial;
|
||||
obj->mExpectedInventorySerialNum = serial;
|
||||
obj->loadTaskInvLLSD(result);
|
||||
}
|
||||
else if (status.getType() == 304)
|
||||
{
|
||||
LL_INFOS() << "Inventory wasn't changed on server!" << LL_ENDL;
|
||||
obj->mInvRequestState = INVENTORY_REQUEST_STOPPED;
|
||||
// Even though it wasn't necessary to send a response, we still may have mutated
|
||||
// the inventory since we kicked off the request, check for that case.
|
||||
potentially_stale = obj->mInventorySerialNum < obj->mExpectedInventorySerialNum;
|
||||
// Set this to what we already have so that we don't re-request a second time.
|
||||
obj->mExpectedInventorySerialNum = obj->mInventorySerialNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not sure that there's anything sensible we can do to recover here, retrying in a loop would be bad.
|
||||
LL_WARNS() << "Error status while requesting task inventory: " << status.toString() << LL_ENDL;
|
||||
obj->mInvRequestState = INVENTORY_REQUEST_STOPPED;
|
||||
}
|
||||
|
||||
if (potentially_stale)
|
||||
{
|
||||
// Stale? I guess we can use what we got for now, but we'll have to re-request
|
||||
LL_WARNS() << "Stale inv_serial? Re-requesting." << LL_ENDL;
|
||||
obj->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLControlAvatar *LLViewerObject::getControlAvatar()
|
||||
{
|
||||
return getRootEdit()->mControlAvatar.get();
|
||||
|
|
@ -3140,6 +3223,20 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
|
|||
S16 serial = 0;
|
||||
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial);
|
||||
|
||||
if (object->mRegionp && !object->mRegionp->getCapability("RequestTaskInventory").empty())
|
||||
{
|
||||
// It seems that simulator may ask us to re-download the task inventory if an update to the inventory
|
||||
// happened out-of-band while we had the object selected (like if a script is saved.)
|
||||
//
|
||||
// If we're meant to use the HTTP capability, ignore the contents of the UDP message and fetch the
|
||||
// inventory via the CAP so that we don't flow down the UDP inventory request path unconditionally here.
|
||||
// We shouldn't need to wait, as any updates should already be ready to fetch by this point.
|
||||
LL_INFOS() << "Handling unsolicited ReplyTaskInventory for " << task_id << LL_ENDL;
|
||||
object->mExpectedInventorySerialNum = serial;
|
||||
object->fetchInventoryFromServer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (serial == object->mInventorySerialNum
|
||||
&& serial < object->mExpectedInventorySerialNum)
|
||||
{
|
||||
|
|
@ -3347,6 +3444,47 @@ bool LLViewerObject::loadTaskInvFile(const std::string& filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
void LLViewerObject::loadTaskInvLLSD(const LLSD& inv_result)
|
||||
{
|
||||
if (inv_result.has("contents"))
|
||||
{
|
||||
if(mInventory)
|
||||
{
|
||||
mInventory->clear(); // will deref and delete it
|
||||
}
|
||||
else
|
||||
{
|
||||
mInventory = new LLInventoryObject::object_list_t;
|
||||
}
|
||||
|
||||
// Synthesize the "Contents" category, the viewer expects it, but it isn't sent.
|
||||
LLPointer<LLInventoryObject> inv = new LLInventoryObject(mID, LLUUID::null, LLAssetType::AT_CATEGORY, "Contents");
|
||||
mInventory->push_front(inv);
|
||||
|
||||
const LLSD& inventory = inv_result["contents"];
|
||||
for (const auto& inv_entry : llsd::inArray(inventory))
|
||||
{
|
||||
if (inv_entry.has("item_id"))
|
||||
{
|
||||
LLPointer<LLViewerInventoryItem> inv = new LLViewerInventoryItem;
|
||||
inv->unpackMessage(inv_entry);
|
||||
mInventory->push_front(inv);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS_ONCE() << "Unknown inventory entry while reading from inventory file. Entry: '"
|
||||
<< inv_entry << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "unable to load task inventory: " << inv_result << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
doInventoryCallback();
|
||||
}
|
||||
|
||||
void LLViewerObject::doInventoryCallback()
|
||||
{
|
||||
for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ private:
|
|||
// forms task inventory request after some time passed, marks request as pending
|
||||
void fetchInventoryDelayed(const F64 &time_seconds);
|
||||
static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds);
|
||||
static void fetchInventoryFromCapCoro(const LLUUID task_inv);
|
||||
|
||||
public:
|
||||
//
|
||||
|
|
@ -826,6 +827,7 @@ protected:
|
|||
|
||||
static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status);
|
||||
bool loadTaskInvFile(const std::string& filename);
|
||||
void loadTaskInvLLSD(const LLSD &inv_result);
|
||||
void doInventoryCallback();
|
||||
|
||||
bool isOnMap();
|
||||
|
|
|
|||
|
|
@ -3239,6 +3239,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
|||
capabilityNames.append("FetchInventory2");
|
||||
capabilityNames.append("FetchInventoryDescendents2");
|
||||
capabilityNames.append("IncrementCOFVersion");
|
||||
capabilityNames.append("RequestTaskInventory");
|
||||
AISAPI::getCapNames(capabilityNames);
|
||||
|
||||
capabilityNames.append("InterestList");
|
||||
|
|
|
|||
Loading…
Reference in New Issue