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
parent
081a66d570
commit
611327e104
|
@ -36,8 +36,7 @@ using OpenSim.Framework.Console;
|
|||
|
||||
namespace OpenSim.Framework.Communications.Cache
|
||||
{
|
||||
public delegate void DownloadComplete(AssetCache.TextureSender sender);
|
||||
|
||||
|
||||
public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset);
|
||||
|
||||
/// <summary>
|
||||
|
@ -57,21 +56,11 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>();
|
||||
//Textures requested from the asset server
|
||||
|
||||
public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>();
|
||||
|
||||
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 Thread m_assetCacheThread;
|
||||
private Thread m_textureSenderThread;
|
||||
private LogBase m_log;
|
||||
|
||||
/// <summary>
|
||||
|
@ -88,9 +77,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
m_assetCacheThread.IsBackground = true;
|
||||
m_assetCacheThread.Start();
|
||||
|
||||
m_textureSenderThread = new Thread(new ThreadStart(ProcessTextureSenders));
|
||||
m_textureSenderThread.IsBackground = true;
|
||||
m_textureSenderThread.Start();
|
||||
|
||||
m_log = log;
|
||||
}
|
||||
|
||||
|
@ -104,7 +91,6 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
try
|
||||
{
|
||||
ProcessAssetQueue();
|
||||
ProcessTextureQueue();
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -188,7 +174,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
|
||||
if (asset.Type == 0)
|
||||
{
|
||||
if(Textures.ContainsKey(asset.FullID))
|
||||
if (Textures.ContainsKey(asset.FullID))
|
||||
{
|
||||
result = "Duplicate ignored.";
|
||||
}
|
||||
|
@ -250,67 +236,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
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)
|
||||
{
|
||||
|
@ -354,7 +280,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
if (assetInf.Data.LongLength > 600)
|
||||
{
|
||||
//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
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
/// <summary>
|
||||
|
@ -458,7 +398,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
if (asset.Data.LongLength > 600)
|
||||
{
|
||||
//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
|
||||
{
|
||||
|
@ -473,6 +413,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
/// </summary>
|
||||
private void ProcessAssetQueue()
|
||||
{
|
||||
//should move the asset downloading to a module, like has been done with texture downloading
|
||||
if (AssetRequests.Count == 0)
|
||||
{
|
||||
//no requests waiting
|
||||
|
@ -492,7 +433,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
AssetRequest req;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
req = (AssetRequest) AssetRequests[i];
|
||||
req = (AssetRequest)AssetRequests[i];
|
||||
//Console.WriteLine("sending asset " + req.RequestAssetID);
|
||||
TransferInfoPacket Transfer = new TransferInfoPacket();
|
||||
Transfer.TransferInfo.ChannelType = 2;
|
||||
|
@ -502,7 +443,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
{
|
||||
Transfer.TransferInfo.Params = new byte[20];
|
||||
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);
|
||||
}
|
||||
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.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;
|
||||
req.RequestUser.OutPacket(Transfer,ThrottleOutPacketType.Asset);
|
||||
req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
|
||||
|
||||
if (req.NumPackets == 1)
|
||||
{
|
||||
|
@ -573,79 +514,6 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
|
||||
#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 IClientAPI RequestUser;
|
||||
|
@ -702,123 +570,28 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
}
|
||||
}
|
||||
|
||||
public class TextureSender
|
||||
|
||||
public class AssetRequestsList
|
||||
{
|
||||
public AssetRequest request;
|
||||
private int counter = 0;
|
||||
public LLUUID AssetID;
|
||||
public List<NewAssetRequest> Requests = new List<NewAssetRequest>();
|
||||
|
||||
public TextureSender(AssetRequest req)
|
||||
public AssetRequestsList(LLUUID assetID)
|
||||
{
|
||||
request = req;
|
||||
}
|
||||
|
||||
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();
|
||||
AssetID = assetID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AssetRequestsList
|
||||
{
|
||||
public LLUUID AssetID;
|
||||
public List<NewAssetRequest> Requests = new List<NewAssetRequest>();
|
||||
|
||||
public AssetRequestsList(LLUUID assetID)
|
||||
public class NewAssetRequest
|
||||
{
|
||||
AssetID = assetID;
|
||||
}
|
||||
}
|
||||
public LLUUID AssetID;
|
||||
public AssetRequestCallback Callback;
|
||||
|
||||
public class NewAssetRequest
|
||||
{
|
||||
public LLUUID AssetID;
|
||||
public AssetRequestCallback Callback;
|
||||
|
||||
public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback)
|
||||
{
|
||||
AssetID = assetID;
|
||||
Callback = callback;
|
||||
public NewAssetRequest(LLUUID assetID, AssetRequestCallback callback)
|
||||
{
|
||||
AssetID = assetID;
|
||||
Callback = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
}
|
||||
|
||||
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);
|
||||
AgentAssetTransactions transactions = GetUserTransActions(remoteClient.AgentId);
|
||||
|
@ -92,7 +92,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
AgentAssetTransactions.AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
|
||||
if (uploader != null)
|
||||
{
|
||||
uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal);
|
||||
uploader.Initialise(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,66 +113,6 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
// Fields
|
||||
|
@ -230,7 +170,7 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
}
|
||||
|
||||
public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data,
|
||||
bool storeLocal)
|
||||
bool storeLocal, bool tempFile)
|
||||
{
|
||||
ourClient = remoteClient;
|
||||
Asset = new AssetBase();
|
||||
|
@ -240,6 +180,9 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
Asset.Data = data;
|
||||
Asset.Name = "blank";
|
||||
Asset.Description = "empty";
|
||||
Asset.Local = storeLocal;
|
||||
Asset.Temporary = tempFile;
|
||||
|
||||
TransactionID = transaction;
|
||||
m_storeLocal = storeLocal;
|
||||
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
|
||||
{
|
||||
// Fields
|
||||
|
@ -420,5 +424,6 @@ namespace OpenSim.Framework.Communications.Cache
|
|||
return text;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ using System.Text;
|
|||
namespace OpenSim.Region.Capabilities
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// Borrowed from (a older version of ) libsl for now, as their new llsd code doesn't work we our decoding code.
|
||||
/// </summary>
|
||||
public static class LLSD
|
||||
{
|
||||
|
|
|
@ -157,6 +157,13 @@ namespace OpenSim.Framework
|
|||
protected LLUUID m_requestedAssetID;
|
||||
private sbyte m_discardLevel;
|
||||
private uint m_packetNumber;
|
||||
private float m_priority;
|
||||
|
||||
public float Priority
|
||||
{
|
||||
get { return m_priority; }
|
||||
set { m_priority = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -348,7 +355,7 @@ namespace OpenSim.Framework
|
|||
public delegate void RemoveTaskInventory(IClientAPI remoteClient, LLUUID itemID, uint localID);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -2738,6 +2738,7 @@ namespace OpenSim.Region.ClientStack
|
|||
args.RequestedAssetID = imageRequest.RequestImage[i].Image;
|
||||
args.DiscardLevel = imageRequest.RequestImage[i].DiscardLevel;
|
||||
args.PacketNumber = imageRequest.RequestImage[i].Packet;
|
||||
args.Priority = imageRequest.RequestImage[i].DownloadPriority;
|
||||
|
||||
OnRequestTexture(this, args);
|
||||
}
|
||||
|
@ -2761,7 +2762,7 @@ namespace OpenSim.Region.ClientStack
|
|||
LLUUID temp=libsecondlife.LLUUID.Combine(request.AssetBlock.TransactionID, SecureSessionId);
|
||||
OnAssetUploadRequest(this, temp,
|
||||
request.AssetBlock.TransactionID, request.AssetBlock.Type,
|
||||
request.AssetBlock.AssetData, request.AssetBlock.StoreLocal);
|
||||
request.AssetBlock.AssetData, request.AssetBlock.StoreLocal, request.AssetBlock.Tempfile);
|
||||
}
|
||||
break;
|
||||
case PacketType.RequestXfer:
|
||||
|
|
|
@ -46,11 +46,10 @@ namespace OpenSim.Region.Environment.Modules
|
|||
private Scene m_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 Dictionary<LLUUID, List<LLUUID>> InProcess = new Dictionary<LLUUID, List<LLUUID>>();
|
||||
|
||||
private Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices = new Dictionary<LLUUID, UserTextureDownloadService>();
|
||||
|
||||
private Thread m_thread;
|
||||
|
||||
public TextureDownloadModule()
|
||||
|
@ -85,55 +84,36 @@ namespace OpenSim.Region.Environment.Modules
|
|||
|
||||
public bool IsSharedModule
|
||||
{
|
||||
get { return true; }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
//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);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
textureService = new UserTextureDownloadService(m_scene, QueueSenders);
|
||||
m_userTextureServices.Add(userID, textureService);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void TextureRequest(Object sender, TextureRequestArgs e)
|
||||
{
|
||||
IClientAPI client = (IClientAPI)sender;
|
||||
if (!ClientRequests[client.AgentId].ContainsKey(e.RequestedAssetID))
|
||||
UserTextureDownloadService textureService;
|
||||
if (TryGetUserTextureService(client.AgentId, out textureService))
|
||||
{
|
||||
lock (ClientRequests)
|
||||
{
|
||||
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);
|
||||
textureService.HandleTextureRequest(client, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,57 +122,150 @@ namespace OpenSim.Region.Environment.Modules
|
|||
while (true)
|
||||
{
|
||||
TextureSender sender = QueueSenders.Dequeue();
|
||||
bool finished = sender.SendTexture();
|
||||
if (finished)
|
||||
if (sender.Cancel)
|
||||
{
|
||||
TextureSent(sender);
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueSenders.Enqueue(sender);
|
||||
bool finished = sender.SendTexturePacket();
|
||||
if (finished)
|
||||
{
|
||||
TextureSent(sender);
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueSenders.Enqueue(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 AssetRequest request;
|
||||
private int counter = 0;
|
||||
public int counter = 0;
|
||||
private AssetBase m_asset;
|
||||
public long DataPointer = 0;
|
||||
public int NumPackets = 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;
|
||||
m_asset = asset;
|
||||
|
||||
if (asset.Data.LongLength > 600)
|
||||
{
|
||||
NumPackets = 2 + (int)(asset.Data.Length - 601) / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
NumPackets = 1;
|
||||
}
|
||||
|
||||
PacketCounter = (int)req.PacketNumber;
|
||||
RequestUser = client;
|
||||
RequestedAssetID = textureID;
|
||||
RequestedDiscardLevel = discardLevel;
|
||||
StartPacketNumber = 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();
|
||||
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;
|
||||
}
|
||||
|
@ -201,65 +274,68 @@ namespace OpenSim.Region.Environment.Modules
|
|||
|
||||
public void SendPacket()
|
||||
{
|
||||
AssetRequest req = request;
|
||||
if (PacketCounter == 0)
|
||||
if (PacketCounter <= NumPackets)
|
||||
{
|
||||
if (NumPackets == 1)
|
||||
if (PacketCounter == 0)
|
||||
{
|
||||
ImageDataPacket im = new ImageDataPacket();
|
||||
im.Header.Reliable = false;
|
||||
im.ImageID.Packets = 1;
|
||||
im.ImageID.ID = m_asset.FullID;
|
||||
im.ImageID.Size = (uint)m_asset.Data.Length;
|
||||
im.ImageData.Data = m_asset.Data;
|
||||
im.ImageID.Codec = 2;
|
||||
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
|
||||
PacketCounter++;
|
||||
if (NumPackets == 0)
|
||||
{
|
||||
ImageDataPacket im = new ImageDataPacket();
|
||||
im.Header.Reliable = false;
|
||||
im.ImageID.Packets = 0;
|
||||
im.ImageID.ID = m_asset.FullID;
|
||||
im.ImageID.Size = (uint)m_asset.Data.Length;
|
||||
im.ImageData.Data = m_asset.Data;
|
||||
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
|
||||
{
|
||||
ImageDataPacket im = new ImageDataPacket();
|
||||
ImagePacketPacket im = new ImagePacketPacket();
|
||||
im.Header.Reliable = false;
|
||||
im.ImageID.Packets = (ushort)(NumPackets);
|
||||
im.ImageID.Packet = (ushort)(PacketCounter);
|
||||
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;
|
||||
req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
|
||||
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);
|
||||
RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
|
||||
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
|
||||
{
|
||||
public IClientAPI RequestUser;
|
||||
public LLUUID RequestAssetID;
|
||||
public int DiscardLevel = -1;
|
||||
public uint PacketNumber = 0;
|
||||
|
||||
public AssetRequest(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
|
||||
private int CalculateNumPackets(int length)
|
||||
{
|
||||
RequestUser = client;
|
||||
RequestAssetID = textureID;
|
||||
DiscardLevel = discardLevel;
|
||||
PacketNumber = packetNumber;
|
||||
int numPackets = 0;
|
||||
|
||||
if (length > 600)
|
||||
{
|
||||
//over 600 bytes so split up file
|
||||
int restData = (length - 600);
|
||||
int restPackets = ((restData + 999) / 1000);
|
||||
numPackets = restPackets;
|
||||
}
|
||||
|
||||
return numPackets;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -35,8 +35,5 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
public interface IScenePresenceBody
|
||||
{
|
||||
void processMovement(IClientAPI remoteClient, uint flags, LLQuaternion bodyRotation);
|
||||
void SetAppearance(byte[] texture, AgentSetAppearancePacket.VisualParamBlock[] visualParam);
|
||||
void SendOurAppearance(IClientAPI OurClient);
|
||||
void SendAppearanceToOtherAgent(ScenePresence avatarInfo);
|
||||
}
|
||||
}
|
|
@ -1019,7 +1019,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
ScenePresence avatar = null;
|
||||
|
||||
AvatarAppearance appearance;
|
||||
LoadAvatarAppearance(client, out appearance);
|
||||
GetAvatarAppearance(client, out appearance);
|
||||
|
||||
avatar = m_innerScene.CreateAndAddScenePresence(client, child, appearance);
|
||||
|
||||
|
@ -1031,7 +1031,7 @@ namespace OpenSim.Region.Environment.Scenes
|
|||
return avatar;
|
||||
}
|
||||
|
||||
protected void LoadAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
|
||||
protected void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
|
||||
{
|
||||
if (m_AvatarFactory == null ||
|
||||
!m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance))
|
||||
|
|
Loading…
Reference in New Issue