Merge branch 'avination' into careminster

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

View File

@@ -26,6 +26,7 @@
*/
using System;
using System.Timers;
using System.Collections;
using System.Collections.Generic;
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 NewInventoryItem(UUID userID, InventoryItemBase item);
public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
public delegate void NewAsset(AssetBase asset);
@@ -386,6 +387,37 @@ namespace OpenSim.Region.ClientStack.Linden
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>
@@ -396,8 +428,11 @@ namespace OpenSim.Region.ClientStack.Linden
//m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
//m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
uint cost = 0;
if (llsdRequest.asset_type == "texture" ||
llsdRequest.asset_type == "animation" ||
llsdRequest.asset_type == "mesh" ||
llsdRequest.asset_type == "sound")
{
ScenePresence avatar = null;
@@ -428,7 +463,33 @@ namespace OpenSim.Region.ClientStack.Linden
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);
@@ -449,9 +510,9 @@ namespace OpenSim.Region.ClientStack.Linden
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, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
AssetUploaderWithCost uploader =
new AssetUploaderWithCost(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost);
m_HostCapsObj.HttpListener.AddStreamHandler(
new BinaryStreamHandler(
@@ -469,11 +530,31 @@ namespace OpenSim.Region.ClientStack.Linden
string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
uploaderPath;
LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
uploadResponse.uploader = uploaderURL;
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;
return uploadResponse;
}
/// <summary>
@@ -484,7 +565,7 @@ namespace OpenSim.Region.ClientStack.Linden
/// <param name="data"></param>
public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
string assetType)
string assetType, uint cost)
{
m_log.DebugFormat(
"[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)
{
AddNewInventoryItem(m_HostCapsObj.AgentID, item);
AddNewInventoryItem(m_HostCapsObj.AgentID, item, cost);
}
}
@@ -1014,6 +1095,9 @@ namespace OpenSim.Region.ClientStack.Linden
public class AssetUploader
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event UpLoadedAsset OnUpLoad;
private UpLoadedAsset handlerUpLoad = null;
@@ -1028,6 +1112,7 @@ namespace OpenSim.Region.ClientStack.Linden
private string m_invType = String.Empty;
private string m_assetType = String.Empty;
private Timer m_timeoutTimer = new Timer();
public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
UUID parentFolderID, string invType, string assetType, string path,
@@ -1043,6 +1128,11 @@ namespace OpenSim.Region.ClientStack.Linden
m_assetType = assetType;
m_invType = invType;
m_dumpAssetsToFile = dumpAssetsToFile;
m_timeoutTimer.Elapsed += TimedOut;
m_timeoutTimer.Interval = 120000;
m_timeoutTimer.AutoReset = false;
m_timeoutTimer.Start();
}
/// <summary>
@@ -1064,6 +1154,7 @@ namespace OpenSim.Region.ClientStack.Linden
res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
httpListener.RemoveStreamHandler("POST", uploaderPath);
m_timeoutTimer.Stop();
// TODO: probably make this a better set of extensions here
string extension = ".jp2";
@@ -1085,6 +1176,12 @@ namespace OpenSim.Region.ClientStack.Linden
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
//private void SaveAssetToFile(string filename, byte[] data)
//{

View File

@@ -27,18 +27,13 @@
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System.Web;
using System.Threading;
using log4net;
using Nini.Config;
using Mono.Addins;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
@@ -47,64 +42,73 @@ using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers;
using OpenSim.Framework.Monitoring;
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
{
// private static readonly ILog m_log =
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
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
const string REDIRECT_URL = null;
private IAssetService m_assetService = 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
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)
{
if (!m_Enabled)
return;
m_scene = s;
m_assetService = s.AssetService;
}
public void RemoveRegion(Scene s)
{
if (!m_Enabled)
return;
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
m_scene = null;
}
public void RegionLoaded(Scene s)
{
if (!m_Enabled)
return;
// We'll reuse the same handler for all requests.
m_getTextureHandler = new GetTextureHandler(m_assetService);
m_assetService = m_scene.RequestModuleInterface<IAssetService>();
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()
@@ -122,24 +126,155 @@ namespace OpenSim.Region.ClientStack.Linden
#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")
private class PollServiceTextureEventArgs : PollServiceEventArgs
{
private List<Hashtable> requests =
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_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()));
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;
};
}
else
public void Process()
{
// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
caps.RegisterHandler("GetTexture", m_URL);
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 Caps = OpenSim.Framework.Capabilities.Caps;
using OpenSim.Capabilities.Handlers;
using OpenSim.Framework.Monitoring;
namespace OpenSim.Region.ClientStack.Linden
{
@@ -58,13 +59,13 @@ namespace OpenSim.Region.ClientStack.Linden
private IInventoryService m_InventoryService;
private ILibraryService m_LibraryService;
private WebFetchInvDescHandler m_webFetchHandler;
private object m_lock = new object();
private static WebFetchInvDescHandler m_webFetchHandler;
private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
private Dictionary<UUID, Hashtable> m_requests = new Dictionary<UUID, Hashtable>();
bool m_busy = false;
private static Thread[] m_workerThreads = null;
private static OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs> m_queue =
new OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs>();
#region ISharedRegionModule Members
@@ -94,6 +95,22 @@ namespace OpenSim.Region.ClientStack.Linden
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
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()
@@ -111,13 +128,103 @@ namespace OpenSim.Region.ClientStack.Linden
#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)
{
string capUrl = "/CAPS/" + UUID.Random() + "/";
// Register this as a poll service
// 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;
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));
m_capsDict[agentID] = capUrl;
m_busy = false;
}
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);
lock(m_lock)
m_requests[requestID] = request;
}
private bool HasEvents(UUID requestID, UUID sessionID)
{
lock (m_lock)
while (true)
{
return !m_busy;
PollServiceInventoryEventArgs args = m_queue.Dequeue();
args.Process();
}
}
private Hashtable NoEvents(UUID requestID, UUID sessionID)
{
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;
}
}
}