more work on texture downloading.

Refractored the TextureDownloadModule (but currently to make debugging easier, it is running as a non shared module, so this results in a instance of this module being created for each region (and a extra thread per region), this will be changed back soon.
Removed the old texture handling/sending code from AssetCache.
A few other small changes/fixes.
afrisby
MW 2007-12-10 13:27:23 +00:00
parent 081a66d570
commit 611327e104
9 changed files with 298 additions and 439 deletions

View File

@ -36,7 +36,6 @@ using OpenSim.Framework.Console;
namespace OpenSim.Framework.Communications.Cache namespace OpenSim.Framework.Communications.Cache
{ {
public delegate void DownloadComplete(AssetCache.TextureSender sender);
public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset); public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset);
@ -57,21 +56,11 @@ namespace OpenSim.Framework.Communications.Cache
public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>();
//Textures requested from the asset server //Textures requested from the asset server
public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>();
public Dictionary<LLUUID, AssetRequestsList> RequestLists = new Dictionary<LLUUID, AssetRequestsList>(); public Dictionary<LLUUID, AssetRequestsList> RequestLists = new Dictionary<LLUUID, AssetRequestsList>();
private BlockingQueue<TextureSender> m_queueTextures = new BlockingQueue<TextureSender>();
private Dictionary<LLUUID, List<LLUUID>> m_avatarReceivedTextures = new Dictionary<LLUUID, List<LLUUID>>();
private Dictionary<LLUUID, Dictionary<LLUUID, int>> m_timesTextureSent =
new Dictionary<LLUUID, Dictionary<LLUUID, int>>();
private IAssetServer m_assetServer; private IAssetServer m_assetServer;
private Thread m_assetCacheThread; private Thread m_assetCacheThread;
private Thread m_textureSenderThread;
private LogBase m_log; private LogBase m_log;
/// <summary> /// <summary>
@ -88,9 +77,7 @@ namespace OpenSim.Framework.Communications.Cache
m_assetCacheThread.IsBackground = true; m_assetCacheThread.IsBackground = true;
m_assetCacheThread.Start(); m_assetCacheThread.Start();
m_textureSenderThread = new Thread(new ThreadStart(ProcessTextureSenders));
m_textureSenderThread.IsBackground = true;
m_textureSenderThread.Start();
m_log = log; m_log = log;
} }
@ -104,7 +91,6 @@ namespace OpenSim.Framework.Communications.Cache
try try
{ {
ProcessAssetQueue(); ProcessAssetQueue();
ProcessTextureQueue();
Thread.Sleep(500); Thread.Sleep(500);
} }
catch (Exception e) catch (Exception e)
@ -188,7 +174,7 @@ namespace OpenSim.Framework.Communications.Cache
if (asset.Type == 0) if (asset.Type == 0)
{ {
if(Textures.ContainsKey(asset.FullID)) if (Textures.ContainsKey(asset.FullID))
{ {
result = "Duplicate ignored."; result = "Duplicate ignored.";
} }
@ -250,67 +236,7 @@ namespace OpenSim.Framework.Communications.Cache
return asset; return asset;
} }
/// <summary>
///
/// </summary>
private void ProcessTextureQueue()
{
if (TextureRequests.Count == 0)
{
//no requests waiting
return;
}
int num;
num = TextureRequests.Count;
AssetRequest req;
for (int i = 0; i < num; i++)
{
req = (AssetRequest) TextureRequests[i];
if (!SendingTextures.ContainsKey(req.ImageInfo.FullID))
{
//Console.WriteLine("new texture to send");
TextureSender sender = new TextureSender(req);
//sender.OnComplete += this.TextureSent;
SendingTextures.Add(req.ImageInfo.FullID, sender);
m_queueTextures.Enqueue(sender);
}
}
TextureRequests.Clear();
}
public void ProcessTextureSenders()
{
while (true)
{
TextureSender sender = m_queueTextures.Dequeue();
bool finished = sender.SendTexture();
if (finished)
{
TextureSent(sender);
}
else
{
// Console.WriteLine("readding texture");
m_queueTextures.Enqueue(sender);
}
}
}
/// <summary>
/// Event handler, called by a TextureSender object to say that texture has been sent
/// </summary>
/// <param name="sender"></param>
public void TextureSent(TextureSender sender)
{
if (SendingTextures.ContainsKey(sender.request.ImageInfo.FullID))
{
SendingTextures.Remove(sender.request.ImageInfo.FullID);
// this.m_avatarReceivedTextures[sender.request.RequestUser.AgentId].Add(sender.request.ImageInfo.FullID);
}
}
public void AssetReceived(AssetBase asset, bool IsTexture) public void AssetReceived(AssetBase asset, bool IsTexture)
{ {
@ -354,7 +280,7 @@ namespace OpenSim.Framework.Communications.Cache
if (assetInf.Data.LongLength > 600) if (assetInf.Data.LongLength > 600)
{ {
//over 600 bytes so split up file //over 600 bytes so split up file
req.NumPackets = 1 + (int) (assetInf.Data.Length - 600 + 999)/1000; req.NumPackets = 1 + (int)(assetInf.Data.Length - 600 + 999) / 1000;
} }
else else
{ {
@ -400,6 +326,20 @@ namespace OpenSim.Framework.Communications.Cache
//} //}
} }
private int CalculateNumPackets(int length)
{
int numPackets = 1;
if (length > 600)
{
//over 600 bytes so split up file
int restData = (length - 600);
int restPackets = ((restData + 999) / 1000);
numPackets = 1 + restPackets;
}
return numPackets;
}
#region Assets #region Assets
/// <summary> /// <summary>
@ -458,7 +398,7 @@ namespace OpenSim.Framework.Communications.Cache
if (asset.Data.LongLength > 600) if (asset.Data.LongLength > 600)
{ {
//over 600 bytes so split up file //over 600 bytes so split up file
req.NumPackets = 1 + (int) (asset.Data.Length - 600 + 999)/1000; req.NumPackets = 1 + (int)(asset.Data.Length - 600 + 999) / 1000;
} }
else else
{ {
@ -473,6 +413,7 @@ namespace OpenSim.Framework.Communications.Cache
/// </summary> /// </summary>
private void ProcessAssetQueue() private void ProcessAssetQueue()
{ {
//should move the asset downloading to a module, like has been done with texture downloading
if (AssetRequests.Count == 0) if (AssetRequests.Count == 0)
{ {
//no requests waiting //no requests waiting
@ -492,7 +433,7 @@ namespace OpenSim.Framework.Communications.Cache
AssetRequest req; AssetRequest req;
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
req = (AssetRequest) AssetRequests[i]; req = (AssetRequest)AssetRequests[i];
//Console.WriteLine("sending asset " + req.RequestAssetID); //Console.WriteLine("sending asset " + req.RequestAssetID);
TransferInfoPacket Transfer = new TransferInfoPacket(); TransferInfoPacket Transfer = new TransferInfoPacket();
Transfer.TransferInfo.ChannelType = 2; Transfer.TransferInfo.ChannelType = 2;
@ -502,7 +443,7 @@ namespace OpenSim.Framework.Communications.Cache
{ {
Transfer.TransferInfo.Params = new byte[20]; Transfer.TransferInfo.Params = new byte[20];
Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
int assType = (int) req.AssetInf.Type; int assType = (int)req.AssetInf.Type;
Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4); Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
} }
else if (req.AssetRequestSource == 3) else if (req.AssetRequestSource == 3)
@ -512,9 +453,9 @@ namespace OpenSim.Framework.Communications.Cache
//Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16); //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
//Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16); //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
} }
Transfer.TransferInfo.Size = (int) req.AssetInf.Data.Length; Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
Transfer.TransferInfo.TransferID = req.TransferRequestID; Transfer.TransferInfo.TransferID = req.TransferRequestID;
req.RequestUser.OutPacket(Transfer,ThrottleOutPacketType.Asset); req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
if (req.NumPackets == 1) if (req.NumPackets == 1)
{ {
@ -573,79 +514,6 @@ namespace OpenSim.Framework.Communications.Cache
#endregion #endregion
#region Textures
/// <summary>
///
/// </summary>
/// <param name="userInfo"></param>
/// <param name="imageID"></param>
public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID, uint packetNumber, int discard)
{
// System.Console.WriteLine("texture request for " + imageID.ToStringHyphenated() + " packetnumber= " + packetNumber);
//check to see if texture is in local cache, if not request from asset server
if (!m_avatarReceivedTextures.ContainsKey(userInfo.AgentId))
{
m_avatarReceivedTextures.Add(userInfo.AgentId, new List<LLUUID>());
}
/* if(this.m_avatarReceivedTextures[userInfo.AgentId].Contains(imageID))
{
//Console.WriteLine(userInfo.AgentId +" is requesting a image( "+ imageID+" that has already been sent to them");
return;
}*/
if (!Textures.ContainsKey(imageID))
{
if (!RequestedTextures.ContainsKey(imageID))
{
//not is cache so request from asset server
AssetRequest request = new AssetRequest();
request.RequestUser = userInfo;
request.RequestAssetID = imageID;
request.IsTextureRequest = true;
request.DiscardLevel = discard;
RequestedTextures.Add(imageID, request);
m_assetServer.RequestAsset(imageID, true);
}
return;
}
// System.Console.WriteLine("texture already in cache");
TextureImage imag = Textures[imageID];
AssetRequest req = new AssetRequest();
req.RequestUser = userInfo;
req.RequestAssetID = imageID;
req.IsTextureRequest = true;
req.ImageInfo = imag;
req.DiscardLevel = discard;
req.NumPackets = CalculateNumPackets(imag.Data.Length);
if (packetNumber != 0)
{
req.PacketCounter = (int) packetNumber;
}
TextureRequests.Add(req);
}
private int CalculateNumPackets(int length)
{
int numPackets = 1;
if (length > 600)
{
//over 600 bytes so split up file
int restData = (length - 600);
int restPackets = ((restData+999)/1000);
numPackets = 1 + restPackets;
}
return numPackets;
}
#endregion
public class AssetRequest public class AssetRequest
{ {
public IClientAPI RequestUser; public IClientAPI RequestUser;
@ -702,123 +570,28 @@ namespace OpenSim.Framework.Communications.Cache
} }
} }
public class TextureSender
public class AssetRequestsList
{ {
public AssetRequest request; public LLUUID AssetID;
private int counter = 0; public List<NewAssetRequest> Requests = new List<NewAssetRequest>();
public TextureSender(AssetRequest req) public AssetRequestsList(LLUUID assetID)
{ {
request = req; AssetID = assetID;
}
public bool SendTexture()
{
SendPacket();
counter++;
if ((request.PacketCounter >= request.NumPackets) || counter > 100 || (request.NumPackets == 1) ||
(request.DiscardLevel == -1))
{
return true;
}
return false;
}
public void SendPacket()
{
AssetRequest req = request;
//Console.WriteLine("sending " + req.ImageInfo.FullID);
if (req.PacketCounter == 0)
{
//first time for this request so send imagedata packet
if (req.NumPackets == 1)
{
//Console.WriteLine("only one packet so send whole file");
ImageDataPacket im = new ImageDataPacket();
im.Header.Reliable = false;
im.ImageID.Packets = 1;
im.ImageID.ID = req.ImageInfo.FullID;
im.ImageID.Size = (uint) req.ImageInfo.Data.Length;
im.ImageData.Data = req.ImageInfo.Data;
im.ImageID.Codec = 2;
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
req.PacketCounter++;
//req.ImageInfo.l= time;
//System.Console.WriteLine("sent texture: " + req.ImageInfo.FullID);
//Console.WriteLine("sending single packet for " + req.ImageInfo.FullID.ToStringHyphenated());
}
else
{
//more than one packet so split file up
ImageDataPacket im = new ImageDataPacket();
im.Header.Reliable = false;
im.ImageID.Packets = (ushort) (req.NumPackets);
im.ImageID.ID = req.ImageInfo.FullID;
im.ImageID.Size = (uint) req.ImageInfo.Data.Length;
im.ImageData.Data = new byte[600];
Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
im.ImageID.Codec = 2;
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
req.PacketCounter++;
//req.ImageInfo.last_used = time;
//System.Console.WriteLine("sent first packet of texture: " + req.ImageInfo.FullID);
//Console.WriteLine("sending packet 1 for " + req.ImageInfo.FullID.ToStringHyphenated());
}
}
else
{
//Console.WriteLine("sending packet " + req.PacketCounter + " for " + req.ImageInfo.FullID.ToStringHyphenated());
//send imagepacket
//more than one packet so split file up
ImagePacketPacket im = new ImagePacketPacket();
im.Header.Reliable = false;
im.ImageID.Packet = (ushort) (req.PacketCounter);
im.ImageID.ID = req.ImageInfo.FullID;
int size = req.ImageInfo.Data.Length - 600 - (1000*(req.PacketCounter - 1));
if (size > 1000) size = 1000;
//Console.WriteLine("length= {0} counter= {1} size= {2}",req.ImageInfo.Data.Length, req.PacketCounter, size);
im.ImageData.Data = new byte[size];
Array.Copy(req.ImageInfo.Data, 600 + (1000*(req.PacketCounter - 1)), im.ImageData.Data, 0, size);
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
req.PacketCounter++;
//req.ImageInfo.last_used = time;
//System.Console.WriteLine("sent a packet of texture: "+req.ImageInfo.FullID);
}
}
private void SaveAssetToFile(string filename, byte[] data)
{
FileStream fs = File.Create(filename);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(data);
bw.Close();
fs.Close();
} }
} }
}
public class AssetRequestsList public class NewAssetRequest
{
public LLUUID AssetID;
public List<NewAssetRequest> Requests = new List<NewAssetRequest>();
public AssetRequestsList(LLUUID assetID)
{ {
AssetID = assetID; public LLUUID AssetID;
} public AssetRequestCallback Callback;
}
public class NewAssetRequest public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback)
{ {
public LLUUID AssetID; AssetID = assetID;
public AssetRequestCallback Callback; Callback = callback;
}
public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback)
{
AssetID = assetID;
Callback = callback;
} }
} }
} }

