/// <summary> /// Request a download of this folder's content information. Block until done, or timeout is reached /// </summary> /// <param name="recurse">Indicate if we should recursively download content information.</param> /// <param name="folders">Indicate if sub-folder data should be downloaded (true)</param> /// <param name="items">Indicate if item data should be downloaded too (true)</param> /// <param name="timeout">Milliseconds to wait before timing out, or -1 to wait indefinately.</param> /// <returns>The Request object for this download</returns> public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, int timeout) { DownloadRequest_Folder dr = iManager.FolderRequestAppend(FolderID, recurse, true, items, Name); dr.RequestComplete.WaitOne(timeout, false); return(dr); }
public override bool Equals(object obj) { if (obj is DownloadRequest_Folder) { DownloadRequest_Folder df = (DownloadRequest_Folder)obj; if ((this.FolderID == df.FolderID) && (this.Recurse == df.Recurse) && (this.FetchFolders == df.FetchFolders) && (this.FetchItems == df.FetchItems) && (this.Received == df.Received) && (this.Expected == df.Expected) ) { return(true); } else { return(false); } } else { return(base.Equals(obj)); } }
/// <summary> /// Request a download of this folder's content information. /// </summary> /// <param name="Recurse">Indicate if we should recursively download content information.</param> /// <param name="Items">Indicate if item data should be downloaded too (true), or only folders(false)</param> /// <returns>The Request object for this download</returns> public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool items) { _Contents.Clear(); DownloadRequest_Folder dr = new DownloadRequest_Folder(FolderID, recurse, items); iManager.RequestFolder(dr); return(dr); }
/// <summary> /// /// </summary> /// <param name="dr"></param> internal void RequestFolder(DownloadRequest_Folder dr) { Packet packet = InvPacketHelper.FetchInventoryDescendents( dr.FolderID , dr.FetchFolders , dr.FetchItems); FolderDownloadStatus[dr.FolderID] = dr; slClient.Network.SendPacket(packet); }
/// <summary> /// If not currently downloading a request, dequeue the next request and start it. /// </summary> protected void FolderRequestBegin() { // Wait until it's safe to be modifying what is currently downloading. CurrentlyDownloadingMutex.WaitOne(); // If we not already downloading stuff, then lets start if (CurrentlyDownloadingAFolder == false) { // Start downloading the first thing at the head of the queue lock (FolderRequests) { while ((FolderRequests.Count > 0) && (FolderRequests[0].IsCompleted)) { LogDescendantQueueEvent("Head request completed, notify recurse completed: " + FolderRequests[0]); FolderRequests.RemoveAt(0); } if (FolderRequests.Count > 0) { CurrentlyDownloadingRequest = FolderRequests[0]; LogDescendantQueueEvent("Starting download of head of queue: " + FolderRequests[0].ToString()); } else { // Nothing to do // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); return; } } // Mark that we're currently downloading CurrentlyDownloadingAFolder = true; // Download! Packet packet = InvPacketHelper.FetchInventoryDescendents( CurrentlyDownloadingRequest.FolderID , CurrentlyDownloadingRequest.FetchFolders , CurrentlyDownloadingRequest.FetchItems); slClient.Network.SendPacket(packet); } // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); }
protected DownloadRequest_Folder FolderRequestPrepend(LLUUID folderID, bool recurse, bool fetchFolders, bool fetchItems, string requestName) { DownloadRequest_Folder dr = new DownloadRequest_Folder(folderID, recurse, fetchFolders, fetchItems, requestName); // Prepend the request at the head of the queue lock (FolderRequests) { if (FolderRequests.Contains(dr)) { foreach (DownloadRequest_Folder existing in FolderRequests) { if (dr.Equals(existing)) { dr = existing; break; } } LogDescendantQueueEvent("Append(returned existing): " + dr.ToString()); } else { FolderRequests.Insert(0, dr); LogDescendantQueueEvent("Prepend: " + dr.ToString()); } } return dr; }
/// <summary> /// Append a request to the end of the queue. /// </summary> internal DownloadRequest_Folder FolderRequestAppend(LLUUID folderID, bool recurse, bool fetchFolders, bool fetchItems, string requestName) { DownloadRequest_Folder dr = new DownloadRequest_Folder(folderID, recurse, fetchFolders, fetchItems, requestName); // Add new request to the tail of the queue lock (FolderRequests) { if (FolderRequests.Contains(dr)) { foreach (DownloadRequest_Folder existing in FolderRequests) { if (dr.Equals(existing)) { dr = existing; break; } } LogDescendantQueueEvent("Append(returned existing): " + dr.ToString()); } else { FolderRequests.Add(dr); LogDescendantQueueEvent("Append: " + dr.ToString()); } } FolderRequestBegin(); return dr; }
/// <summary> /// Returned in response to a FetchInventoryDescendents request. Contains information about the /// contents of a folder. /// </summary> /// <param name="packet"></param> /// <param name="simulator"></param> public void InventoryDescendentsHandler(Packet packet, Simulator simulator) { InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet; // The UUID of this folder. LLUUID uuidFolderID = reply.AgentData.FolderID; // Wait until it's safe to be looking at what is currently downloading. CurrentlyDownloadingMutex.WaitOne(); // Make sure this request matches the one we believe is the currently downloading request if (((CurrentlyDownloadingRequest != null) && (CurrentlyDownloadingRequest.FolderID != uuidFolderID)) || (CurrentlyDownloadingRequest == null)) { // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); // Log problem LogDescendantQueueEvent("Unexpected descendent packet for folder: " + uuidFolderID.ToStringHyphenated()); // Just discard this packet... return; } // Get the Inventory folder that we'll be updating InventoryFolder InvFolderUpdating = (InventoryFolder)FoldersByUUID[uuidFolderID]; // Update Inventory Manager's last tick point, used for timeouts and such // LastPacketRecievedAtTick = Environment.TickCount; // Used to count the number of descendants received to see if we're finished or not. int iDescendentsExpected = reply.AgentData.Descendents; int iDescendentsReceivedThisBlock = 0; #region Handle Child Items foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) { // There is always an item block, even if there isn't any items // the "filler" block will not have a name if (itemBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; if (itemBlock.ItemID == LLUUID.Zero) { // this shouldn't ever happen, unless you've uploaded an invalid item // to yourself while developping inventory code :-( } else { InventoryItem TempInvItem = new InventoryItem(this, itemBlock); if (InvFolderUpdating._Contents.Contains(TempInvItem) == false) { #region Create an instance of the appriopriate Inventory class if ((TempInvItem.InvType == 7) && (TempInvItem.Type == (sbyte)Asset.AssetType.Notecard)) { InventoryItem temp = new InventoryNotecard(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 3) && (TempInvItem.Type == (sbyte)Asset.AssetType.Landmark)) { InventoryItem temp = new InventoryLandmark(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 0) && (TempInvItem.Type == (sbyte)Asset.AssetType.Texture)) { InventoryItem temp = new InventoryImage(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 10) && (TempInvItem.Type == (sbyte)Asset.AssetType.LSLText)) { InventoryItem temp = new InventoryScript(this, TempInvItem); TempInvItem = temp; } if ((TempInvItem.InvType == 18) && ( (TempInvItem.Type == (sbyte)Asset.AssetType.Bodypart) || (TempInvItem.Type == (sbyte)Asset.AssetType.Clothing) ) ) { InventoryItem temp = new InventoryWearable(this, TempInvItem); TempInvItem = temp; } #endregion InvFolderUpdating._Contents.Add(TempInvItem); } } } } #endregion #region Handle Child Folders foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) { String IncomingName = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); LLUUID IncomingFolderID = folderBlock.FolderID; LLUUID IncomingParentID = folderBlock.ParentID; sbyte IncomingType = folderBlock.Type; // There is always an folder block, even if there isn't any folders // the "filler" block will not have a name if (folderBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; // See if the Incoming Folder already exists locally if (FoldersByUUID.ContainsKey(IncomingFolderID)) { InventoryFolder existingFolder = FoldersByUUID[IncomingFolderID]; existingFolder._Name = IncomingName; existingFolder._Type = IncomingType; // Check if parent of existing is the same as the incoming if (!existingFolder.ParentID.Equals(IncomingParentID)) { // Remove existing from old parent if (FoldersByUUID.ContainsKey(existingFolder.ParentID)) { InventoryFolder ExistingParent = FoldersByUUID[existingFolder.ParentID]; if (ExistingParent._Contents.Contains(existingFolder)) { ExistingParent._Contents.Remove(existingFolder); } } // Set existings parent to new existingFolder._ParentID = IncomingParentID; // Connect existing folder to parent specified in new if (FoldersByUUID.ContainsKey(IncomingParentID)) { InventoryFolder ExistingParent = FoldersByUUID[IncomingParentID]; if (!ExistingParent._Contents.Contains(existingFolder)) { ExistingParent._Contents.Add(existingFolder); } } } } else { InventoryFolder TempInvFolder = new InventoryFolder(this, IncomingName, IncomingFolderID, IncomingParentID, IncomingType); // Add folder to Parent if (InvFolderUpdating._Contents.Contains(TempInvFolder) == false) { InvFolderUpdating._Contents.Add(TempInvFolder); } // Add folder to local cache lookup FoldersByUUID[TempInvFolder.FolderID] = TempInvFolder; } // Do we recurse? if (CurrentlyDownloadingRequest.Recurse) { // It's not the root, should be safe to "recurse" if (!IncomingFolderID.Equals(slClient.Self.InventoryRootFolderUUID)) { FolderRequestPrepend(IncomingFolderID, CurrentlyDownloadingRequest.Recurse, CurrentlyDownloadingRequest.FetchFolders, CurrentlyDownloadingRequest.FetchItems, CurrentlyDownloadingRequest.Name + "/" + IncomingName); } } } } #endregion // Update total number of descendants expected , and update the total downloaded CurrentlyDownloadingRequest.Expected = iDescendentsExpected; CurrentlyDownloadingRequest.Received += iDescendentsReceivedThisBlock; CurrentlyDownloadingRequest.LastReceivedAtTick = Environment.TickCount; if ((iDescendentsExpected > 1) && (iDescendentsReceivedThisBlock == 0)) { slClient.Log("Received an InventoryDescendant packet where it indicated that there should be at least 1 descendant, but none were present... [" + CurrentlyDownloadingRequest.Name + "]", Helpers.LogLevel.Warning); CurrentlyDownloadingRequest.Expected = 0; } if (LogDescendantQueue) { slClient.Log("Received packet for: " + CurrentlyDownloadingRequest.ToString(), Helpers.LogLevel.Info); } // Check if we're finished if (CurrentlyDownloadingRequest.Received >= CurrentlyDownloadingRequest.Expected) { LogDescendantQueueEvent("Done downloading request: " + CurrentlyDownloadingRequest); // Singal anyone that was waiting for this request to finish CurrentlyDownloadingRequest.RequestComplete.Set(); // Raise an event for anyone that cares to listen for downloaded folder events if (OnRequestDownloadFinishedEvent != null) { DownloadRequest_EventArgs e = new DownloadRequest_EventArgs(); e.DownloadRequest = CurrentlyDownloadingRequest; FireRequestDownloadFinishedEvent(InvFolderUpdating, e); } // Set Inventory Manager state to reflect that we're done with the current download CurrentlyDownloadingAFolder = false; CurrentlyDownloadingRequest = null; } // Release so that we can let other things look at and modify what is currently downloading. CurrentlyDownloadingMutex.ReleaseMutex(); // If there's any more download requests queued, grab one, and go FolderRequestBegin(); }
/// <summary> /// Request a download of this folder's content information. /// </summary> /// <param name="Recurse">Indicate if we should recursively download content information.</param> /// <param name="Items">Indicate if item data should be downloaded too (true), or only folders(false)</param> /// <returns>The Request object for this download</returns> public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool items) { _Contents.Clear(); DownloadRequest_Folder dr = new DownloadRequest_Folder(FolderID, recurse, items); iManager.RequestFolder(dr); return dr; }
/// <summary> /// Returned in response to a InventoryDescendantRequest. Contains information about the /// contents of a folder. /// </summary> /// <seealso cref="InventoryManager.RequestFolder"/> /// <param name="packet"></param> /// <param name="simulator"></param> public void InventoryDescendentsHandler(Packet packet, Simulator simulator) { InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet; // The UUID of this folder. LLUUID uuidFolderID = reply.AgentData.FolderID; // Get the original Descendent Request for this Packet DownloadRequest_Folder dr = (DownloadRequest_Folder)FolderDownloadStatus[uuidFolderID]; // Update Inventory Manager's last tick point, used for timeouts and such LastPacketRecievedAtTick = Environment.TickCount; // Some temp variables to be reused as we're parsing the packet InventoryItem invItem; InventoryFolder invFolder; // Used to count the number of descendants received to see if we're finished or not. int iDescendentsExpected = reply.AgentData.Descendents; int iDescendentsReceivedThisBlock = 0; foreach (InventoryDescendentsPacket.ItemDataBlock itemBlock in reply.ItemData) { // There is always an item block, even if there isn't any items // the "filler" block will not have a name if (itemBlock.Name.Length != 0) { iDescendentsReceivedThisBlock++; if (itemBlock.ItemID == LLUUID.Zero) { // this shouldn't ever happen, unless you've uploaded an invalid item // to yourself while developping inventory code :-( } else { invItem = new InventoryItem(this, itemBlock); InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invItem.FolderID]; if (ifolder._Contents.Contains(invItem) == false) { if ((invItem.InvType == 7) && (invItem.Type == Asset.ASSET_TYPE_NOTECARD)) { InventoryItem temp = new InventoryNotecard(this, invItem); invItem = temp; } if ((invItem.InvType == 0) && (invItem.Type == Asset.ASSET_TYPE_IMAGE)) { InventoryItem temp = new InventoryImage(this, invItem); invItem = temp; } if ((invItem.InvType == 18) && ( (invItem.Type == Asset.ASSET_TYPE_WEARABLE_BODY) || (invItem.Type == Asset.ASSET_TYPE_WEARABLE_CLOTHING) ) ) { InventoryItem temp = new InventoryWearable(this, invItem); invItem = temp; } ifolder._Contents.Add(invItem); } } } } foreach (InventoryDescendentsPacket.FolderDataBlock folderBlock in reply.FolderData) { String name = System.Text.Encoding.UTF8.GetString(folderBlock.Name).Trim().Replace("\0", ""); LLUUID folderid = folderBlock.FolderID; LLUUID parentid = folderBlock.ParentID; // unused? sbyte type = folderBlock.Type; // There is always an folder block, even if there isn't any folders // the "filler" block will not have a name if (folderBlock.Name.Length != 0) { invFolder = new InventoryFolder(this, name, folderid, parentid); iDescendentsReceivedThisBlock++; // Add folder to Parent InventoryFolder ifolder = (InventoryFolder)htFoldersByUUID[invFolder.ParentID]; if (ifolder._Contents.Contains(invFolder) == false) { ifolder._Contents.Add(invFolder); } // Add folder to UUID Lookup htFoldersByUUID[invFolder.FolderID] = invFolder; // Do we recurse? if (dr.Recurse) { // It's not the root, should be safe to "recurse" if (!invFolder.FolderID.Equals(slClient.Self.InventoryRootFolderUUID)) { bool alreadyQueued = false; foreach (DownloadRequest_Folder adr in alFolderRequestQueue) { if (adr.FolderID == invFolder.FolderID) { alreadyQueued = true; break; } } if (!alreadyQueued) { alFolderRequestQueue.Add(new DownloadRequest_Folder(invFolder.FolderID)); } } } } } // Update download status for this folder if (iDescendentsReceivedThisBlock >= iDescendentsExpected) { // We received all the descendents we're expecting for this folder // in this packet, so go ahead and remove folder from status list. FolderDownloadStatus.Remove(uuidFolderID); dr.RequestComplete.Set(); } else { // This one packet didn't have all the descendents we're expecting // so update the total we're expecting, and update the total downloaded dr.Expected = iDescendentsExpected; dr.Received += iDescendentsReceivedThisBlock; dr.LastReceivedAtTick = Environment.TickCount; if (dr.Received >= dr.Expected) { // Looks like after updating, we have all the descendents, // remove from folder status. FolderDownloadStatus.Remove(uuidFolderID); dr.RequestComplete.Set(); } else { FolderDownloadStatus[uuidFolderID] = dr; } } }
public void DownloadInventory() { ClearState(); if (FolderDownloadStatus == null) { // Create status table FolderDownloadStatus = new Dictionary <LLUUID, DownloadRequest_Folder>(); } else { if (FolderDownloadStatus.Count != 0) { throw new Exception("Inventory Download requested while previous download in progress."); } } if (alFolderRequestQueue == null) { alFolderRequestQueue = new List <DownloadRequest_Folder>(); } // Set last packet received to now, just so out time-out timer works LastPacketRecievedAtTick = Environment.TickCount; // Send Packet requesting the root Folder, // this should recurse through all folders RequestFolder(new DownloadRequest_Folder(slClient.Self.InventoryRootFolderUUID)); while ((FolderDownloadStatus.Count > 0) || (alFolderRequestQueue.Count > 0)) { if (FolderDownloadStatus.Count == 0) { DownloadRequest_Folder dr = alFolderRequestQueue[0]; alFolderRequestQueue.RemoveAt(0); RequestFolder(dr); } int curTick = Environment.TickCount; if ((curTick - LastPacketRecievedAtTick) > 10000) { slClient.Log("Time-out while waiting for packets (" + ((curTick - LastPacketRecievedAtTick) / 1000) + " seconds since last packet)", Helpers.LogLevel.Warning); // have to make a seperate list otherwise we run into modifying the original array // while still enumerating it. List <DownloadRequest_Folder> alRestartList = new List <DownloadRequest_Folder>(); foreach (DownloadRequest_Folder dr in FolderDownloadStatus.Values) { alRestartList.Add(dr); } LastPacketRecievedAtTick = Environment.TickCount; foreach (DownloadRequest_Folder dr in alRestartList) { RequestFolder(dr); } } slClient.Tick(); } }