From 2159b3079ec8df2a7337a9d4ea54810b7028c4e1 Mon Sep 17 00:00:00 2001 From: gareth Date: Wed, 7 Mar 2007 19:07:00 +0000 Subject: fixed last screwup --- src/Assets/AssetCache.cs | 436 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 src/Assets/AssetCache.cs (limited to 'src/Assets') diff --git a/src/Assets/AssetCache.cs b/src/Assets/AssetCache.cs new file mode 100644 index 0000000..d35b482 --- /dev/null +++ b/src/Assets/AssetCache.cs @@ -0,0 +1,436 @@ +/* +* Copyright (c) OpenSim project, http://sim.opensecondlife.org/ +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.Collections.Generic; +using System.Threading; +using libsecondlife; +using libsecondlife.Packets; +using OpenSim; +using OpenSim.GridServers; + +namespace OpenSim.Assets +{ + /// + /// Manages local cache of assets and their sending to viewers. + /// + public class AssetCache : IAssetReceiver + { + public Dictionary Assets; + public Dictionary Textures; + + public List AssetRequests = new List(); //assets ready to be sent to viewers + public List TextureRequests = new List(); //textures ready to be sent + + public Dictionary RequestedAssets = new Dictionary(); //Assets requested from the asset server + public Dictionary RequestedTextures = new Dictionary(); //Textures requested from the asset server + + private IAssetServer _assetServer; + private Thread _assetCacheThread; + + /// + /// + /// + public AssetCache( IAssetServer assetServer) + { + _assetServer = assetServer; + _assetServer.SetReceiver(this); + Assets = new Dictionary (); + Textures = new Dictionary (); + this._assetCacheThread = new Thread( new ThreadStart(RunAssetManager)); + this._assetCacheThread.IsBackground = true; + this._assetCacheThread.Start(); + } + + /// + /// + /// + private void RunAssetManager() + { + this.ProcessAssetQueue(); + this.ProcessTextureQueue(); + Thread.Sleep(100); + } + + /// + /// + /// + private void ProcessTextureQueue() + { + if(this.TextureRequests.Count == 0) + { + //no requests waiting + return; + } + int num; + + if(this.TextureRequests.Count < 5) + { + //lower than 5 so do all of them + num = this.TextureRequests.Count; + } + else + { + num=5; + } + AssetRequest req; + for(int i = 0; i < num; i++) + { + req=(AssetRequest)this.TextureRequests[i]; + + if(req.PacketCounter == 0) + { + //first time for this request so send imagedata packet + if(req.NumPackets == 1) + { + //only one packet so send whole file + ImageDataPacket im = new ImageDataPacket(); + im.ImageID.Packets = 1; + im.ImageID.ID = req.ImageInfo.FullID; + im.ImageID.Size = (uint)req.ImageInfo.Data.Length; + im.ImageData.Data = req.ImageInfo.Data; + im.ImageID.Codec = 2; + req.RequestUser.OutPacket(im); + req.PacketCounter++; + //req.ImageInfo.l= time; + //System.Console.WriteLine("sent texture: "+req.image_info.FullID); + } + else + { + //more than one packet so split file up + ImageDataPacket im = new ImageDataPacket(); + im.ImageID.Packets = (ushort)req.NumPackets; + im.ImageID.ID = req.ImageInfo.FullID; + im.ImageID.Size = (uint)req.ImageInfo.Data.Length; + im.ImageData.Data = new byte[600]; + Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600); + im.ImageID.Codec = 2; + req.RequestUser.OutPacket(im); + req.PacketCounter++; + //req.ImageInfo.last_used = time; + //System.Console.WriteLine("sent first packet of texture: + } + } + else + { + //send imagepacket + //more than one packet so split file up + ImagePacketPacket im = new ImagePacketPacket(); + im.ImageID.Packet = (ushort)req.PacketCounter; + im.ImageID.ID = req.ImageInfo.FullID; + int size = req.ImageInfo.Data.Length - 600 - 1000*(req.PacketCounter - 1); + if(size > 1000) size = 1000; + im.ImageData.Data = new byte[size]; + Array.Copy(req.ImageInfo.Data, 600 + 1000*(req.PacketCounter - 1), im.ImageData.Data, 0, size); + req.RequestUser.OutPacket(im); + req.PacketCounter++; + //req.ImageInfo.last_used = time; + //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID); + } + } + + //remove requests that have been completed + int count = 0; + for(int i = 0; i < num; i++) + { + req=(AssetRequest)this.TextureRequests[count]; + if(req.PacketCounter == req.NumPackets) + { + this.TextureRequests.Remove(req); + } + else + { + count++; + } + } + + } + public void AssetReceived(AssetBase asset, bool IsTexture) + { + //check if it is a texture or not + //then add to the correct cache list + //then check for waiting requests for this asset/texture (in the Requested lists) + //and move those requests into the Requests list. + if(IsTexture) + { + TextureImage image = new TextureImage(asset); + this.Textures.Add(image.FullID, image); + if(this.RequestedTextures.ContainsKey(image.FullID)) + { + AssetRequest req = this.RequestedTextures[image.FullID]; + req.ImageInfo = image; + this.RequestedTextures.Remove(image.FullID); + this.TextureRequests.Add(req); + } + } + else + { + AssetInfo assetInf = new AssetInfo(asset); + this.Assets.Add(assetInf.FullID, assetInf); + if(this.RequestedAssets.ContainsKey(assetInf.FullID)) + { + AssetRequest req = this.RequestedAssets[assetInf.FullID]; + req.AssetInf = assetInf; + this.RequestedAssets.Remove(assetInf.FullID); + this.AssetRequests.Add(req); + } + } + } + + public void AssetNotFound(AssetBase asset) + { + //the asset server had no knowledge of requested asset + + } + + #region Assets + /// + /// + /// + /// + /// + public void AddAssetRequest(OpenSimClient userInfo, TransferRequestPacket transferRequest) + { + LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0); + //check to see if asset is in local cache, if not we need to request it from asset server. + if(!this.Assets.ContainsKey(requestID)) + { + //not found asset + // so request from asset server + AssetRequest request = new AssetRequest(); + request.RequestUser = userInfo; + request.RequestAssetID = requestID; + request.TransferRequestID = transferRequest.TransferInfo.TransferID; + this.RequestedAssets.Add(requestID,request); + this._assetServer.RequestAsset(requestID, false); + return; + } + //it is in our cache + AssetInfo asset = this.Assets[requestID]; + + //work out how many packets it should be sent in + // and add to the AssetRequests list + AssetRequest req = new AssetRequest(); + req.RequestUser = userInfo; + req.RequestAssetID = requestID; + req.TransferRequestID = transferRequest.TransferInfo.TransferID; + req.AssetInf = asset; + + if(asset.Data.LongLength>600) + { + //over 600 bytes so split up file + req.NumPackets = 1 + (int)(asset.Data.Length-600+999)/1000; + } + else + { + req.NumPackets = 1; + } + + this.AssetRequests.Add(req); + } + + /// + /// + /// + private void ProcessAssetQueue() + { + if(this.AssetRequests.Count == 0) + { + //no requests waiting + return; + } + int num; + + if(this.AssetRequests.Count < 5) + { + //lower than 5 so do all of them + num = this.AssetRequests.Count; + } + else + { + num=5; + } + AssetRequest req; + for(int i = 0; i < num; i++) + { + req=(AssetRequest)this.AssetRequests[i]; + + TransferInfoPacket Transfer = new TransferInfoPacket(); + Transfer.TransferInfo.ChannelType = 2; + Transfer.TransferInfo.Status = 0; + Transfer.TransferInfo.TargetType = 0; + Transfer.TransferInfo.Params = req.RequestAssetID.GetBytes(); + Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length; + Transfer.TransferInfo.TransferID = req.TransferRequestID; + req.RequestUser.OutPacket(Transfer); + + if(req.NumPackets == 1) + { + TransferPacketPacket TransferPacket = new TransferPacketPacket(); + TransferPacket.TransferData.Packet = 0; + TransferPacket.TransferData.ChannelType = 2; + TransferPacket.TransferData.TransferID=req.TransferRequestID; + TransferPacket.TransferData.Data = req.AssetInf.Data; + TransferPacket.TransferData.Status = 1; + req.RequestUser.OutPacket(TransferPacket); + } + else + { + //more than one packet so split file up , for now it can't be bigger than 2000 bytes + TransferPacketPacket TransferPacket = new TransferPacketPacket(); + TransferPacket.TransferData.Packet = 0; + TransferPacket.TransferData.ChannelType = 2; + TransferPacket.TransferData.TransferID=req.TransferRequestID; + byte[] chunk = new byte[1000]; + Array.Copy(req.AssetInf.Data,chunk,1000); + TransferPacket.TransferData.Data = chunk; + TransferPacket.TransferData.Status = 0; + req.RequestUser.OutPacket(TransferPacket); + + TransferPacket = new TransferPacketPacket(); + TransferPacket.TransferData.Packet = 1; + TransferPacket.TransferData.ChannelType = 2; + TransferPacket.TransferData.TransferID = req.TransferRequestID; + byte[] chunk1 = new byte[(req.AssetInf.Data.Length-1000)]; + Array.Copy(req.AssetInf.Data, 1000, chunk1, 0, chunk1.Length); + TransferPacket.TransferData.Data = chunk1; + TransferPacket.TransferData.Status = 1; + req.RequestUser.OutPacket(TransferPacket); + } + + } + + //remove requests that have been completed + for(int i = 0; i < num; i++) + { + this.AssetRequests.RemoveAt(0); + } + + } + + #endregion + + #region Textures + /// + /// + /// + /// + /// + public void AddTextureRequest(OpenSimClient userInfo, LLUUID imageID) + { + //check to see if texture is in local cache, if not request from asset server + if(!this.Textures.ContainsKey(imageID)) + { + //not is cache so request from asset server + AssetRequest request = new AssetRequest(); + request.RequestUser = userInfo; + request.RequestAssetID = imageID; + request.IsTextureRequest = true; + this.RequestedTextures.Add(imageID, request); + this._assetServer.RequestAsset(imageID, true); + return; + } + TextureImage imag = this.Textures[imageID]; + AssetRequest req = new AssetRequest(); + req.RequestUser = userInfo; + req.RequestAssetID = imageID; + req.IsTextureRequest = true; + req.ImageInfo = imag; + + if(imag.Data.LongLength>600) + { + //over 600 bytes so split up file + req.NumPackets = 1 + (int)(imag.Data.Length-600+999)/1000; + } + else + { + req.NumPackets = 1; + } + + this.TextureRequests.Add(req); + } + #endregion + + } + + public class AssetRequest + { + public OpenSimClient RequestUser; + public LLUUID RequestAssetID; + public AssetInfo AssetInf; + public TextureImage ImageInfo; + public LLUUID TransferRequestID; + public long DataPointer = 0; + public int NumPackets = 0; + public int PacketCounter = 0; + public bool IsTextureRequest; + //public bool AssetInCache; + //public int TimeRequested; + + public AssetRequest() + { + + } + } + + public class AssetInfo : AssetBase + { + public AssetInfo() + { + + } + + public AssetInfo(AssetBase aBase) + { + Data= aBase.Data; + FullID = aBase.FullID; + Type = aBase.Type; + InvType = aBase.InvType; + Name= aBase.Name; + Description = aBase.Description; + } + } + + public class TextureImage : AssetBase + { + public TextureImage() + { + + } + + public TextureImage(AssetBase aBase) + { + Data= aBase.Data; + FullID = aBase.FullID; + Type = aBase.Type; + InvType = aBase.InvType; + Name= aBase.Name; + Description = aBase.Description; + } + } + +} -- cgit v1.1