diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 146 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 2 | ||||
| -rwxr-xr-x | indra/newview/llviewerregion.cpp | 1 | 
3 files changed, 145 insertions, 4 deletions
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 86440fca48..2eeb0640cc 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -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(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 119b07b1f5..63458e60ea 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -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(); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c21aeb1d57..697433148b 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -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");  | 
