aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/Assets/AssetCache.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Assets/AssetCache.cs')
-rw-r--r--src/Assets/AssetCache.cs436
1 files changed, 436 insertions, 0 deletions
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 @@
1/*
2* Copyright (c) OpenSim project, http://sim.opensecondlife.org/
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are met:
6* * Redistributions of source code must retain the above copyright
7* notice, this list of conditions and the following disclaimer.
8* * Redistributions in binary form must reproduce the above copyright
9* notice, this list of conditions and the following disclaimer in the
10* documentation and/or other materials provided with the distribution.
11* * Neither the name of the <organization> nor the
12* names of its contributors may be used to endorse or promote products
13* derived from this software without specific prior written permission.
14*
15* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
16* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
19* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*
26*/
27
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using libsecondlife;
32using libsecondlife.Packets;
33using OpenSim;
34using OpenSim.GridServers;
35
36namespace OpenSim.Assets
37{
38 /// <summary>
39 /// Manages local cache of assets and their sending to viewers.
40 /// </summary>
41 public class AssetCache : IAssetReceiver
42 {
43 public Dictionary<libsecondlife.LLUUID, AssetInfo> Assets;
44 public Dictionary<libsecondlife.LLUUID, TextureImage> Textures;
45
46 public List<AssetRequest> AssetRequests = new List<AssetRequest>(); //assets ready to be sent to viewers
47 public List<AssetRequest> TextureRequests = new List<AssetRequest>(); //textures ready to be sent
48
49 public Dictionary<LLUUID, AssetRequest> RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); //Assets requested from the asset server
50 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server
51
52 private IAssetServer _assetServer;
53 private Thread _assetCacheThread;
54
55 /// <summary>
56 ///
57 /// </summary>
58 public AssetCache( IAssetServer assetServer)
59 {
60 _assetServer = assetServer;
61 _assetServer.SetReceiver(this);
62 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo> ();
63 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage> ();
64 this._assetCacheThread = new Thread( new ThreadStart(RunAssetManager));
65 this._assetCacheThread.IsBackground = true;
66 this._assetCacheThread.Start();
67 }
68
69 /// <summary>
70 ///
71 /// </summary>
72 private void RunAssetManager()
73 {
74 this.ProcessAssetQueue();
75 this.ProcessTextureQueue();
76 Thread.Sleep(100);
77 }
78
79 /// <summary>
80 ///
81 /// </summary>
82 private void ProcessTextureQueue()
83 {
84 if(this.TextureRequests.Count == 0)
85 {
86 //no requests waiting
87 return;
88 }
89 int num;
90
91 if(this.TextureRequests.Count < 5)
92 {
93 //lower than 5 so do all of them
94 num = this.TextureRequests.Count;
95 }
96 else
97 {
98 num=5;
99 }
100 AssetRequest req;
101 for(int i = 0; i < num; i++)
102 {
103 req=(AssetRequest)this.TextureRequests[i];
104
105 if(req.PacketCounter == 0)
106 {
107 //first time for this request so send imagedata packet
108 if(req.NumPackets == 1)
109 {
110 //only one packet so send whole file
111 ImageDataPacket im = new ImageDataPacket();
112 im.ImageID.Packets = 1;
113 im.ImageID.ID = req.ImageInfo.FullID;
114 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
115 im.ImageData.Data = req.ImageInfo.Data;
116 im.ImageID.Codec = 2;
117 req.RequestUser.OutPacket(im);
118 req.PacketCounter++;
119 //req.ImageInfo.l= time;
120 //System.Console.WriteLine("sent texture: "+req.image_info.FullID);
121 }
122 else
123 {
124 //more than one packet so split file up
125 ImageDataPacket im = new ImageDataPacket();
126 im.ImageID.Packets = (ushort)req.NumPackets;
127 im.ImageID.ID = req.ImageInfo.FullID;
128 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
129 im.ImageData.Data = new byte[600];
130 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
131 im.ImageID.Codec = 2;
132 req.RequestUser.OutPacket(im);
133 req.PacketCounter++;
134 //req.ImageInfo.last_used = time;
135 //System.Console.WriteLine("sent first packet of texture:
136 }
137 }
138 else
139 {
140 //send imagepacket
141 //more than one packet so split file up
142 ImagePacketPacket im = new ImagePacketPacket();
143 im.ImageID.Packet = (ushort)req.PacketCounter;
144 im.ImageID.ID = req.ImageInfo.FullID;
145 int size = req.ImageInfo.Data.Length - 600 - 1000*(req.PacketCounter - 1);
146 if(size > 1000) size = 1000;
147 im.ImageData.Data = new byte[size];
148 Array.Copy(req.ImageInfo.Data, 600 + 1000*(req.PacketCounter - 1), im.ImageData.Data, 0, size);
149 req.RequestUser.OutPacket(im);
150 req.PacketCounter++;
151 //req.ImageInfo.last_used = time;
152 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
153 }
154 }
155
156 //remove requests that have been completed
157 int count = 0;
158 for(int i = 0; i < num; i++)
159 {
160 req=(AssetRequest)this.TextureRequests[count];
161 if(req.PacketCounter == req.NumPackets)
162 {
163 this.TextureRequests.Remove(req);
164 }
165 else
166 {
167 count++;
168 }
169 }
170
171 }
172 public void AssetReceived(AssetBase asset, bool IsTexture)
173 {
174 //check if it is a texture or not
175 //then add to the correct cache list
176 //then check for waiting requests for this asset/texture (in the Requested lists)
177 //and move those requests into the Requests list.
178 if(IsTexture)
179 {
180 TextureImage image = new TextureImage(asset);
181 this.Textures.Add(image.FullID, image);
182 if(this.RequestedTextures.ContainsKey(image.FullID))
183 {
184 AssetRequest req = this.RequestedTextures[image.FullID];
185 req.ImageInfo = image;
186 this.RequestedTextures.Remove(image.FullID);
187 this.TextureRequests.Add(req);
188 }
189 }
190 else
191 {
192 AssetInfo assetInf = new AssetInfo(asset);
193 this.Assets.Add(assetInf.FullID, assetInf);
194 if(this.RequestedAssets.ContainsKey(assetInf.FullID))
195 {
196 AssetRequest req = this.RequestedAssets[assetInf.FullID];
197 req.AssetInf = assetInf;
198 this.RequestedAssets.Remove(assetInf.FullID);
199 this.AssetRequests.Add(req);
200 }
201 }
202 }
203
204 public void AssetNotFound(AssetBase asset)
205 {
206 //the asset server had no knowledge of requested asset
207
208 }
209
210 #region Assets
211 /// <summary>
212 ///
213 /// </summary>
214 /// <param name="userInfo"></param>
215 /// <param name="transferRequest"></param>
216 public void AddAssetRequest(OpenSimClient userInfo, TransferRequestPacket transferRequest)
217 {
218 LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
219 //check to see if asset is in local cache, if not we need to request it from asset server.
220 if(!this.Assets.ContainsKey(requestID))
221 {
222 //not found asset
223 // so request from asset server
224 AssetRequest request = new AssetRequest();
225 request.RequestUser = userInfo;
226 request.RequestAssetID = requestID;
227 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
228 this.RequestedAssets.Add(requestID,request);
229 this._assetServer.RequestAsset(requestID, false);
230 return;
231 }
232 //it is in our cache
233 AssetInfo asset = this.Assets[requestID];
234
235 //work out how many packets it should be sent in
236 // and add to the AssetRequests list
237 AssetRequest req = new AssetRequest();
238 req.RequestUser = userInfo;
239 req.RequestAssetID = requestID;
240 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
241 req.AssetInf = asset;
242
243 if(asset.Data.LongLength>600)
244 {
245 //over 600 bytes so split up file
246 req.NumPackets = 1 + (int)(asset.Data.Length-600+999)/1000;
247 }
248 else
249 {
250 req.NumPackets = 1;
251 }
252
253 this.AssetRequests.Add(req);
254 }
255
256 /// <summary>
257 ///
258 /// </summary>
259 private void ProcessAssetQueue()
260 {
261 if(this.AssetRequests.Count == 0)
262 {
263 //no requests waiting
264 return;
265 }
266 int num;
267
268 if(this.AssetRequests.Count < 5)
269 {
270 //lower than 5 so do all of them
271 num = this.AssetRequests.Count;
272 }
273 else
274 {
275 num=5;
276 }
277 AssetRequest req;
278 for(int i = 0; i < num; i++)
279 {
280 req=(AssetRequest)this.AssetRequests[i];
281
282 TransferInfoPacket Transfer = new TransferInfoPacket();
283 Transfer.TransferInfo.ChannelType = 2;
284 Transfer.TransferInfo.Status = 0;
285 Transfer.TransferInfo.TargetType = 0;
286 Transfer.TransferInfo.Params = req.RequestAssetID.GetBytes();
287 Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
288 Transfer.TransferInfo.TransferID = req.TransferRequestID;
289 req.RequestUser.OutPacket(Transfer);
290
291 if(req.NumPackets == 1)
292 {
293 TransferPacketPacket TransferPacket = new TransferPacketPacket();
294 TransferPacket.TransferData.Packet = 0;
295 TransferPacket.TransferData.ChannelType = 2;
296 TransferPacket.TransferData.TransferID=req.TransferRequestID;
297 TransferPacket.TransferData.Data = req.AssetInf.Data;
298 TransferPacket.TransferData.Status = 1;
299 req.RequestUser.OutPacket(TransferPacket);
300 }
301 else
302 {
303 //more than one packet so split file up , for now it can't be bigger than 2000 bytes
304 TransferPacketPacket TransferPacket = new TransferPacketPacket();
305 TransferPacket.TransferData.Packet = 0;
306 TransferPacket.TransferData.ChannelType = 2;
307 TransferPacket.TransferData.TransferID=req.TransferRequestID;
308 byte[] chunk = new byte[1000];
309 Array.Copy(req.AssetInf.Data,chunk,1000);
310 TransferPacket.TransferData.Data = chunk;
311 TransferPacket.TransferData.Status = 0;
312 req.RequestUser.OutPacket(TransferPacket);
313
314 TransferPacket = new TransferPacketPacket();
315 TransferPacket.TransferData.Packet = 1;
316 TransferPacket.TransferData.ChannelType = 2;
317 TransferPacket.TransferData.TransferID = req.TransferRequestID;
318 byte[] chunk1 = new byte[(req.AssetInf.Data.Length-1000)];
319 Array.Copy(req.AssetInf.Data, 1000, chunk1, 0, chunk1.Length);
320 TransferPacket.TransferData.Data = chunk1;
321 TransferPacket.TransferData.Status = 1;
322 req.RequestUser.OutPacket(TransferPacket);
323 }
324
325 }
326
327 //remove requests that have been completed
328 for(int i = 0; i < num; i++)
329 {
330 this.AssetRequests.RemoveAt(0);
331 }
332
333 }
334
335 #endregion
336
337 #region Textures
338 /// <summary>
339 ///
340 /// </summary>
341 /// <param name="userInfo"></param>
342 /// <param name="imageID"></param>
343 public void AddTextureRequest(OpenSimClient userInfo, LLUUID imageID)
344 {
345 //check to see if texture is in local cache, if not request from asset server
346 if(!this.Textures.ContainsKey(imageID))
347 {
348 //not is cache so request from asset server
349 AssetRequest request = new AssetRequest();
350 request.RequestUser = userInfo;
351 request.RequestAssetID = imageID;
352 request.IsTextureRequest = true;
353 this.RequestedTextures.Add(imageID, request);
354 this._assetServer.RequestAsset(imageID, true);
355 return;
356 }
357 TextureImage imag = this.Textures[imageID];
358 AssetRequest req = new AssetRequest();
359 req.RequestUser = userInfo;
360 req.RequestAssetID = imageID;
361 req.IsTextureRequest = true;
362 req.ImageInfo = imag;
363
364 if(imag.Data.LongLength>600)
365 {
366 //over 600 bytes so split up file
367 req.NumPackets = 1 + (int)(imag.Data.Length-600+999)/1000;
368 }
369 else
370 {
371 req.NumPackets = 1;
372 }
373
374 this.TextureRequests.Add(req);
375 }
376 #endregion
377
378 }
379
380 public class AssetRequest
381 {
382 public OpenSimClient RequestUser;
383 public LLUUID RequestAssetID;
384 public AssetInfo AssetInf;
385 public TextureImage ImageInfo;
386 public LLUUID TransferRequestID;
387 public long DataPointer = 0;
388 public int NumPackets = 0;
389 public int PacketCounter = 0;
390 public bool IsTextureRequest;
391 //public bool AssetInCache;
392 //public int TimeRequested;
393
394 public AssetRequest()
395 {
396
397 }
398 }
399
400 public class AssetInfo : AssetBase
401 {
402 public AssetInfo()
403 {
404
405 }
406
407 public AssetInfo(AssetBase aBase)
408 {
409 Data= aBase.Data;
410 FullID = aBase.FullID;
411 Type = aBase.Type;
412 InvType = aBase.InvType;
413 Name= aBase.Name;
414 Description = aBase.Description;
415 }
416 }
417
418 public class TextureImage : AssetBase
419 {
420 public TextureImage()
421 {
422
423 }
424
425 public TextureImage(AssetBase aBase)
426 {
427 Data= aBase.Data;
428 FullID = aBase.FullID;
429 Type = aBase.Type;
430 InvType = aBase.InvType;
431 Name= aBase.Name;
432 Description = aBase.Description;
433 }
434 }
435
436}