aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs')
-rw-r--r--OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs574
1 files changed, 574 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs b/OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs
new file mode 100644
index 0000000..ccebb24
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Assets/AssetCache.cs
@@ -0,0 +1,574 @@
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.Framework.Interfaces;
35using OpenSim.Framework.Types;
36using OpenSim.Framework.Utilities;
37
38namespace OpenSim.Assets
39{
40 /// <summary>
41 /// Manages local cache of assets and their sending to viewers.
42 /// </summary>
43 public class AssetCache : IAssetReceiver
44 {
45 public Dictionary<libsecondlife.LLUUID, AssetInfo> Assets;
46 public Dictionary<libsecondlife.LLUUID, TextureImage> Textures;
47
48 public List<AssetRequest> AssetRequests = new List<AssetRequest>(); //assets ready to be sent to viewers
49 public List<AssetRequest> TextureRequests = new List<AssetRequest>(); //textures ready to be sent
50
51 public Dictionary<LLUUID, AssetRequest> RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); //Assets requested from the asset server
52 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server
53
54 private IAssetServer _assetServer;
55 private Thread _assetCacheThread;
56 private LLUUID[] textureList = new LLUUID[5];
57
58 /// <summary>
59 ///
60 /// </summary>
61 public AssetCache(IAssetServer assetServer)
62 {
63 Console.WriteLine("Creating Asset cache");
64 _assetServer = assetServer;
65 _assetServer.SetReceiver(this);
66 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo>();
67 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage>();
68 this._assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
69 this._assetCacheThread.IsBackground = true;
70 this._assetCacheThread.Start();
71
72 }
73
74 /// <summary>
75 ///
76 /// </summary>
77 public void RunAssetManager()
78 {
79 while (true)
80 {
81 try
82 {
83 //Console.WriteLine("Asset cache loop");
84 this.ProcessAssetQueue();
85 this.ProcessTextureQueue();
86 Thread.Sleep(500);
87 }
88 catch (Exception e)
89 {
90 Console.WriteLine(e.Message);
91 }
92 }
93 }
94
95 public void LoadDefaultTextureSet()
96 {
97 //hack: so we can give each user a set of textures
98 textureList[0] = new LLUUID("00000000-0000-0000-9999-000000000001");
99 textureList[1] = new LLUUID("00000000-0000-0000-9999-000000000002");
100 textureList[2] = new LLUUID("00000000-0000-0000-9999-000000000003");
101 textureList[3] = new LLUUID("00000000-0000-0000-9999-000000000004");
102 textureList[4] = new LLUUID("00000000-0000-0000-9999-000000000005");
103
104 for (int i = 0; i < textureList.Length; i++)
105 {
106 this._assetServer.RequestAsset(textureList[i], true);
107 }
108
109 }
110
111 public AssetBase[] CreateNewInventorySet(LLUUID agentID)
112 {
113 AssetBase[] inventorySet = new AssetBase[this.textureList.Length];
114 for (int i = 0; i < textureList.Length; i++)
115 {
116 if (this.Textures.ContainsKey(textureList[i]))
117 {
118 inventorySet[i] = this.CloneImage(agentID, this.Textures[textureList[i]]);
119 TextureImage image = new TextureImage(inventorySet[i]);
120 this.Textures.Add(image.FullID, image);
121 this._assetServer.UploadNewAsset(image); //save the asset to the asset server
122 }
123 }
124 return inventorySet;
125 }
126
127 public AssetBase GetAsset(LLUUID assetID)
128 {
129 AssetBase asset = null;
130 if(this.Textures.ContainsKey(assetID))
131 {
132 asset = this.Textures[assetID];
133 }
134 else if (this.Assets.ContainsKey(assetID))
135 {
136 asset = this.Assets[assetID];
137 }
138 return asset;
139 }
140
141 public void AddAsset(AssetBase asset)
142 {
143 if (asset.Type == 0)
144 {
145 if (!this.Textures.ContainsKey(asset.FullID))
146 { //texture
147 TextureImage textur = new TextureImage(asset);
148 this.Textures.Add(textur.FullID, textur);
149 this._assetServer.UploadNewAsset(asset);
150 }
151 }
152 else
153 {
154 if (!this.Assets.ContainsKey(asset.FullID))
155 {
156 AssetInfo assetInf = new AssetInfo(asset);
157 this.Assets.Add(assetInf.FullID, assetInf);
158 this._assetServer.UploadNewAsset(asset);
159 }
160 }
161 }
162
163 /// <summary>
164 ///
165 /// </summary>
166 private void ProcessTextureQueue()
167 {
168 if (this.TextureRequests.Count == 0)
169 {
170 //no requests waiting
171 return;
172 }
173 int num;
174
175 if (this.TextureRequests.Count < 5)
176 {
177 //lower than 5 so do all of them
178 num = this.TextureRequests.Count;
179 }
180 else
181 {
182 num = 5;
183 }
184 AssetRequest req;
185 for (int i = 0; i < num; i++)
186 {
187 req = (AssetRequest)this.TextureRequests[i];
188 if (req.PacketCounter != req.NumPackets)
189 {
190 // if (req.ImageInfo.FullID == new LLUUID("00000000-0000-0000-5005-000000000005"))
191 if (req.PacketCounter == 0)
192 {
193 //first time for this request so send imagedata packet
194 if (req.NumPackets == 1)
195 {
196 //only one packet so send whole file
197 ImageDataPacket im = new ImageDataPacket();
198 im.ImageID.Packets = 1;
199 im.ImageID.ID = req.ImageInfo.FullID;
200 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
201 im.ImageData.Data = req.ImageInfo.Data;
202 im.ImageID.Codec = 2;
203 req.RequestUser.OutPacket(im);
204 req.PacketCounter++;
205 //req.ImageInfo.l= time;
206 //System.Console.WriteLine("sent texture: "+req.image_info.FullID);
207 }
208 else
209 {
210 //more than one packet so split file up
211 ImageDataPacket im = new ImageDataPacket();
212 im.ImageID.Packets = (ushort)req.NumPackets;
213 im.ImageID.ID = req.ImageInfo.FullID;
214 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
215 im.ImageData.Data = new byte[600];
216 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
217 im.ImageID.Codec = 2;
218 req.RequestUser.OutPacket(im);
219 req.PacketCounter++;
220 //req.ImageInfo.last_used = time;
221 //System.Console.WriteLine("sent first packet of texture:
222 }
223 }
224 else
225 {
226 //send imagepacket
227 //more than one packet so split file up
228 ImagePacketPacket im = new ImagePacketPacket();
229 im.ImageID.Packet = (ushort)req.PacketCounter;
230 im.ImageID.ID = req.ImageInfo.FullID;
231 int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1);
232 if (size > 1000) size = 1000;
233 im.ImageData.Data = new byte[size];
234 Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size);
235 req.RequestUser.OutPacket(im);
236 req.PacketCounter++;
237 //req.ImageInfo.last_used = time;
238 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
239 }
240 }
241 }
242
243 //remove requests that have been completed
244 int count = 0;
245 for (int i = 0; i < num; i++)
246 {
247 if (this.TextureRequests.Count > count)
248 {
249 req = (AssetRequest)this.TextureRequests[count];
250 if (req.PacketCounter == req.NumPackets)
251 {
252 this.TextureRequests.Remove(req);
253 }
254 else
255 {
256 count++;
257 }
258 }
259 }
260
261 }
262 public void AssetReceived(AssetBase asset, bool IsTexture)
263 {
264 if (asset.FullID != LLUUID.Zero) // if it is set to zero then the asset wasn't found by the server
265 {
266 //check if it is a texture or not
267 //then add to the correct cache list
268 //then check for waiting requests for this asset/texture (in the Requested lists)
269 //and move those requests into the Requests list.
270 if (IsTexture)
271 {
272 TextureImage image = new TextureImage(asset);
273 this.Textures.Add(image.FullID, image);
274 if (this.RequestedTextures.ContainsKey(image.FullID))
275 {
276 AssetRequest req = this.RequestedTextures[image.FullID];
277 req.ImageInfo = image;
278 if (image.Data.LongLength > 600)
279 {
280 //over 600 bytes so split up file
281 req.NumPackets = 1 + (int)(image.Data.Length - 600 + 999) / 1000;
282 }
283 else
284 {
285 req.NumPackets = 1;
286 }
287 this.RequestedTextures.Remove(image.FullID);
288 this.TextureRequests.Add(req);
289 }
290 }
291 else
292 {
293 AssetInfo assetInf = new AssetInfo(asset);
294 this.Assets.Add(assetInf.FullID, assetInf);
295 if (this.RequestedAssets.ContainsKey(assetInf.FullID))
296 {
297 AssetRequest req = this.RequestedAssets[assetInf.FullID];
298 req.AssetInf = assetInf;
299 if (assetInf.Data.LongLength > 600)
300 {
301 //over 600 bytes so split up file
302 req.NumPackets = 1 + (int)(assetInf.Data.Length - 600 + 999) / 1000;
303 }
304 else
305 {
306 req.NumPackets = 1;
307 }
308 this.RequestedAssets.Remove(assetInf.FullID);
309 this.AssetRequests.Add(req);
310 }
311 }
312 }
313 }
314
315 public void AssetNotFound(AssetBase asset)
316 {
317 //the asset server had no knowledge of requested asset
318
319 }
320
321 #region Assets
322 /// <summary>
323 ///
324 /// </summary>
325 /// <param name="userInfo"></param>
326 /// <param name="transferRequest"></param>
327 public void AddAssetRequest(ClientView userInfo, TransferRequestPacket transferRequest)
328 {
329 LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
330 //check to see if asset is in local cache, if not we need to request it from asset server.
331 if (!this.Assets.ContainsKey(requestID))
332 {
333 //not found asset
334 // so request from asset server
335 if (!this.RequestedAssets.ContainsKey(requestID))
336 {
337 AssetRequest request = new AssetRequest();
338 request.RequestUser = userInfo;
339 request.RequestAssetID = requestID;
340 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
341 this.RequestedAssets.Add(requestID, request);
342 this._assetServer.RequestAsset(requestID, false);
343 }
344 return;
345 }
346 //it is in our cache
347 AssetInfo asset = this.Assets[requestID];
348
349 //work out how many packets it should be sent in
350 // and add to the AssetRequests list
351 AssetRequest req = new AssetRequest();
352 req.RequestUser = userInfo;
353 req.RequestAssetID = requestID;
354 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
355 req.AssetInf = asset;
356
357 if (asset.Data.LongLength > 600)
358 {
359 //over 600 bytes so split up file
360 req.NumPackets = 1 + (int)(asset.Data.Length - 600 + 999) / 1000;
361 }
362 else
363 {
364 req.NumPackets = 1;
365 }
366
367 this.AssetRequests.Add(req);
368 }
369
370 /// <summary>
371 ///
372 /// </summary>
373 private void ProcessAssetQueue()
374 {
375 if (this.AssetRequests.Count == 0)
376 {
377 //no requests waiting
378 return;
379 }
380 int num;
381
382 if (this.AssetRequests.Count < 5)
383 {
384 //lower than 5 so do all of them
385 num = this.AssetRequests.Count;
386 }
387 else
388 {
389 num = 5;
390 }
391 AssetRequest req;
392 for (int i = 0; i < num; i++)
393 {
394 req = (AssetRequest)this.AssetRequests[i];
395
396 TransferInfoPacket Transfer = new TransferInfoPacket();
397 Transfer.TransferInfo.ChannelType = 2;
398 Transfer.TransferInfo.Status = 0;
399 Transfer.TransferInfo.TargetType = 0;
400 Transfer.TransferInfo.Params = req.RequestAssetID.GetBytes();
401 Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
402 Transfer.TransferInfo.TransferID = req.TransferRequestID;
403 req.RequestUser.OutPacket(Transfer);
404
405 if (req.NumPackets == 1)
406 {
407 TransferPacketPacket TransferPacket = new TransferPacketPacket();
408 TransferPacket.TransferData.Packet = 0;
409 TransferPacket.TransferData.ChannelType = 2;
410 TransferPacket.TransferData.TransferID = req.TransferRequestID;
411 TransferPacket.TransferData.Data = req.AssetInf.Data;
412 TransferPacket.TransferData.Status = 1;
413 req.RequestUser.OutPacket(TransferPacket);
414 }
415 else
416 {
417 //more than one packet so split file up , for now it can't be bigger than 2000 bytes
418 TransferPacketPacket TransferPacket = new TransferPacketPacket();
419 TransferPacket.TransferData.Packet = 0;
420 TransferPacket.TransferData.ChannelType = 2;
421 TransferPacket.TransferData.TransferID = req.TransferRequestID;
422 byte[] chunk = new byte[1000];
423 Array.Copy(req.AssetInf.Data, chunk, 1000);
424 TransferPacket.TransferData.Data = chunk;
425 TransferPacket.TransferData.Status = 0;
426 req.RequestUser.OutPacket(TransferPacket);
427
428 TransferPacket = new TransferPacketPacket();
429 TransferPacket.TransferData.Packet = 1;
430 TransferPacket.TransferData.ChannelType = 2;
431 TransferPacket.TransferData.TransferID = req.TransferRequestID;
432 byte[] chunk1 = new byte[(req.AssetInf.Data.Length - 1000)];
433 Array.Copy(req.AssetInf.Data, 1000, chunk1, 0, chunk1.Length);
434 TransferPacket.TransferData.Data = chunk1;
435 TransferPacket.TransferData.Status = 1;
436 req.RequestUser.OutPacket(TransferPacket);
437 }
438
439 }
440
441 //remove requests that have been completed
442 for (int i = 0; i < num; i++)
443 {
444 this.AssetRequests.RemoveAt(0);
445 }
446
447 }
448
449 public AssetInfo CloneAsset(LLUUID newOwner, AssetInfo sourceAsset)
450 {
451 AssetInfo newAsset = new AssetInfo();
452 newAsset.Data = new byte[sourceAsset.Data.Length];
453 Array.Copy(sourceAsset.Data, newAsset.Data, sourceAsset.Data.Length);
454 newAsset.FullID = LLUUID.Random();
455 newAsset.Type = sourceAsset.Type;
456 newAsset.InvType = sourceAsset.InvType;
457 return (newAsset);
458 }
459 #endregion
460
461 #region Textures
462 /// <summary>
463 ///
464 /// </summary>
465 /// <param name="userInfo"></param>
466 /// <param name="imageID"></param>
467 public void AddTextureRequest(ClientView userInfo, LLUUID imageID)
468 {
469 //check to see if texture is in local cache, if not request from asset server
470 if (!this.Textures.ContainsKey(imageID))
471 {
472 if (!this.RequestedTextures.ContainsKey(imageID))
473 {
474 //not is cache so request from asset server
475 AssetRequest request = new AssetRequest();
476 request.RequestUser = userInfo;
477 request.RequestAssetID = imageID;
478 request.IsTextureRequest = true;
479 this.RequestedTextures.Add(imageID, request);
480 this._assetServer.RequestAsset(imageID, true);
481 }
482 return;
483 }
484
485 TextureImage imag = this.Textures[imageID];
486 AssetRequest req = new AssetRequest();
487 req.RequestUser = userInfo;
488 req.RequestAssetID = imageID;
489 req.IsTextureRequest = true;
490 req.ImageInfo = imag;
491
492 if (imag.Data.LongLength > 600)
493 {
494 //over 600 bytes so split up file
495 req.NumPackets = 1 + (int)(imag.Data.Length - 600 + 999) / 1000;
496 }
497 else
498 {
499 req.NumPackets = 1;
500 }
501 this.TextureRequests.Add(req);
502 }
503
504 public TextureImage CloneImage(LLUUID newOwner, TextureImage source)
505 {
506 TextureImage newImage = new TextureImage();
507 newImage.Data = new byte[source.Data.Length];
508 Array.Copy(source.Data, newImage.Data, source.Data.Length);
509 //newImage.filename = source.filename;
510 newImage.FullID = LLUUID.Random();
511 newImage.Name = source.Name;
512 return (newImage);
513 }
514 #endregion
515
516 }
517
518 public class AssetRequest
519 {
520 public ClientView RequestUser;
521 public LLUUID RequestAssetID;
522 public AssetInfo AssetInf;
523 public TextureImage ImageInfo;
524 public LLUUID TransferRequestID;
525 public long DataPointer = 0;
526 public int NumPackets = 0;
527 public int PacketCounter = 0;
528 public bool IsTextureRequest;
529 //public bool AssetInCache;
530 //public int TimeRequested;
531
532 public AssetRequest()
533 {
534
535 }
536 }
537
538 public class AssetInfo : AssetBase
539 {
540 public AssetInfo()
541 {
542
543 }
544
545 public AssetInfo(AssetBase aBase)
546 {
547 Data = aBase.Data;
548 FullID = aBase.FullID;
549 Type = aBase.Type;
550 InvType = aBase.InvType;
551 Name = aBase.Name;
552 Description = aBase.Description;
553 }
554 }
555
556 public class TextureImage : AssetBase
557 {
558 public TextureImage()
559 {
560
561 }
562
563 public TextureImage(AssetBase aBase)
564 {
565 Data = aBase.Data;
566 FullID = aBase.FullID;
567 Type = aBase.Type;
568 InvType = aBase.InvType;
569 Name = aBase.Name;
570 Description = aBase.Description;
571 }
572 }
573
574}