Merge branch 'avination' into careminster

Conflicts:
	OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
avinationmerge
Melanie 2012-09-16 04:21:18 +01:00
commit 66bf1376b5
19 changed files with 578 additions and 561 deletions

View File

@ -47,36 +47,36 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers namespace OpenSim.Capabilities.Handlers
{ {
public class GetTextureHandler : BaseStreamHandler public class GetTextureHandler
{ {
private static readonly ILog m_log = private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_assetService; private IAssetService m_assetService;
public const string DefaultFormat = "x-j2c"; public const string DefaultFormat = "x-j2c";
// TODO: Change this to a config option public GetTextureHandler(IAssetService assService)
const string REDIRECT_URL = null;
public GetTextureHandler(string path, IAssetService assService, string name, string description)
: base("GET", path, name, description)
{ {
m_assetService = assService; m_assetService = assService;
} }
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) public Hashtable Handle(Hashtable request)
{ {
// Try to parse the texture ID from the request URL Hashtable ret = new Hashtable();
NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
string textureStr = query.GetOne("texture_id"); ret["content_type"] = "text/plain";
string format = query.GetOne("format"); ret["keepalive"] = false;
ret["reusecontext"] = false;
string textureStr = (string)request["texture_id"];
string format = (string)request["format"];
//m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
if (m_assetService == null) if (m_assetService == null)
{ {
m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
} }
UUID textureID; UUID textureID;
@ -91,30 +91,30 @@ namespace OpenSim.Capabilities.Handlers
} }
else else
{ {
formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); formats = new string[1] { DefaultFormat }; // default
if (((Hashtable)request["headers"])["Accept"] != null)
formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]);
if (formats.Length == 0) if (formats.Length == 0)
formats = new string[1] { DefaultFormat }; // default formats = new string[1] { DefaultFormat }; // default
} }
// OK, we have an array with preferred formats, possibly with only one entry // OK, we have an array with preferred formats, possibly with only one entry
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
foreach (string f in formats) foreach (string f in formats)
{ {
if (FetchTexture(httpRequest, httpResponse, textureID, f)) if (FetchTexture(request, ret, textureID, f))
break; break;
} }
} }
else else
{ {
m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
} }
// m_log.DebugFormat( // m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", // "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
// textureID, httpResponse.StatusCode, httpResponse.ContentLength); // textureID, httpResponse.StatusCode, httpResponse.ContentLength);
return ret;
return null;
} }
/// <summary> /// <summary>
@ -125,7 +125,7 @@ namespace OpenSim.Capabilities.Handlers
/// <param name="textureID"></param> /// <param name="textureID"></param>
/// <param name="format"></param> /// <param name="format"></param>
/// <returns>False for "caller try another codec"; true otherwise</returns> /// <returns>False for "caller try another codec"; true otherwise</returns>
private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
{ {
// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
AssetBase texture; AssetBase texture;
@ -134,30 +134,6 @@ namespace OpenSim.Capabilities.Handlers
if (format != DefaultFormat) if (format != DefaultFormat)
fullID = fullID + "-" + format; fullID = fullID + "-" + format;
if (!String.IsNullOrEmpty(REDIRECT_URL))
{
// Only try to fetch locally cached textures. Misses are redirected
texture = m_assetService.GetCached(fullID);
if (texture != null)
{
if (texture.Type != (sbyte)AssetType.Texture)
{
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true;
}
WriteTextureData(httpRequest, httpResponse, texture, format);
}
else
{
string textureUrl = REDIRECT_URL + textureID.ToString();
m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
httpResponse.RedirectLocation = textureUrl;
return true;
}
}
else // no redirect
{
// try the cache // try the cache
texture = m_assetService.GetCached(fullID); texture = m_assetService.GetCached(fullID);
@ -171,13 +147,11 @@ namespace OpenSim.Capabilities.Handlers
if (texture != null) if (texture != null)
{ {
if (texture.Type != (sbyte)AssetType.Texture) if (texture.Type != (sbyte)AssetType.Texture)
{
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true; return true;
}
if (format == DefaultFormat) if (format == DefaultFormat)
{ {
WriteTextureData(httpRequest, httpResponse, texture, format); WriteTextureData(request, response, texture, format);
return true; return true;
} }
else else
@ -190,7 +164,7 @@ namespace OpenSim.Capabilities.Handlers
newTexture.Flags = AssetFlags.Collectable; newTexture.Flags = AssetFlags.Collectable;
newTexture.Temporary = true; newTexture.Temporary = true;
m_assetService.Store(newTexture); m_assetService.Store(newTexture);
WriteTextureData(httpRequest, httpResponse, newTexture, format); WriteTextureData(request, response, newTexture, format);
return true; return true;
} }
} }
@ -198,20 +172,23 @@ namespace OpenSim.Capabilities.Handlers
else // it was on the cache else // it was on the cache
{ {
//m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
WriteTextureData(httpRequest, httpResponse, texture, format); WriteTextureData(request, response, texture, format);
return true; return true;
} }
}
// not found // not found
// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true; return true;
} }
private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
{ {
string range = request.Headers.GetOne("Range"); Hashtable headers = new Hashtable();
response["headers"] = headers;
string range = String.Empty;
if (((Hashtable)request["headers"])["Range"] != null)
range = (string)((Hashtable)request["headers"])["Range"];
if (!String.IsNullOrEmpty(range)) // JP2's only if (!String.IsNullOrEmpty(range)) // JP2's only
{ {
@ -239,10 +216,8 @@ namespace OpenSim.Capabilities.Handlers
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution. // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; // response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
// response.StatusCode = (int)System.Net.HttpStatusCode.OK; response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentType = texture.Metadata.ContentType;
} }
else else
{ {
@ -256,37 +231,33 @@ namespace OpenSim.Capabilities.Handlers
// We were accidentally sending back 404 before in this situation // We were accidentally sending back 404 before in this situation
// https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
// entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
// response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
// We also do not want to send back OK even if the whole range was satisfiable since this causes response["content-type"] = texture.Metadata.ContentType;
// HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
// if (end > maxEnd)
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
// else
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentLength = len; byte[] d = new byte[len];
response.ContentType = texture.Metadata.ContentType; Array.Copy(texture.Data, start, d, 0, len);
response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); response["bin_response_data"] = d;
// response.Body.Write(texture.Data, start, len);
response.Body.Write(texture.Data, start, len);
} }
} }
else else
{ {
m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
} }
} }
else // JP2's or other formats else // JP2's or other formats
{ {
// Full content request // Full content request
response.StatusCode = (int)System.Net.HttpStatusCode.OK; response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
response.ContentLength = texture.Data.Length;
if (format == DefaultFormat) if (format == DefaultFormat)
response.ContentType = texture.Metadata.ContentType; response["content_type"] = texture.Metadata.ContentType;
else else
response.ContentType = "image/" + format; response["content_type"] = "image/" + format;
response.Body.Write(texture.Data, 0, texture.Data.Length);
response["bin_response_data"] = texture.Data;
// response.Body.Write(texture.Data, 0, texture.Data.Length);
} }
// if (response.StatusCode < 200 || response.StatusCode > 299) // if (response.StatusCode < 200 || response.StatusCode > 299)