View File

@ -83,7 +83,7 @@ namespace OpenSim.Framework.Communications.Cache
} }
public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, public void HandleUDPUploadRequest(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type,
byte[] data, bool storeLocal) byte[] data, bool storeLocal, bool tempFile)
{ {
// Console.WriteLine("asset upload of " + assetID); // Console.WriteLine("asset upload of " + assetID);
AgentAssetTransactions transactions = GetUserTransActions(remoteClient.AgentId); AgentAssetTransactions transactions = GetUserTransActions(remoteClient.AgentId);
@ -92,7 +92,7 @@ namespace OpenSim.Framework.Communications.Cache
AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction); AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
if (uploader != null) if (uploader != null)
{ {
uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal); uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
} }
} }
} }

View File

@ -113,66 +113,6 @@ namespace OpenSim.Framework.Communications.Cache
} }
// Nested Types // Nested Types
public class AssetCapsUploader
{
// Fields
private BaseHttpServer httpListener;
private LLUUID inventoryItemID;
private string m_assetDescription = "";
private string m_assetName = "";
private LLUUID m_folderID;
private LLUUID newAssetID;
private bool m_dumpImageToFile;
private string uploaderPath = "";
// Events
public event UpLoadedAsset OnUpLoad;
// Methods
public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem,
LLUUID folderID, string path, BaseHttpServer httpServer, bool dumpImageToFile)
{
m_assetName = assetName;
m_assetDescription = assetDescription;
m_folderID = folderID;
newAssetID = assetID;
inventoryItemID = inventoryItem;
uploaderPath = path;
httpListener = httpServer;
m_dumpImageToFile = dumpImageToFile;
}
private void SaveImageToFile(string filename, byte[] data)
{
FileStream output = File.Create(filename);
BinaryWriter writer = new BinaryWriter(output);
writer.Write(data);
writer.Close();
output.Close();
}
public string uploaderCaps(byte[] data, string path, string param)
{
LLUUID inventoryItemID = this.inventoryItemID;
string text = "";
LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete();
complete.new_asset = newAssetID.ToStringHyphenated();
complete.new_inventory_item = inventoryItemID;
complete.state = "complete";
text = LLSDHelpers.SerialiseLLSDReply(complete);
httpListener.RemoveStreamHandler("POST", uploaderPath);
if (m_dumpImageToFile)
{
SaveImageToFile(m_assetName + ".jp2", data);
}
if (OnUpLoad != null)
{
OnUpLoad(m_assetName, "description", newAssetID, inventoryItemID, LLUUID.Zero, data, "", "");
}
return text;
}
}
public class AssetXferUploader public class AssetXferUploader
{ {
// Fields // Fields
@ -230,7 +170,7 @@ namespace OpenSim.Framework.Communications.Cache
} }
public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data,
bool storeLocal) bool storeLocal, bool tempFile)
{ {
ourClient = remoteClient; ourClient = remoteClient;
Asset = new AssetBase(); Asset = new AssetBase();
@ -240,6 +180,9 @@ namespace OpenSim.Framework.Communications.Cache
Asset.Data = data; Asset.Data = data;
Asset.Name = "blank"; Asset.Name = "blank";
Asset.Description = "empty"; Asset.Description = "empty";
Asset.Local = storeLocal;
Asset.Temporary = tempFile;
TransactionID = transaction; TransactionID = transaction;
m_storeLocal = storeLocal; m_storeLocal = storeLocal;
if (Asset.Data.Length > 2) if (Asset.Data.Length > 2)
@ -368,6 +311,67 @@ namespace OpenSim.Framework.Communications.Cache
} }
} }
#region Nested Classes currently not in use (waiting for them to be enabled)
public class AssetCapsUploader
{
// Fields
private BaseHttpServer httpListener;
private LLUUID inventoryItemID;
private string m_assetDescription = "";
private string m_assetName = "";
private LLUUID m_folderID;
private LLUUID newAssetID;
private bool m_dumpImageToFile;
private string uploaderPath = "";
// Events
public event UpLoadedAsset OnUpLoad;
// Methods
public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem,
LLUUID folderID, string path, BaseHttpServer httpServer, bool dumpImageToFile)
{
m_assetName = assetName;
m_assetDescription = assetDescription;
m_folderID = folderID;
newAssetID = assetID;
inventoryItemID = inventoryItem;
uploaderPath = path;
httpListener = httpServer;
m_dumpImageToFile = dumpImageToFile;
}
private void SaveImageToFile(string filename, byte[] data)
{
FileStream output = File.Create(filename);
BinaryWriter writer = new BinaryWriter(output);
writer.Write(data);
writer.Close();
output.Close();
}
public string uploaderCaps(byte[] data, string path, string param)
{
LLUUID inventoryItemID = this.inventoryItemID;
string text = "";
LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete();
complete.new_asset = newAssetID.ToStringHyphenated();
complete.new_inventory_item = inventoryItemID;
complete.state = "complete";
text = LLSDHelpers.SerialiseLLSDReply(complete);
httpListener.RemoveStreamHandler("POST", uploaderPath);
if (m_dumpImageToFile)
{
SaveImageToFile(m_assetName + ".jp2", data);
}
if (OnUpLoad != null)
{
OnUpLoad(m_assetName, "description", newAssetID, inventoryItemID, LLUUID.Zero, data, "", "");
}
return text;
}
}
public class NoteCardCapsUpdate public class NoteCardCapsUpdate
{ {
// Fields // Fields
@ -420,5 +424,6 @@ namespace OpenSim.Framework.Communications.Cache
return text; return text;
} }
} }
#endregion
} }
} }

