+ Added Async download support to AssetSystem/ImageManager.cs

+ Started converting IA_ImageTool/ImageTool.cs to use the JasperLibrary, but was getting errors

TODO: Add an Async download option to the ImageTool download example application

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@448 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
Michael Cortez
2006-10-31 20:08:02 +00:00
parent 9206e74940
commit 6730dbd208
3 changed files with 216 additions and 17 deletions

View File

@@ -26,6 +26,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using libsecondlife;
using libsecondlife.Packets;
@@ -34,17 +35,26 @@ using libsecondlife.InventorySystem;
namespace libsecondlife.AssetSystem
{
/// <summary>
public delegate void ImageRetrievedCallback(LLUUID id, byte[] data); //this delegate is called when an image completed.
/// <summary>
/// Manages the uploading and downloading of Images from SecondLife
/// </summary>
public class ImageManager
{
private SecondLife slClient;
public enum CacheTypes {None, Memory, Disk};
private CacheTypes CacheType;
private string CacheDirectory = "ImageCache";
private Dictionary<LLUUID, Byte[]> CacheTable = new Dictionary<LLUUID, byte[]>();
private ImagePacketHelpers ImagePacketHelper;
private Dictionary<LLUUID, TransferRequest> htDownloadRequests = new Dictionary<LLUUID,TransferRequest>();
public ImageRetrievedCallback OnImageRetrieved;
private class TransferRequest
{
public bool Completed;
@@ -75,18 +85,122 @@ namespace libsecondlife.AssetSystem
/// <param name="client"></param>
public ImageManager(SecondLife client)
{
slClient = client;
Init(client, CacheTypes.None, null);
}
/// <summary>
/// </summary>
/// <param name="client"></param>
/// <param name="ctype">The type of Cache system to use for images.</param>
public ImageManager(SecondLife client, CacheTypes ctype)
{
Init(client, ctype, null);
}
/// <summary>
/// </summary>
/// <param name="client"></param>
/// <param name="ctype">The type of Cache system to use for images.</param>
/// <param name="directory">The directory to use for disk based caching.</param>
public ImageManager(SecondLife client, CacheTypes ctype, String directory)
{
Init(client, ctype, directory);
}
/// <summary>
/// </summary>
/// <param name="client"></param>
/// <param name="ctype">The type of Cache system to use for images.</param>
/// <param name="directory">The directory to use for disk based caching.</param>
private void Init(SecondLife client, CacheTypes ctype, string directory)
{
slClient = client;
// Setup Image Caching
CacheType = ctype;
if (ctype == CacheTypes.Disk)
{
if (directory != null)
{
CacheDirectory = directory;
}
try
{
if (!Directory.Exists(CacheDirectory))
{
Directory.CreateDirectory(CacheDirectory);
}
}
catch (Exception e)
{
Console.WriteLine("ERROR: Disk Cache directory could not be established, defaulting to Memory Cache.");
Console.WriteLine(e.Message);
CacheType = CacheTypes.Memory;
}
}
// Image Packet Helpers
ImagePacketHelper = new ImagePacketHelpers(client.Network.AgentID, client.Network.SessionID);
PacketCallback ImageDataCallback = new PacketCallback(ImageDataCallbackHandler);
slClient.Network.RegisterCallback(PacketType.ImageData, ImageDataCallback);
// Image Callbacks
slClient.Network.RegisterCallback(PacketType.ImageData, new PacketCallback(ImageDataCallbackHandler));
slClient.Network.RegisterCallback(PacketType.ImagePacket, new PacketCallback(ImagePacketCallbackHandler));
slClient.Network.RegisterCallback(PacketType.ImageNotInDatabase, new PacketCallback(ImageNotInDatabaseCallbackHandler));
}
PacketCallback ImagePacketCallback = new PacketCallback(ImagePacketCallbackHandler);
slClient.Network.RegisterCallback(PacketType.ImagePacket, ImagePacketCallback);
private void CacheImage(LLUUID ImageID, byte[] ImageData)
{
switch (CacheType)
{
case CacheTypes.Memory:
CacheTable[ImageID] = ImageData;
break;
case CacheTypes.Disk:
String filepath = Path.Combine(CacheDirectory, ImageID.ToStringHyphenated());
File.WriteAllBytes(filepath, ImageData);
break;
default:
break;
}
}
PacketCallback ImageNotInDatabaseCallback = new PacketCallback(ImageNotInDatabaseCallbackHandler);
slClient.Network.RegisterCallback(PacketType.ImageNotInDatabase, ImageNotInDatabaseCallback);
private byte[] CachedImage(LLUUID ImageID)
{
switch (CacheType)
{
case CacheTypes.Memory:
if (CacheTable.ContainsKey(ImageID))
{
return CacheTable[ImageID];
}
else
{
return null;
}
case CacheTypes.Disk:
String filepath = Path.Combine(CacheDirectory, ImageID.ToStringHyphenated());
if (File.Exists(filepath))
{
return File.ReadAllBytes(filepath);
}
else
{
return null;
}
default:
return null;
}
}
public bool isDownloadingImages()
{
return htDownloadRequests.Count > 0;
}
/// <summary>
@@ -95,6 +209,12 @@ namespace libsecondlife.AssetSystem
/// <param name="ImageID">The Image's AssetID</param>
public byte[] RequestImage(LLUUID ImageID)
{
byte[] imgData = CachedImage(ImageID);
if (imgData != null)
{
return imgData;
}
TransferRequest tr = new TransferRequest();
tr.Completed = false;
tr.Size = int.MaxValue; // Number of bytes expected
@@ -113,15 +233,39 @@ namespace libsecondlife.AssetSystem
if( tr.Status == true )
{
CacheImage(ImageID, tr.AssetData);
return tr.AssetData;
}
else
{
throw new Exception( "RequestImage: " + tr.StatusMsg );
}
}
/// <summary>
/// Requests an image from SecondLife.
/// </summary>
/// <param name="ImageID">The Image's AssetID</param>
public void RequestImageAsync(LLUUID ImageID)
{
byte[] imgData = CachedImage(ImageID);
if (imgData != null)
{
FireImageRetrieved(ImageID, imgData);
}
TransferRequest tr = new TransferRequest();
tr.Completed = false;
tr.Size = int.MaxValue; // Number of bytes expected
tr.Received = 0; // Number of bytes received
tr.LastPacket = Helpers.GetUnixTime(); // last time we recevied a packet for this request
htDownloadRequests[ImageID] = tr;
Packet packet = ImagePacketHelper.RequestImage(ImageID);
slClient.Network.SendPacket(packet);
}
/// <summary>
/// Handles the Image Data packet, which includes the ID, and Size of the image,
@@ -140,7 +284,7 @@ namespace libsecondlife.AssetSystem
byte[] Data = reply.ImageData.Data;
// Lookup the request that this packet is for
TransferRequest tr = (TransferRequest)htDownloadRequests[ImageID];
TransferRequest tr = htDownloadRequests[ImageID];
if( tr == null )
{
// Received a packet for an image we didn't request...
@@ -159,8 +303,11 @@ namespace libsecondlife.AssetSystem
// If we've gotten all the data, mark it completed.
if( tr.Received >= tr.Size )
{
tr.Completed = true;
tr.Status = true;
tr.Completed = true;
// Fire off image downloaded event
FireImageRetrieved(ImageID, tr.AssetData);
}
}
@@ -173,9 +320,10 @@ namespace libsecondlife.AssetSystem
{
ImagePacketPacket reply = (ImagePacketPacket)packet;
LLUUID ImageID = reply.ImageID.ID;
// Lookup the request for this packet
TransferRequest tr = (TransferRequest)htDownloadRequests[reply.ImageID.ID];
TransferRequest tr = (TransferRequest)htDownloadRequests[ImageID];
if( tr == null )
{
// Received a packet that doesn't belong to any requests in our queue, strange...
@@ -195,8 +343,11 @@ namespace libsecondlife.AssetSystem
// If we've gotten all the data, mark it completed.
if( tr.Received >= tr.Size )
{
tr.Completed = true;
tr.Status = true;
tr.Status = true;
tr.Completed = true;
// Fire off image downloaded event
FireImageRetrieved(ImageID, tr.AssetData);
}
}
@@ -205,7 +356,33 @@ namespace libsecondlife.AssetSystem
/// </summary>
public void ImageNotInDatabaseCallbackHandler(Packet packet, Simulator simulator)
{
Console.WriteLine(packet);
ImageNotInDatabasePacket reply = (ImageNotInDatabasePacket)packet;
LLUUID ImageID = reply.ImageID.ID;
// Lookup the request for this packet
TransferRequest tr = (TransferRequest)htDownloadRequests[ImageID];
if( tr == null )
{
// Received a packet that doesn't belong to any requests in our queue, strange...
return;
}
tr.Status = false;
tr.StatusMsg = "Image not in database";
tr.Completed = true;
// Fire off image downloaded event
FireImageRetrieved(ImageID, null);
}
private void FireImageRetrieved(LLUUID ImageID, byte[] ImageData)
{
if (OnImageRetrieved != null)
{
OnImageRetrieved(ImageID, ImageData);
}
}
}
}