View File

@ -33,6 +33,7 @@ using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base; using OpenSim.Server.Handlers.Base;
using OpenMetaverse; using OpenMetaverse;
/*
namespace OpenSim.Capabilities.Handlers namespace OpenSim.Capabilities.Handlers
{ {
public class GetTextureServerConnector : ServiceConnector public class GetTextureServerConnector : ServiceConnector
@ -63,7 +64,8 @@ namespace OpenSim.Capabilities.Handlers
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
server.AddStreamHandler( server.AddStreamHandler(
new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null)); new GetTextureHandler("/CAPS/GetTexture/", m_AssetService, "GetTexture", null));
} }
} }
} }
*/

View File

@ -39,6 +39,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
/*
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
{ {
[TestFixture] [TestFixture]
@ -61,3 +62,4 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
} }
} }
} }
*/

View File

@ -30,6 +30,15 @@ using OpenMetaverse;
namespace OpenSim.Framework.Capabilities namespace OpenSim.Framework.Capabilities
{ {
[OSDMap]
public class LLSDAssetResource
{
public OSDArray instance_list = new OSDArray();
public OSDArray texture_list = new OSDArray();
public OSDArray mesh_list = new OSDArray();
public string metric = String.Empty;
}
[OSDMap] [OSDMap]
public class LLSDAssetUploadRequest public class LLSDAssetUploadRequest
{ {
@ -38,7 +47,7 @@ namespace OpenSim.Framework.Capabilities
public UUID folder_id = UUID.Zero; public UUID folder_id = UUID.Zero;
public string inventory_type = String.Empty; public string inventory_type = String.Empty;
public string name = String.Empty; public string name = String.Empty;
public LLSDAssetResource asset_resources = new LLSDAssetResource();
public LLSDAssetUploadRequest() public LLSDAssetUploadRequest()
{ {
} }

View File

@ -29,12 +29,33 @@ using System;
namespace OpenSim.Framework.Capabilities namespace OpenSim.Framework.Capabilities
{ {
[OSDMap]
public class LLSDAssetUploadResponsePricebrkDown
{
public int mesh_streaming;
public int mesh_physics;
public int mesh_instance;
public int texture;
public int model;
}
[OSDMap]
public class LLSDAssetUploadResponseData
{
public double resource_cost;
public double model_streaming_cost;
public double simulation_cost;
public double physics_cost;
public LLSDAssetUploadResponsePricebrkDown upload_price_breakdown = new LLSDAssetUploadResponsePricebrkDown();
}
[OSDMap] [OSDMap]
public class LLSDAssetUploadResponse public class LLSDAssetUploadResponse
{ {
public string uploader = String.Empty; public string uploader = String.Empty;
public string state = String.Empty; public string state = String.Empty;
public int upload_price = 0;
public LLSDAssetUploadResponseData data = null;
public LLSDAssetUploadResponse() public LLSDAssetUploadResponse()
{ {
} }

View File

@ -632,7 +632,7 @@ namespace OpenSim.Framework.Servers.HttpServer
// Every month or so this will wrap and give bad numbers, not really a problem // Every month or so this will wrap and give bad numbers, not really a problem
// since its just for reporting // since its just for reporting
int tickdiff = requestEndTick - requestStartTick; int tickdiff = requestEndTick - requestStartTick;
if (tickdiff > 3000) if (tickdiff > 3000 && requestHandler.Name != "GetTexture")
{ {
m_log.InfoFormat( m_log.InfoFormat(
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
@ -1493,7 +1493,8 @@ namespace OpenSim.Framework.Servers.HttpServer
internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
{ {
int responsecode; int responsecode;
string responseString; string responseString = String.Empty;
byte[] responseData = null;
string contentType; string contentType;
if (responsedata == null) if (responsedata == null)
@ -1509,6 +1510,9 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
//m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
responsecode = (int)responsedata["int_response_code"]; responsecode = (int)responsedata["int_response_code"];
if (responsedata["bin_response_data"] != null)
responseData = (byte[])responsedata["bin_response_data"];
else
responseString = (string)responsedata["str_response_string"]; responseString = (string)responsedata["str_response_string"];
contentType = (string)responsedata["content_type"]; contentType = (string)responsedata["content_type"];
} }
@ -1564,8 +1568,22 @@ namespace OpenSim.Framework.Servers.HttpServer
response.AddHeader("Content-Type", contentType); response.AddHeader("Content-Type", contentType);
if (responsedata.ContainsKey("headers"))
{
Hashtable headerdata = (Hashtable)responsedata["headers"];
foreach (string header in headerdata.Keys)
response.AddHeader(header, (string)headerdata[header]);
}
byte[] buffer; byte[] buffer;
if (responseData != null)
{
buffer = responseData;
}
else
{
if (!(contentType.Contains("image") if (!(contentType.Contains("image")
|| contentType.Contains("x-shockwave-flash") || contentType.Contains("x-shockwave-flash")
|| contentType.Contains("application/x-oar") || contentType.Contains("application/x-oar")
@ -1583,6 +1601,7 @@ namespace OpenSim.Framework.Servers.HttpServer
response.SendChunked = false; response.SendChunked = false;
response.ContentLength64 = buffer.Length; response.ContentLength64 = buffer.Length;
response.ContentEncoding = Encoding.UTF8; response.ContentEncoding = Encoding.UTF8;
}
return buffer; return buffer;
} }

View File

@ -52,7 +52,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
Normal = 0, Normal = 0,
LslHttp = 1, LslHttp = 1,
Inventory = 2 Inventory = 2,
Texture = 3
} }
public PollServiceEventArgs( public PollServiceEventArgs(

View File

@ -231,8 +231,7 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
if (m_running) if (m_running)
{ {
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LslHttp || if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal)
req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Inventory)
{ {
m_requests.Enqueue(req); m_requests.Enqueue(req);
} }

View File

@ -694,6 +694,13 @@ namespace OpenSim.Framework
// //
public static void MakeRequest<TRequest, TResponse>(string verb, public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action) string requestUrl, TRequest obj, Action<TResponse> action)
{
MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, 0);
}
public static void MakeRequest<TRequest, TResponse>(string verb,
string requestUrl, TRequest obj, Action<TResponse> action,
int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
@ -706,6 +713,10 @@ namespace OpenSim.Framework
Type type = typeof(TRequest); Type type = typeof(TRequest);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
WebResponse response = null; WebResponse response = null;
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
@ -1002,6 +1013,11 @@ namespace OpenSim.Framework
} }
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{ {
int reqnum = WebUtil.RequestNumber++; int reqnum = WebUtil.RequestNumber++;
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
@ -1013,6 +1029,10 @@ namespace OpenSim.Framework
TResponse deserial = default(TResponse); TResponse deserial = default(TResponse);
WebRequest request = WebRequest.Create(requestUrl); WebRequest request = WebRequest.Create(requestUrl);
HttpWebRequest ht = (HttpWebRequest)request;
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
ht.ServicePoint.ConnectionLimit = maxConnections;
request.Method = verb; request.Method = verb;
if (pTimeout != 0) if (pTimeout != 0)
request.Timeout = pTimeout * 1000; request.Timeout = pTimeout * 1000;

View File

@ -74,7 +74,7 @@ namespace OpenSim
AppDomain.CurrentDomain.UnhandledException += AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
ServicePointManager.DefaultConnectionLimit = 6; ServicePointManager.DefaultConnectionLimit = 12;
// Add the arguments supplied when running the application to the configuration // Add the arguments supplied when running the application to the configuration
ArgvConfigSource configSource = new ArgvConfigSource(args); ArgvConfigSource configSource = new ArgvConfigSource(args);

View File

@ -26,6 +26,7 @@
*/ */
using System; using System;
using System.Timers;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -60,7 +61,7 @@ namespace OpenSim.Region.ClientStack.Linden
public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
public delegate void NewAsset(AssetBase asset); public delegate void NewAsset(AssetBase asset);
@ -386,6 +387,37 @@ namespace OpenSim.Region.ClientStack.Linden
return UUID.Zero; return UUID.Zero;
} }
private delegate void UploadWithCostCompleteDelegate(string assetName,
string assetDescription, UUID assetID, UUID inventoryItem,
UUID parentFolder, byte[] data, string inventoryType,
string assetType, uint cost);
private class AssetUploaderWithCost : AssetUploader
{
private uint m_cost;
public event UploadWithCostCompleteDelegate OnUpLoad;
public AssetUploaderWithCost(string assetName, string description, UUID assetID,
UUID inventoryItem, UUID parentFolderID, string invType, string assetType,
string path, IHttpServer httpServer, bool dumpAssetsToFile, uint cost) :
base(assetName, description, assetID, inventoryItem, parentFolderID,
invType, assetType, path, httpServer, dumpAssetsToFile)
{
m_cost = cost;
base.OnUpLoad += UploadCompleteHandler;
}
private void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
string assetType)
{
OnUpLoad(assetName, assetDescription, assetID, inventoryItem, parentFolder,
data, inventoryType, assetType, m_cost);
}
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -396,8 +428,11 @@ namespace OpenSim.Region.ClientStack.Linden
//m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
//m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
uint cost = 0;
if (llsdRequest.asset_type == "texture" || if (llsdRequest.asset_type == "texture" ||
llsdRequest.asset_type == "animation" || llsdRequest.asset_type == "animation" ||
llsdRequest.asset_type == "mesh" ||
llsdRequest.asset_type == "sound") llsdRequest.asset_type == "sound")
{ {
ScenePresence avatar = null; ScenePresence avatar = null;
@ -428,7 +463,33 @@ namespace OpenSim.Region.ClientStack.Linden
if (mm != null) if (mm != null)
{ {
if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) // XPTO: The cost should be calculated about here
if (llsdRequest.asset_type == "mesh")
{
cost += 20; // Constant for now to test showing a price
if (llsdRequest.asset_resources == null)
{
client.SendAgentAlertMessage("Unable to upload asset. missing information.", false);
LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
errorResponse.uploader = "";
errorResponse.state = "error";
return errorResponse;
}
uint textures_cost = (uint)llsdRequest.asset_resources.texture_list.Array.Count;
textures_cost *= (uint)mm.UploadCharge;
cost += textures_cost;
}
else
{
cost = (uint)mm.UploadCharge;
}
if (!mm.UploadCovered(client.AgentId, (int)cost))
{ {
client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
@ -449,9 +510,9 @@ namespace OpenSim.Region.ClientStack.Linden
UUID parentFolder = llsdRequest.folder_id; UUID parentFolder = llsdRequest.folder_id;
string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
AssetUploader uploader = AssetUploaderWithCost uploader =
new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, new AssetUploaderWithCost(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost);
m_HostCapsObj.HttpListener.AddStreamHandler( m_HostCapsObj.HttpListener.AddStreamHandler(
new BinaryStreamHandler( new BinaryStreamHandler(
@ -469,11 +530,31 @@ namespace OpenSim.Region.ClientStack.Linden
string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
uploaderPath; uploaderPath;
LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
uploadResponse.uploader = uploaderURL; uploadResponse.uploader = uploaderURL;
uploadResponse.state = "upload"; uploadResponse.state = "upload";
uploadResponse.upload_price = (int)cost;
// use fake values for now
if (llsdRequest.asset_type == "mesh")
{
uploadResponse.data = new LLSDAssetUploadResponseData();
uploadResponse.data.model_streaming_cost = 1.0;
uploadResponse.data.simulation_cost = 1.5;
uploadResponse.data.physics_cost = 2.0;
uploadResponse.data.resource_cost = 3.0;
uploadResponse.data.upload_price_breakdown.mesh_instance = 1;
uploadResponse.data.upload_price_breakdown.mesh_physics = 2;
uploadResponse.data.upload_price_breakdown.mesh_streaming = 3;
uploadResponse.data.upload_price_breakdown.texture = 5;
uploadResponse.data.upload_price_breakdown.model = 4;
}
uploader.OnUpLoad += UploadCompleteHandler; uploader.OnUpLoad += UploadCompleteHandler;
return uploadResponse; return uploadResponse;
} }
/// <summary> /// <summary>
@ -484,7 +565,7 @@ namespace OpenSim.Region.ClientStack.Linden
/// <param name="data"></param> /// <param name="data"></param>
public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
string assetType) string assetType, uint cost)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
@ -703,7 +784,7 @@ namespace OpenSim.Region.ClientStack.Linden
if (AddNewInventoryItem != null) if (AddNewInventoryItem != null)
{ {
AddNewInventoryItem(m_HostCapsObj.AgentID, item); AddNewInventoryItem(m_HostCapsObj.AgentID, item, cost);
} }
} }
@ -1014,6 +1095,9 @@ namespace OpenSim.Region.ClientStack.Linden
public class AssetUploader public class AssetUploader
{ {
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event UpLoadedAsset OnUpLoad; public event UpLoadedAsset OnUpLoad;
private UpLoadedAsset handlerUpLoad = null; private UpLoadedAsset handlerUpLoad = null;
@ -1028,6 +1112,7 @@ namespace OpenSim.Region.ClientStack.Linden
private string m_invType = String.Empty; private string m_invType = String.Empty;
private string m_assetType = String.Empty; private string m_assetType = String.Empty;
private Timer m_timeoutTimer = new Timer();
public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
UUID parentFolderID, string invType, string assetType, string path, UUID parentFolderID, string invType, string assetType, string path,
@ -1043,6 +1128,11 @@ namespace OpenSim.Region.ClientStack.Linden
m_assetType = assetType; m_assetType = assetType;
m_invType = invType; m_invType = invType;
m_dumpAssetsToFile = dumpAssetsToFile; m_dumpAssetsToFile = dumpAssetsToFile;
m_timeoutTimer.Elapsed += TimedOut;
m_timeoutTimer.Interval = 120000;
m_timeoutTimer.AutoReset = false;
m_timeoutTimer.Start();
} }
/// <summary> /// <summary>
@ -1064,6 +1154,7 @@ namespace OpenSim.Region.ClientStack.Linden
res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
httpListener.RemoveStreamHandler("POST", uploaderPath); httpListener.RemoveStreamHandler("POST", uploaderPath);
m_timeoutTimer.Stop();
// TODO: probably make this a better set of extensions here // TODO: probably make this a better set of extensions here
string extension = ".jp2"; string extension = ".jp2";
@ -1085,6 +1176,12 @@ namespace OpenSim.Region.ClientStack.Linden
return res; return res;
} }
private void TimedOut(object sender, ElapsedEventArgs args)
{
m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
httpListener.RemoveStreamHandler("POST", uploaderPath);
}
///Left this in and commented in case there are unforseen issues ///Left this in and commented in case there are unforseen issues
//private void SaveAssetToFile(string filename, byte[] data) //private void SaveAssetToFile(string filename, byte[] data)
//{ //{

View File

@ -27,18 +27,13 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Specialized; using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection; using System.Reflection;
using System.IO; using System.Threading;
using System.Web;
using log4net; using log4net;
using Nini.Config; using Nini.Config;
using Mono.Addins; using Mono.Addins;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Servers; using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Servers.HttpServer;
@ -47,64 +42,73 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps; using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers; using OpenSim.Capabilities.Handlers;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.Linden namespace OpenSim.Region.ClientStack.Linden
{ {
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] /// <summary>
/// This module implements both WebFetchTextureDescendents and FetchTextureDescendents2 capabilities.
/// </summary>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
public class GetTextureModule : INonSharedRegionModule public class GetTextureModule : INonSharedRegionModule
{ {
// private static readonly ILog m_log = private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene; private Scene m_scene;
private IAssetService m_assetService;
private bool m_Enabled = false; private static GetTextureHandler m_getTextureHandler;
// TODO: Change this to a config option private IAssetService m_assetService = null;
const string REDIRECT_URL = null;
private string m_URL; private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
private static Thread[] m_workerThreads = null;
private static OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs> m_queue =
new OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs>();
#region ISharedRegionModule Members #region ISharedRegionModule Members
public void Initialise(IConfigSource source) public void Initialise(IConfigSource source)
{ {
IConfig config = source.Configs["ClientStack.LindenCaps"];
if (config == null)
return;
m_URL = config.GetString("Cap_GetTexture", string.Empty);
// Cap doesn't exist
if (m_URL != string.Empty)
m_Enabled = true;
} }
public void AddRegion(Scene s) public void AddRegion(Scene s)
{ {
if (!m_Enabled)
return;
m_scene = s; m_scene = s;
m_assetService = s.AssetService;
} }
public void RemoveRegion(Scene s) public void RemoveRegion(Scene s)
{ {
if (!m_Enabled)
return;
m_scene.EventManager.OnRegisterCaps -= RegisterCaps; m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
m_scene = null; m_scene = null;
} }
public void RegionLoaded(Scene s) public void RegionLoaded(Scene s)
{ {
if (!m_Enabled) // We'll reuse the same handler for all requests.
return; m_getTextureHandler = new GetTextureHandler(m_assetService);
m_assetService = m_scene.RequestModuleInterface<IAssetService>();
m_scene.EventManager.OnRegisterCaps += RegisterCaps; m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
if (m_workerThreads == null)
{
m_workerThreads = new Thread[4];
for (uint i = 0; i < 4; i++)
{
m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
String.Format("TextureWorkerThread{0}", i),
ThreadPriority.Normal,
false,
true,
null,
int.MaxValue);
}
}
} }
public void PostInitialise() public void PostInitialise()
@ -122,24 +126,155 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion #endregion
public void RegisterCaps(UUID agentID, Caps caps) ~GetTextureModule()
{ {
UUID capID = UUID.Random(); foreach (Thread t in m_workerThreads)
t.Abort();
//caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
if (m_URL == "localhost")
{
// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
caps.RegisterHandler(
"GetTexture",
new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString()));
} }
else
private class PollServiceTextureEventArgs : PollServiceEventArgs
{ {
// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); private List<Hashtable> requests =
caps.RegisterHandler("GetTexture", m_URL); new List<Hashtable>();
private Dictionary<UUID, Hashtable> responses =
new Dictionary<UUID, Hashtable>();
private Scene m_scene;
public PollServiceTextureEventArgs(UUID pId, Scene scene) :
base(null, null, null, null, pId, 30000)
{
m_scene = scene;
HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
GetEvents = (x, y, s) =>
{
try
{
return this.responses[x];
}
finally
{
responses.Remove(x);
}
};
Request = (x, y) =>
{
y["RequestID"] = x.ToString();
lock (this.requests)
this.requests.Add(y);
m_queue.Enqueue(this);
};
NoEvents = (x, y) =>
{
lock (this.requests)
{
Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
requests.Remove(request);
}
Hashtable response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
return response;
};
}
public void Process()
{
Hashtable response;
Hashtable request = null;
try
{
lock (this.requests)
{
request = requests[0];
requests.RemoveAt(0);
}
}
catch
{
return;
}
UUID requestID = new UUID(request["RequestID"].ToString());
// If the avatar is gone, don't bother to get the texture
if (m_scene.GetScenePresence(Id) == null)
{
response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
responses[requestID] = response;
return;
}
response = m_getTextureHandler.Handle(request);
responses[requestID] = response;
}
}
private void RegisterCaps(UUID agentID, Caps caps)
{
string capUrl = "/CAPS/" + UUID.Random() + "/";
// Register this as a poll service
// absurd large timeout to tune later to make a bit less than viewer
PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
args.Type = PollServiceEventArgs.EventType.Texture;
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
string hostName = m_scene.RegionInfo.ExternalHostName;
uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
string protocol = "http";
if (MainServer.Instance.UseSSL)
{
hostName = MainServer.Instance.SSLCommonName;
port = MainServer.Instance.SSLPort;
protocol = "https";
}
caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
m_capsDict[agentID] = capUrl;
}
private void DeregisterCaps(UUID agentID, Caps caps)
{
string capUrl;
if (m_capsDict.TryGetValue(agentID, out capUrl))
{
MainServer.Instance.RemoveHTTPHandler("", capUrl);
m_capsDict.Remove(agentID);
}
}
private void DoTextureRequests()
{
while (true)
{
PollServiceTextureEventArgs args = m_queue.Dequeue();
args.Process();
}
} }
} }
} }
}

View File

@ -1,296 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using System.IO;
using System.Web;
using Mono.Addins;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Framework.Capabilities;
namespace OpenSim.Region.ClientStack.Linden
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene;
// private IAssetService m_assetService;
private bool m_dumpAssetsToFile = false;
private bool m_enabled = true;
private int m_levelUpload = 0;
#region IRegionModuleBase Members
public Type ReplaceableInterface
{
get { return null; }
}
public void Initialise(IConfigSource source)
{
IConfig meshConfig = source.Configs["Mesh"];
if (meshConfig == null)
return;
m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
}
public void AddRegion(Scene pScene)
{
m_scene = pScene;
}
public void RemoveRegion(Scene scene)
{
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
m_scene = null;
}
public void RegionLoaded(Scene scene)
{
// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
}
#endregion
#region IRegionModule Members
public void Close() { }
public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
public void RegisterCaps(UUID agentID, Caps caps)
{
if(!m_enabled)
return;
UUID capID = UUID.Random();
// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
caps.RegisterHandler(
"NewFileAgentInventoryVariablePrice",
new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
"POST",
"/CAPS/" + capID.ToString(),
req => NewAgentInventoryRequest(req, agentID),
"NewFileAgentInventoryVariablePrice",
agentID.ToString()));
}
#endregion
public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
{
//TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
// you need to be aware of this
//if (llsdRequest.asset_type == "texture" ||
// llsdRequest.asset_type == "animation" ||
// llsdRequest.asset_type == "sound")
// {
// check user level
ScenePresence avatar = null;
IClientAPI client = null;
m_scene.TryGetScenePresence(agentID, out avatar);
if (avatar != null)
{
client = avatar.ControllingClient;
if (avatar.UserLevel < m_levelUpload)
{
if (client != null)
client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
errorResponse.rsvp = "";
errorResponse.state = "error";
return errorResponse;
}
}
// check funds
IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
if (mm != null)
{
if (!mm.UploadCovered(agentID, mm.UploadCharge))
{
if (client != null)
client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
errorResponse.rsvp = "";
errorResponse.state = "error";
return errorResponse;
}
}
// }
string assetName = llsdRequest.name;
string assetDes = llsdRequest.description;
string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
UUID newAsset = UUID.Random();
UUID newInvItem = UUID.Random();
UUID parentFolder = llsdRequest.folder_id;
string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
AssetUploader uploader =
new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
MainServer.Instance.AddStreamHandler(
new BinaryStreamHandler(
"POST",
capsBase + uploaderPath,
uploader.uploaderCaps,
"NewFileAgentInventoryVariablePrice",
agentID.ToString()));
string protocol = "http://";
if (MainServer.Instance.UseSSL)
protocol = "https://";
string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
uploaderPath;
LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
uploadResponse.rsvp = uploaderURL;
uploadResponse.state = "upload";
uploadResponse.resource_cost = 0;
uploadResponse.upload_price = 0;
uploader.OnUpLoad += //UploadCompleteHandler;
delegate(
string passetName, string passetDescription, UUID passetID,
UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
string passetType)
{
UploadCompleteHandler(passetName, passetDescription, passetID,
pinventoryItem, pparentFolder, pdata, pinventoryType,
passetType,agentID);
};
return uploadResponse;
}
public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
string assetType,UUID AgentID)
{
// m_log.DebugFormat(
// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
sbyte assType = 0;
sbyte inType = 0;
if (inventoryType == "sound")
{
inType = 1;
assType = 1;
}
else if (inventoryType == "animation")
{
inType = 19;
assType = 20;
}
else if (inventoryType == "wearable")
{
inType = 18;
switch (assetType)
{
case "bodypart":
assType = 13;
break;
case "clothing":
assType = 5;
break;
}
}
else if (inventoryType == "mesh")
{
inType = (sbyte)InventoryType.Mesh;
assType = (sbyte)AssetType.Mesh;
}
AssetBase asset;
asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
asset.Data = data;
if (m_scene.AssetService != null)
m_scene.AssetService.Store(asset);
InventoryItemBase item = new InventoryItemBase();
item.Owner = AgentID;
item.CreatorId = AgentID.ToString();
item.ID = inventoryItem;
item.AssetID = asset.FullID;
item.Description = assetDescription;
item.Name = assetName;
item.AssetType = assType;
item.InvType = inType;
item.Folder = parentFolder;
item.CurrentPermissions
= (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
item.BasePermissions = (uint)PermissionMask.All;
item.EveryOnePermissions = 0;
item.NextPermissions = (uint)PermissionMask.All;
item.CreationDate = Util.UnixTimeSinceEpoch();
m_scene.AddInventoryItem(item);
}
}
}

View File

@ -42,6 +42,7 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps; using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers; using OpenSim.Capabilities.Handlers;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.Linden namespace OpenSim.Region.ClientStack.Linden
{ {
@ -58,13 +59,13 @@ namespace OpenSim.Region.ClientStack.Linden
private IInventoryService m_InventoryService; private IInventoryService m_InventoryService;
private ILibraryService m_LibraryService; private ILibraryService m_LibraryService;
private WebFetchInvDescHandler m_webFetchHandler; private static WebFetchInvDescHandler m_webFetchHandler;
private object m_lock = new object();
private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
private Dictionary<UUID, Hashtable> m_requests = new Dictionary<UUID, Hashtable>(); private static Thread[] m_workerThreads = null;
bool m_busy = false;
private static OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs> m_queue =
new OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs>();
#region ISharedRegionModule Members #region ISharedRegionModule Members
@ -94,6 +95,22 @@ namespace OpenSim.Region.ClientStack.Linden
m_scene.EventManager.OnRegisterCaps += RegisterCaps; m_scene.EventManager.OnRegisterCaps += RegisterCaps;
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
if (m_workerThreads == null)
{
m_workerThreads = new Thread[2];
for (uint i = 0; i < 2; i++)
{
m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
String.Format("InventoryWorkerThread{0}", i),
ThreadPriority.Normal,
false,
true,
null,
int.MaxValue);
}
}
} }
public void PostInitialise() public void PostInitialise()
@ -111,13 +128,103 @@ namespace OpenSim.Region.ClientStack.Linden
#endregion #endregion
~WebFetchInvDescModule()
{
foreach (Thread t in m_workerThreads)
t.Abort();
}
private class PollServiceInventoryEventArgs : PollServiceEventArgs
{
private List<Hashtable> requests =
new List<Hashtable>();
private Dictionary<UUID, Hashtable> responses =
new Dictionary<UUID, Hashtable>();
public PollServiceInventoryEventArgs(UUID pId) :
base(null, null, null, null, pId, 30000)
{
HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
GetEvents = (x, y, s) =>
{
try
{
return this.responses[x];
}
finally
{
responses.Remove(x);
}
};
Request = (x, y) =>
{
y["RequestID"] = x.ToString();
lock (this.requests)
this.requests.Add(y);
m_queue.Enqueue(this);
};
NoEvents = (x, y) =>
{
lock (this.requests)
{
Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
requests.Remove(request);
}
Hashtable response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
return response;
};
}
public void Process()
{
Hashtable request = null;
try
{
lock (this.requests)
{
request = requests[0];
requests.RemoveAt(0);
}
}
catch
{
return;
}
UUID requestID = new UUID(request["RequestID"].ToString());
Hashtable response = new Hashtable();
response["int_response_code"] = 200;
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(request["body"].ToString(), String.Empty, String.Empty, null, null);
responses[requestID] = response;
}
}
private void RegisterCaps(UUID agentID, Caps caps) private void RegisterCaps(UUID agentID, Caps caps)
{ {
string capUrl = "/CAPS/" + UUID.Random() + "/"; string capUrl = "/CAPS/" + UUID.Random() + "/";
// Register this as a poll service // Register this as a poll service
// absurd large timeout to tune later to make a bit less than viewer // absurd large timeout to tune later to make a bit less than viewer
PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, agentID, 300000); PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID);
args.Type = PollServiceEventArgs.EventType.Inventory; args.Type = PollServiceEventArgs.EventType.Inventory;
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
@ -135,8 +242,6 @@ namespace OpenSim.Region.ClientStack.Linden
caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
m_capsDict[agentID] = capUrl; m_capsDict[agentID] = capUrl;
m_busy = false;
} }
private void DeregisterCaps(UUID agentID, Caps caps) private void DeregisterCaps(UUID agentID, Caps caps)
@ -150,83 +255,14 @@ namespace OpenSim.Region.ClientStack.Linden
} }
} }
public void HttpRequestHandler(UUID requestID, Hashtable request) private void DoInventoryRequests()
{ {
// m_log.DebugFormat("[FETCH2]: Received request {0}", requestID); while (true)
lock(m_lock)
m_requests[requestID] = request;
}
private bool HasEvents(UUID requestID, UUID sessionID)
{ {
lock (m_lock) PollServiceInventoryEventArgs args = m_queue.Dequeue();
{
return !m_busy;
}
}
private Hashtable NoEvents(UUID requestID, UUID sessionID) args.Process();
{ }
lock(m_lock)
m_requests.Remove(requestID);
Hashtable response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Script timeout";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
lock (m_lock)
m_busy = false;
return response;
}
private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
{
lock (m_lock)
m_busy = true;
Hashtable response = new Hashtable();
response["int_response_code"] = 500;
response["str_response_string"] = "Internal error";
response["content_type"] = "text/plain";
response["keepalive"] = false;
response["reusecontext"] = false;
try
{
Hashtable requestHash;
lock (m_lock)
{
if (!m_requests.TryGetValue(requestID, out requestHash))
{
m_busy = false;
response["str_response_string"] = "Invalid request";
return response;
}
m_requests.Remove(requestID);
}
// m_log.DebugFormat("[FETCH2]: Processed request {0}", requestID);
string reply = m_webFetchHandler.FetchInventoryDescendentsRequest(requestHash["body"].ToString(), String.Empty, String.Empty, null, null);
response["int_response_code"] = 200;
response["str_response_string"] = reply;
}
finally
{
lock (m_lock)
m_busy = false;
}
return response;
} }
} }
} }