View File

@ -10,7 +10,7 @@ using System.Text;
namespace OpenSim.Region.Capabilities namespace OpenSim.Region.Capabilities
{ {
/// <summary> /// <summary>
/// /// Borrowed from (a older version of ) libsl for now, as their new llsd code doesn't work we our decoding code.
/// </summary> /// </summary>
public static class LLSD public static class LLSD
{ {

View File

@ -157,6 +157,13 @@ namespace OpenSim.Framework
protected LLUUID m_requestedAssetID; protected LLUUID m_requestedAssetID;
private sbyte m_discardLevel; private sbyte m_discardLevel;
private uint m_packetNumber; private uint m_packetNumber;
private float m_priority;
public float Priority
{
get { return m_priority; }
set { m_priority = value; }
}
/// <summary> /// <summary>
/// ///
@ -348,7 +355,7 @@ namespace OpenSim.Framework
public delegate void RemoveTaskInventory(IClientAPI remoteClient, LLUUID itemID, uint localID); public delegate void RemoveTaskInventory(IClientAPI remoteClient, LLUUID itemID, uint localID);
public delegate void UDPAssetUploadRequest( public delegate void UDPAssetUploadRequest(
IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, bool storeLocal); IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data, bool storeLocal, bool tempFile);
public delegate void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data); public delegate void XferReceive(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data);

View File

@ -2738,6 +2738,7 @@ namespace OpenSim.Region.ClientStack
args.RequestedAssetID = imageRequest.RequestImage[i].Image; args.RequestedAssetID = imageRequest.RequestImage[i].Image;
args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel; args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel;
args.PacketNumber = imageRequest.RequestImage[i].Packet; args.PacketNumber = imageRequest.RequestImage[i].Packet;
args.Priority = imageRequest.RequestImage[i].DownloadPriority;
OnRequestTexture(this, args); OnRequestTexture(this, args);
} }
@ -2761,7 +2762,7 @@ namespace OpenSim.Region.ClientStack
LLUUID temp=libsecondlife.LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId); LLUUID temp=libsecondlife.LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
OnAssetUploadRequest(this, temp, OnAssetUploadRequest(this, temp,
request.AssetBlock.TransactionID, request.AssetBlock.Type, request.AssetBlock.TransactionID, request.AssetBlock.Type,
request.AssetBlock.AssetData, request.AssetBlock.StoreLocal); request.AssetBlock.AssetData, request.AssetBlock.StoreLocal, request.AssetBlock.Tempfile);
} }
break; break;
case PacketType.RequestXfer: case PacketType.RequestXfer:

