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