View File

@ -218,7 +218,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
id, m_mod.Scene.RegionInfo.RegionName, currentState)); id, m_mod.Scene.RegionInfo.RegionName, currentState));
} }
int count = 200; int count = 400;
// There should be no race condition here since no other code should be removing the agent transfer or // There should be no race condition here since no other code should be removing the agent transfer or
// changing the state to another other than Transferring => ReceivedAtDestination. // changing the state to another other than Transferring => ReceivedAtDestination.

View File

@ -101,12 +101,12 @@ namespace OpenSim.Region.Framework.Scenes
engine.StartProcessing(); engine.StartProcessing();
} }
public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item) public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item, uint cost)
{ {
IMoneyModule money = RequestModuleInterface<IMoneyModule>(); IMoneyModule money = RequestModuleInterface<IMoneyModule>();
if (money != null) if (money != null)
{ {
money.ApplyUploadCharge(agentID, money.UploadCharge, "Asset upload"); money.ApplyUploadCharge(agentID, (int)cost, "Asset upload");
} }
AddInventoryItem(item); AddInventoryItem(item);

View File

@ -4315,7 +4315,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name='agentID'></param> /// <param name='agentID'></param>
protected virtual ScenePresence WaitGetScenePresence(UUID agentID) protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
{ {
int ntimes = 20; int ntimes = 30;
ScenePresence sp = null; ScenePresence sp = null;
while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0))
Thread.Sleep(1000); Thread.Sleep(1000);

View File

@ -193,7 +193,7 @@ namespace OpenSim.Services.Connectors
if (asset == null || asset.Data == null || asset.Data.Length == 0) if (asset == null || asset.Data == null || asset.Data.Length == 0)
{ {
asset = SynchronousRestObjectRequester. asset = SynchronousRestObjectRequester.
MakeRequest<int, AssetBase>("GET", uri, 0); MakeRequest<int, AssetBase>("GET", uri, 0, 30);
if (m_Cache != null) if (m_Cache != null)
m_Cache.Cache(asset); m_Cache.Cache(asset);
@ -321,7 +321,7 @@ namespace OpenSim.Services.Connectors
h.Invoke(a); h.Invoke(a);
if (handlers != null) if (handlers != null)
handlers.Clear(); handlers.Clear();
}); }, 30);
success = true; success = true;
} }

View File

@ -1703,6 +1703,7 @@
<Reference name="OpenSim.Capabilities"/> <Reference name="OpenSim.Capabilities"/>
<Reference name="OpenSim.Capabilities.Handlers"/> <Reference name="OpenSim.Capabilities.Handlers"/>
<Reference name="OpenSim.Framework"/> <Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Monitoring"/>
<Reference name="OpenSim.Framework.Servers"/> <Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/> <Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Framework.Console"/> <Reference name="OpenSim.Framework.Console"/>