View File

@ -46,11 +46,10 @@ namespace OpenSim.Region.Environment.Modules
private Scene m_scene; private Scene m_scene;
private List<Scene> m_scenes = new List<Scene>(); private List<Scene> m_scenes = new List<Scene>();
private Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>> ClientRequests =
new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>(); private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>();
private Dictionary<LLUUID, List<LLUUID>> InProcess = new Dictionary<LLUUID, List<LLUUID>>();
private Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices = new Dictionary<LLUUID, UserTextureDownloadService>();
private Thread m_thread; private Thread m_thread;
public TextureDownloadModule() public TextureDownloadModule()
@ -85,55 +84,36 @@ namespace OpenSim.Region.Environment.Modules
public bool IsSharedModule public bool IsSharedModule
{ {
get { return true; } get { return false; }
} }
public void NewClient(IClientAPI client) public void NewClient(IClientAPI client)
{ {
lock (ClientRequests)
{
if (!ClientRequests.ContainsKey(client.AgentId))
{
ClientRequests.Add(client.AgentId, new Dictionary<LLUUID, AssetRequest>());
InProcess.Add(client.AgentId, new List<LLUUID>());
}
}
client.OnRequestTexture += TextureRequest; client.OnRequestTexture += TextureRequest;
} }
public void TextureCallback(LLUUID textureID, AssetBase asset) private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService)
{ {
lock (ClientRequests) lock (m_userTextureServices)
{ {
foreach (Dictionary<LLUUID, AssetRequest> reqList in ClientRequests.Values) if (m_userTextureServices.TryGetValue(userID, out textureService))
{ {
if (reqList.ContainsKey(textureID)) return true;
{
//check the texture isn't already in the process of being sent to the client.
if (!InProcess[reqList[textureID].RequestUser.AgentId].Contains(textureID))
{
TextureSender sender = new TextureSender(reqList[textureID], asset);
QueueSenders.Enqueue(sender);
InProcess[reqList[textureID].RequestUser.AgentId].Add(textureID);
reqList.Remove(textureID);
}
}
} }
textureService = new UserTextureDownloadService(m_scene, QueueSenders);
m_userTextureServices.Add(userID, textureService);
return true;
} }
} }
public void TextureRequest(Object sender, TextureRequestArgs e) public void TextureRequest(Object sender, TextureRequestArgs e)
{ {
IClientAPI client = (IClientAPI)sender; IClientAPI client = (IClientAPI)sender;
if (!ClientRequests[client.AgentId].ContainsKey(e.RequestedAssetID)) UserTextureDownloadService textureService;
if (TryGetUserTextureService(client.AgentId, out textureService))
{ {
lock (ClientRequests) textureService.HandleTextureRequest(client, e);
{
AssetRequest request = new AssetRequest(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
ClientRequests[client.AgentId].Add(e.RequestedAssetID, request);
}
m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
} }
} }
@ -142,57 +122,150 @@ namespace OpenSim.Region.Environment.Modules
while (true) while (true)
{ {
TextureSender sender = QueueSenders.Dequeue(); TextureSender sender = QueueSenders.Dequeue();
bool finished = sender.SendTexture(); if (sender.Cancel)
if (finished)
{ {
TextureSent(sender); TextureSent(sender);
} }
else else
{ {
QueueSenders.Enqueue(sender); bool finished = sender.SendTexturePacket();
if (finished)
{
TextureSent(sender);
}
else
{
QueueSenders.Enqueue(sender);
}
} }
} }
} }
private void TextureSent(TextureSender sender) private void TextureSent(TextureSender sender)
{ {
if (InProcess[sender.request.RequestUser.AgentId].Contains(sender.request.RequestAssetID)) sender.Sending = false;
}
public class UserTextureDownloadService
{
private Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
private BlockingQueue<TextureSender> m_sharedSendersQueue;
private Scene m_scene;
public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue)
{ {
InProcess[sender.request.RequestUser.AgentId].Remove(sender.request.RequestAssetID); m_scene = scene;
m_sharedSendersQueue = sharedQueue;
}
public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e)
{
//TODO: should be working out the data size/ number of packets to be sent for each discard level
if ((e.DiscardLevel >= 0) || (e.Priority != 0))
{
lock (m_textureSenders)
{
if (!m_textureSenders.ContainsKey(e.RequestedAssetID))
{
TextureSender requestHandler = new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
m_textureSenders.Add(e.RequestedAssetID, requestHandler);
m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
}
else
{
m_textureSenders[e.RequestedAssetID].UpdateRequest(e.DiscardLevel, e.PacketNumber);
m_textureSenders[e.RequestedAssetID].counter = 0;
if ((m_textureSenders[e.RequestedAssetID].ImageLoaded) && (m_textureSenders[e.RequestedAssetID].Sending ==false))
{
m_textureSenders[e.RequestedAssetID].Sending = true;
m_sharedSendersQueue.Enqueue(m_textureSenders[e.RequestedAssetID]);
}
}
}
}
else
{
lock (m_textureSenders)
{
if (m_textureSenders.ContainsKey(e.RequestedAssetID))
{
m_textureSenders[e.RequestedAssetID].Cancel = true;
}
}
}
}
public void TextureCallback(LLUUID textureID, AssetBase asset)
{
lock (m_textureSenders)
{
if (m_textureSenders.ContainsKey(textureID))
{
if (!m_textureSenders[textureID].ImageLoaded)
{
m_textureSenders[textureID].TextureReceived(asset);
m_textureSenders[textureID].Sending = true;
m_textureSenders[textureID].counter = 0;
m_sharedSendersQueue.Enqueue(m_textureSenders[textureID]);
}
}
else
{
// Got a texture with no sender object to handle it, this shouldn't happen
}
}
} }
} }
public class TextureSender public class TextureSender
{ {
public AssetRequest request; public int counter = 0;
private int counter = 0;
private AssetBase m_asset; private AssetBase m_asset;
public long DataPointer = 0; public long DataPointer = 0;
public int NumPackets = 0; public int NumPackets = 0;
public int PacketCounter = 0; public int PacketCounter = 0;
public bool Cancel = false;
public bool ImageLoaded = false;
public TextureSender(AssetRequest req, AssetBase asset) public bool Sending = false;
public IClientAPI RequestUser;
public LLUUID RequestedAssetID;
public int RequestedDiscardLevel = -1;
public uint StartPacketNumber = 0;
// private int m_sentDiscardLevel = -1;
public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
{ {
request = req; RequestUser = client;
m_asset = asset; RequestedAssetID = textureID;
RequestedDiscardLevel = discardLevel;
if (asset.Data.LongLength > 600) StartPacketNumber = packetNumber;
{
NumPackets = 2 + (int)(asset.Data.Length - 601) / 1000;
}
else
{
NumPackets = 1;
}
PacketCounter = (int)req.PacketNumber;
} }
public bool SendTexture() public void TextureReceived(AssetBase asset)
{
m_asset = asset;
NumPackets = CalculateNumPackets(asset.Data.Length);
PacketCounter = (int)StartPacketNumber;
ImageLoaded = true;
}
public void UpdateRequest(int discardLevel, uint packetNumber)
{
RequestedDiscardLevel = discardLevel;
StartPacketNumber = packetNumber;
PacketCounter = (int)StartPacketNumber;
}
public bool SendTexturePacket()
{ {
SendPacket(); SendPacket();
counter++; counter++;
if ((PacketCounter >= NumPackets) || counter > 100 || (NumPackets == 1) || (request.DiscardLevel == -1)) if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1)))) )
{ {
return true; return true;
} }
@ -201,65 +274,68 @@ namespace OpenSim.Region.Environment.Modules
public void SendPacket() public void SendPacket()
{ {
AssetRequest req = request; if (PacketCounter <= NumPackets)
if (PacketCounter == 0)
{ {
if (NumPackets == 1) if (PacketCounter == 0)
{ {
ImageDataPacket im = new ImageDataPacket(); if (NumPackets == 0)
im.Header.Reliable = false; {
im.ImageID.Packets = 1; ImageDataPacket im = new ImageDataPacket();
im.ImageID.ID = m_asset.FullID; im.Header.Reliable = false;
im.ImageID.Size = (uint)m_asset.Data.Length; im.ImageID.Packets = 0;
im.ImageData.Data = m_asset.Data; im.ImageID.ID = m_asset.FullID;
im.ImageID.Codec = 2; im.ImageID.Size = (uint)m_asset.Data.Length;
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); im.ImageData.Data = m_asset.Data;
PacketCounter++; im.ImageID.Codec = 2;
RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
PacketCounter++;
}
else
{
ImageDataPacket im = new ImageDataPacket();
im.Header.Reliable = false;
im.ImageID.Packets = (ushort)(NumPackets);
im.ImageID.ID = m_asset.FullID;
im.ImageID.Size = (uint)m_asset.Data.Length;
im.ImageData.Data = new byte[600];
Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600);
im.ImageID.Codec = 2;
RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
PacketCounter++;
}
} }
else else
{ {
ImageDataPacket im = new ImageDataPacket(); ImagePacketPacket im = new ImagePacketPacket();
im.Header.Reliable = false; im.Header.Reliable = false;
im.ImageID.Packets = (ushort)(NumPackets); im.ImageID.Packet = (ushort)(PacketCounter);
im.ImageID.ID = m_asset.FullID; im.ImageID.ID = m_asset.FullID;
im.ImageID.Size = (uint)m_asset.Data.Length; int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1));
im.ImageData.Data = new byte[600]; if (size > 1000) size = 1000;
Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); im.ImageData.Data = new byte[size];
im.ImageID.Codec = 2; Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size);
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
PacketCounter++; PacketCounter++;
} }
} }
else
{
ImagePacketPacket im = new ImagePacketPacket();
im.Header.Reliable = false;
im.ImageID.Packet = (ushort)(PacketCounter);
im.ImageID.ID = m_asset.FullID;
int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1));
if (size > 1000) size = 1000;
im.ImageData.Data = new byte[size];
Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size);
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
PacketCounter++;
}
} }
}
public class AssetRequest private int CalculateNumPackets(int length)
{
public IClientAPI RequestUser;
public LLUUID RequestAssetID;
public int DiscardLevel = -1;
public uint PacketNumber = 0;
public AssetRequest(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
{ {
RequestUser = client; int numPackets = 0;
RequestAssetID = textureID;
DiscardLevel = discardLevel; if (length > 600)
PacketNumber = packetNumber; {
//over 600 bytes so split up file
int restData = (length - 600);
int restPackets = ((restData + 999) / 1000);
numPackets = restPackets;
}
return numPackets;
} }
} }
} }
} }

