aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.Caches/AssetCache.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/OpenSim.Caches/AssetCache.cs')
-rw-r--r--OpenSim/OpenSim.Caches/AssetCache.cs618
1 files changed, 618 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.Caches/AssetCache.cs b/OpenSim/OpenSim.Caches/AssetCache.cs
new file mode 100644
index 0000000..fb7fd68
--- /dev/null
+++ b/OpenSim/OpenSim.Caches/AssetCache.cs
@@ -0,0 +1,618 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29using System;
30using System.Collections.Generic;
31using System.Threading;
32using System.Reflection;
33using libsecondlife;
34using libsecondlife.Packets;
35using OpenSim.Framework.Interfaces;
36using OpenSim.Framework.Types;
37using OpenSim.Framework.Utilities;
38
39namespace OpenSim.Assets
40{
41 /// <summary>
42 /// Manages local cache of assets and their sending to viewers.
43 /// </summary>
44 public class AssetCache : IAssetReceiver
45 {
46 public Dictionary<libsecondlife.LLUUID, AssetInfo> Assets;
47 public Dictionary<libsecondlife.LLUUID, TextureImage> Textures;
48
49 public List<AssetRequest> AssetRequests = new List<AssetRequest>(); //assets ready to be sent to viewers
50 public List<AssetRequest> TextureRequests = new List<AssetRequest>(); //textures ready to be sent
51
52 public Dictionary<LLUUID, AssetRequest> RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); //Assets requested from the asset server
53 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server
54
55 private IAssetServer _assetServer;
56 private Thread _assetCacheThread;
57 private LLUUID[] textureList = new LLUUID[5];
58
59 /// <summary>
60 ///
61 /// </summary>
62 public AssetCache(IAssetServer assetServer)
63 {
64 Console.WriteLine("Creating Asset cache");
65 _assetServer = assetServer;
66 _assetServer.SetReceiver(this);
67 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo>();
68 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage>();
69 this._assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
70 this._assetCacheThread.IsBackground = true;
71 this._assetCacheThread.Start();
72
73 }
74
75 public AssetCache(string assetServerDLLName, string assetServerURL, string assetServerKey)
76 {
77 Console.WriteLine("Creating Asset cache");
78 _assetServer = this.LoadAssetDll(assetServerDLLName);
79 _assetServer.SetServerInfo(assetServerURL, assetServerKey);
80 _assetServer.SetReceiver(this);
81 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo>();
82 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage>();
83 this._assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
84 this._assetCacheThread.IsBackground = true;
85 this._assetCacheThread.Start();
86
87 }
88
89 /// <summary>
90 ///
91 /// </summary>
92 public void RunAssetManager()
93 {
94 while (true)
95 {
96 try
97 {
98 //Console.WriteLine("Asset cache loop");
99 this.ProcessAssetQueue();
100 this.ProcessTextureQueue();
101 Thread.Sleep(500);
102 }
103 catch (Exception e)
104 {
105 Console.WriteLine(e.Message);
106 }
107 }
108 }
109
110 public void LoadDefaultTextureSet()
111 {
112 //hack: so we can give each user a set of textures
113 textureList[0] = new LLUUID("00000000-0000-0000-9999-000000000001");
114 textureList[1] = new LLUUID("00000000-0000-0000-9999-000000000002");
115 textureList[2] = new LLUUID("00000000-0000-0000-9999-000000000003");
116 textureList[3] = new LLUUID("00000000-0000-0000-9999-000000000004");
117 textureList[4] = new LLUUID("00000000-0000-0000-9999-000000000005");
118
119 for (int i = 0; i < textureList.Length; i++)
120 {
121 this._assetServer.RequestAsset(textureList[i], true);
122 }
123
124 }
125
126 public AssetBase[] CreateNewInventorySet(LLUUID agentID)
127 {
128 AssetBase[] inventorySet = new AssetBase[this.textureList.Length];
129 for (int i = 0; i < textureList.Length; i++)
130 {
131 if (this.Textures.ContainsKey(textureList[i]))
132 {
133 inventorySet[i] = this.CloneImage(agentID, this.Textures[textureList[i]]);
134 TextureImage image = new TextureImage(inventorySet[i]);
135 this.Textures.Add(image.FullID, image);
136 this._assetServer.UploadNewAsset(image); //save the asset to the asset server
137 }
138 }
139 return inventorySet;
140 }
141
142 public AssetBase GetAsset(LLUUID assetID)
143 {
144 AssetBase asset = null;
145 if (this.Textures.ContainsKey(assetID))
146 {
147 asset = this.Textures[assetID];
148 }
149 else if (this.Assets.ContainsKey(assetID))
150 {
151 asset = this.Assets[assetID];
152 }
153 return asset;
154 }
155
156 public void AddAsset(AssetBase asset)
157 {
158 if (asset.Type == 0)
159 {
160 if (!this.Textures.ContainsKey(asset.FullID))
161 { //texture
162 TextureImage textur = new TextureImage(asset);
163 this.Textures.Add(textur.FullID, textur);
164 this._assetServer.UploadNewAsset(asset);
165 }
166 }
167 else
168 {
169 if (!this.Assets.ContainsKey(asset.FullID))
170 {
171 AssetInfo assetInf = new AssetInfo(asset);
172 this.Assets.Add(assetInf.FullID, assetInf);
173 this._assetServer.UploadNewAsset(asset);
174 }
175 }
176 }
177
178 /// <summary>
179 ///
180 /// </summary>
181 private void ProcessTextureQueue()
182 {
183 if (this.TextureRequests.Count == 0)
184 {
185 //no requests waiting
186 return;
187 }
188 int num;
189
190 if (this.TextureRequests.Count < 5)
191 {
192 //lower than 5 so do all of them
193 num = this.TextureRequests.Count;
194 }
195 else
196 {
197 num = 5;
198 }
199 AssetRequest req;
200 for (int i = 0; i < num; i++)
201 {
202 req = (AssetRequest)this.TextureRequests[i];
203 if (req.PacketCounter != req.NumPackets)
204 {
205 // if (req.ImageInfo.FullID == new LLUUID("00000000-0000-0000-5005-000000000005"))
206 if (req.PacketCounter == 0)
207 {
208 //first time for this request so send imagedata packet
209 if (req.NumPackets == 1)
210 {
211 //only one packet so send whole file
212 ImageDataPacket im = new ImageDataPacket();
213 im.ImageID.Packets = 1;
214 im.ImageID.ID = req.ImageInfo.FullID;
215 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
216 im.ImageData.Data = req.ImageInfo.Data;
217 im.ImageID.Codec = 2;
218 req.RequestUser.OutPacket(im);
219 req.PacketCounter++;
220 //req.ImageInfo.l= time;
221 //System.Console.WriteLine("sent texture: "+req.image_info.FullID);
222 }
223 else
224 {
225 //more than one packet so split file up
226 ImageDataPacket im = new ImageDataPacket();
227 im.ImageID.Packets = (ushort)req.NumPackets;
228 im.ImageID.ID = req.ImageInfo.FullID;
229 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
230 im.ImageData.Data = new byte[600];
231 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
232 im.ImageID.Codec = 2;
233 req.RequestUser.OutPacket(im);
234 req.PacketCounter++;
235 //req.ImageInfo.last_used = time;
236 //System.Console.WriteLine("sent first packet of texture:
237 }
238 }
239 else
240 {
241 //send imagepacket
242 //more than one packet so split file up
243 ImagePacketPacket im = new ImagePacketPacket();
244 im.ImageID.Packet = (ushort)req.PacketCounter;
245 im.ImageID.ID = req.ImageInfo.FullID;
246 int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1);
247 if (size > 1000) size = 1000;
248 im.ImageData.Data = new byte[size];
249 Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size);
250 req.RequestUser.OutPacket(im);
251 req.PacketCounter++;
252 //req.ImageInfo.last_used = time;
253 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
254 }
255 }
256 }
257
258 //remove requests that have been completed
259 int count = 0;
260 for (int i = 0; i < num; i++)
261 {
262 if (this.TextureRequests.Count > count)
263 {
264 req = (AssetRequest)this.TextureRequests[count];
265 if (req.PacketCounter == req.NumPackets)
266 {
267 this.TextureRequests.Remove(req);
268 }
269 else
270 {
271 count++;
272 }
273 }
274 }
275
276 }
277 public void AssetReceived(AssetBase asset, bool IsTexture)
278 {
279 if (asset.FullID != LLUUID.Zero) // if it is set to zero then the asset wasn't found by the server
280 {
281 //check if it is a texture or not
282 //then add to the correct cache list
283 //then check for waiting requests for this asset/texture (in the Requested lists)
284 //and move those requests into the Requests list.
285 if (IsTexture)
286 {
287 TextureImage image = new TextureImage(asset);
288 this.Textures.Add(image.FullID, image);
289 if (this.RequestedTextures.ContainsKey(image.FullID))
290 {
291 AssetRequest req = this.RequestedTextures[image.FullID];
292 req.ImageInfo = image;
293 if (image.Data.LongLength > 600)
294 {
295 //over 600 bytes so split up file
296 req.NumPackets = 1 + (int)(image.Data.Length - 600 + 999) / 1000;
297 }
298 else
299 {
300 req.NumPackets = 1;
301 }
302 this.RequestedTextures.Remove(image.FullID);
303 this.TextureRequests.Add(req);
304 }
305 }
306 else
307 {
308 AssetInfo assetInf = new AssetInfo(asset);
309 this.Assets.Add(assetInf.FullID, assetInf);
310 if (this.RequestedAssets.ContainsKey(assetInf.FullID))
311 {
312 AssetRequest req = this.RequestedAssets[assetInf.FullID];
313 req.AssetInf = assetInf;
314 if (assetInf.Data.LongLength > 600)
315 {
316 //over 600 bytes so split up file
317 req.NumPackets = 1 + (int)(assetInf.Data.Length - 600 + 999) / 1000;
318 }
319 else
320 {
321 req.NumPackets = 1;
322 }
323 this.RequestedAssets.Remove(assetInf.FullID);
324 this.AssetRequests.Add(req);
325 }
326 }
327 }
328 }
329
330 public void AssetNotFound(AssetBase asset)
331 {
332 //the asset server had no knowledge of requested asset
333
334 }
335
336 #region Assets
337 /// <summary>
338 ///
339 /// </summary>
340 /// <param name="userInfo"></param>
341 /// <param name="transferRequest"></param>
342 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
343 {
344 LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
345 //check to see if asset is in local cache, if not we need to request it from asset server.
346 if (!this.Assets.ContainsKey(requestID))
347 {
348 //not found asset
349 // so request from asset server
350 if (!this.RequestedAssets.ContainsKey(requestID))
351 {
352 AssetRequest request = new AssetRequest();
353 request.RequestUser = userInfo;
354 request.RequestAssetID = requestID;
355 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
356 this.RequestedAssets.Add(requestID, request);
357 this._assetServer.RequestAsset(requestID, false);
358 }
359 return;
360 }
361 //it is in our cache
362 AssetInfo asset = this.Assets[requestID];
363
364 //work out how many packets it should be sent in
365 // and add to the AssetRequests list
366 AssetRequest req = new AssetRequest();
367 req.RequestUser = userInfo;
368 req.RequestAssetID = requestID;
369 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
370 req.AssetInf = asset;
371
372 if (asset.Data.LongLength > 600)
373 {
374 //over 600 bytes so split up file
375 req.NumPackets = 1 + (int)(asset.Data.Length - 600 + 999) / 1000;
376 }
377 else
378 {
379 req.NumPackets = 1;
380 }
381
382 this.AssetRequests.Add(req);
383 }
384
385 /// <summary>
386 ///
387 /// </summary>
388 private void ProcessAssetQueue()
389 {
390 if (this.AssetRequests.Count == 0)
391 {
392 //no requests waiting
393 return;
394 }
395 int num;
396
397 if (this.AssetRequests.Count < 5)
398 {
399 //lower than 5 so do all of them
400 num = this.AssetRequests.Count;
401 }
402 else
403 {
404 num = 5;
405 }
406 AssetRequest req;
407 for (int i = 0; i < num; i++)
408 {
409 req = (AssetRequest)this.AssetRequests[i];
410
411 TransferInfoPacket Transfer = new TransferInfoPacket();
412 Transfer.TransferInfo.ChannelType = 2;
413 Transfer.TransferInfo.Status = 0;
414 Transfer.TransferInfo.TargetType = 0;
415 Transfer.TransferInfo.Params = req.RequestAssetID.GetBytes();
416 Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
417 Transfer.TransferInfo.TransferID = req.TransferRequestID;
418 req.RequestUser.OutPacket(Transfer);
419
420 if (req.NumPackets == 1)
421 {
422 TransferPacketPacket TransferPacket = new TransferPacketPacket();
423 TransferPacket.TransferData.Packet = 0;
424 TransferPacket.TransferData.ChannelType = 2;
425 TransferPacket.TransferData.TransferID = req.TransferRequestID;
426 TransferPacket.TransferData.Data = req.AssetInf.Data;
427 TransferPacket.TransferData.Status = 1;
428 req.RequestUser.OutPacket(TransferPacket);
429 }
430 else
431 {
432 //more than one packet so split file up , for now it can't be bigger than 2000 bytes
433 TransferPacketPacket TransferPacket = new TransferPacketPacket();
434 TransferPacket.TransferData.Packet = 0;
435 TransferPacket.TransferData.ChannelType = 2;
436 TransferPacket.TransferData.TransferID = req.TransferRequestID;
437 byte[] chunk = new byte[1000];
438 Array.Copy(req.AssetInf.Data, chunk, 1000);
439 TransferPacket.TransferData.Data = chunk;
440 TransferPacket.TransferData.Status = 0;
441 req.RequestUser.OutPacket(TransferPacket);
442
443 TransferPacket = new TransferPacketPacket();
444 TransferPacket.TransferData.Packet = 1;
445 TransferPacket.TransferData.ChannelType = 2;
446 TransferPacket.TransferData.TransferID = req.TransferRequestID;
447 byte[] chunk1 = new byte[(req.AssetInf.Data.Length - 1000)];
448 Array.Copy(req.AssetInf.Data, 1000, chunk1, 0, chunk1.Length);
449 TransferPacket.TransferData.Data = chunk1;
450 TransferPacket.TransferData.Status = 1;
451 req.RequestUser.OutPacket(TransferPacket);
452 }
453
454 }
455
456 //remove requests that have been completed
457 for (int i = 0; i < num; i++)
458 {
459 this.AssetRequests.RemoveAt(0);
460 }
461
462 }
463
464 public AssetInfo CloneAsset(LLUUID newOwner, AssetInfo sourceAsset)
465 {
466 AssetInfo newAsset = new AssetInfo();
467 newAsset.Data = new byte[sourceAsset.Data.Length];
468 Array.Copy(sourceAsset.Data, newAsset.Data, sourceAsset.Data.Length);
469 newAsset.FullID = LLUUID.Random();
470 newAsset.Type = sourceAsset.Type;
471 newAsset.InvType = sourceAsset.InvType;
472 return (newAsset);
473 }
474 #endregion
475
476 #region Textures
477 /// <summary>
478 ///
479 /// </summary>
480 /// <param name="userInfo"></param>
481 /// <param name="imageID"></param>
482 public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID)
483 {
484 //check to see if texture is in local cache, if not request from asset server
485 if (!this.Textures.ContainsKey(imageID))
486 {
487 if (!this.RequestedTextures.ContainsKey(imageID))
488 {
489 //not is cache so request from asset server
490 AssetRequest request = new AssetRequest();
491 request.RequestUser = userInfo;
492 request.RequestAssetID = imageID;
493 request.IsTextureRequest = true;
494 this.RequestedTextures.Add(imageID, request);
495 this._assetServer.RequestAsset(imageID, true);
496 }
497 return;
498 }
499
500 TextureImage imag = this.Textures[imageID];
501 AssetRequest req = new AssetRequest();
502 req.RequestUser = userInfo;
503 req.RequestAssetID = imageID;
504 req.IsTextureRequest = true;
505 req.ImageInfo = imag;
506
507 if (imag.Data.LongLength > 600)
508 {
509 //over 600 bytes so split up file
510 req.NumPackets = 1 + (int)(imag.Data.Length - 600 + 999) / 1000;
511 }
512 else
513 {
514 req.NumPackets = 1;
515 }
516 this.TextureRequests.Add(req);
517 }
518
519 public TextureImage CloneImage(LLUUID newOwner, TextureImage source)
520 {
521 TextureImage newImage = new TextureImage();
522 newImage.Data = new byte[source.Data.Length];
523 Array.Copy(source.Data, newImage.Data, source.Data.Length);
524 //newImage.filename = source.filename;
525 newImage.FullID = LLUUID.Random();
526 newImage.Name = source.Name;
527 return (newImage);
528 }
529 #endregion
530
531 private IAssetServer LoadAssetDll(string dllName)
532 {
533 Assembly pluginAssembly = Assembly.LoadFrom(dllName);
534 IAssetServer server = null;
535
536 foreach (Type pluginType in pluginAssembly.GetTypes())
537 {
538 if (pluginType.IsPublic)
539 {
540 if (!pluginType.IsAbstract)
541 {
542 Type typeInterface = pluginType.GetInterface("IAssetPlugin", true);
543
544 if (typeInterface != null)
545 {
546 IAssetPlugin plug = (IAssetPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
547 server = plug.GetAssetServer();
548 break;
549 }
550
551 typeInterface = null;
552 }
553 }
554 }
555 pluginAssembly = null;
556 return server;
557 }
558
559 }
560
561 public class AssetRequest
562 {
563 public IClientAPI RequestUser;
564 public LLUUID RequestAssetID;
565 public AssetInfo AssetInf;
566 public TextureImage ImageInfo;
567 public LLUUID TransferRequestID;
568 public long DataPointer = 0;
569 public int NumPackets = 0;
570 public int PacketCounter = 0;
571 public bool IsTextureRequest;
572 //public bool AssetInCache;
573 //public int TimeRequested;
574
575 public AssetRequest()
576 {
577
578 }
579 }
580
581 public class AssetInfo : AssetBase
582 {
583 public AssetInfo()
584 {
585
586 }
587
588 public AssetInfo(AssetBase aBase)
589 {
590 Data = aBase.Data;
591 FullID = aBase.FullID;
592 Type = aBase.Type;
593 InvType = aBase.InvType;
594 Name = aBase.Name;
595 Description = aBase.Description;
596 }
597 }
598
599 public class TextureImage : AssetBase
600 {
601 public TextureImage()
602 {
603
604 }
605
606 public TextureImage(AssetBase aBase)
607 {
608 Data = aBase.Data;
609 FullID = aBase.FullID;
610 Type = aBase.Type;
611 InvType = aBase.InvType;
612 Name = aBase.Name;
613 Description = aBase.Description;
614 }
615 }
616
617}
618