View File

@ -35,8 +35,5 @@ namespace OpenSim.Region.Environment.Scenes
public interface IScenePresenceBody public interface IScenePresenceBody
{ {
void processMovement(IClientAPI remoteClient, uint flags, LLQuaternion bodyRotation); void processMovement(IClientAPI remoteClient, uint flags, LLQuaternion bodyRotation);
void SetAppearance(byte[] texture, AgentSetAppearancePacket.VisualParamBlock[] visualParam);
void SendOurAppearance(IClientAPI OurClient);
void SendAppearanceToOtherAgent(ScenePresence avatarInfo);
} }
} }

View File

@ -1019,7 +1019,7 @@ namespace OpenSim.Region.Environment.Scenes
ScenePresence avatar = null; ScenePresence avatar = null;
AvatarAppearance appearance; AvatarAppearance appearance;
LoadAvatarAppearance(client, out appearance); GetAvatarAppearance(client, out appearance);
avatar = m_innerScene.CreateAndAddScenePresence(client, child, appearance); avatar = m_innerScene.CreateAndAddScenePresence(client, child, appearance);
@ -1031,7 +1031,7 @@ namespace OpenSim.Region.Environment.Scenes
return avatar; return avatar;
} }
protected void LoadAvatarAppearance(IClientAPI client, out AvatarAppearance appearance) protected void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
{ {
if (m_AvatarFactory == null || if (m_AvatarFactory == null ||
!m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance)) !m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance))