From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Linden/Caps/AgentPreferencesModule.cs | 2 +- .../Linden/Caps/AvatarPickerSearchModule.cs | 2 +- .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 1610 ++++++++++++++++---- .../Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs | 6 +- .../Linden/Caps/BunchOfCaps/MeshCost.cs | 746 +++++++++ .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 521 ++----- .../Linden/Caps/EventQueue/EventQueueHelper.cs | 110 +- .../Caps/EventQueue/Tests/EventQueueTests.cs | 14 +- .../Linden/Caps/GetDisplayNamesModule.cs | 144 -- .../ClientStack/Linden/Caps/GetMeshModule.cs | 329 +++- .../ClientStack/Linden/Caps/GetTextureModule.cs | 412 ++++- .../Linden/Caps/MeshUploadFlagModule.cs | 22 +- .../NewFileAgentInventoryVariablePriceModule.cs | 297 ---- .../Linden/Caps/ObjectCaps/ObjectAdd.cs | 14 +- .../Caps/ObjectCaps/UploadObjectAssetModule.cs | 18 +- .../Linden/Caps/Properties/AssemblyInfo.cs | 10 +- .../ClientStack/Linden/Caps/RegionConsoleModule.cs | 18 +- .../Linden/Caps/SimulatorFeaturesModule.cs | 17 +- .../Caps/Tests/WebFetchInvDescModuleTests.cs | 4 +- .../Linden/Caps/UploadBakedTextureModule.cs | 203 +-- .../Linden/Caps/WebFetchInvDescModule.cs | 101 +- 21 files changed, 3085 insertions(+), 1515 deletions(-) create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs delete mode 100644 OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs delete mode 100644 OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs (limited to 'OpenSim/Region/ClientStack/Linden/Caps') diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs index aabdb51..8f65a69 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AgentPreferencesModule.cs @@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenCaps { data = new AgentPrefs(agent); } - + if (req.ContainsKey("access_prefs")) { OSDMap accessPrefs = (OSDMap)req["access_prefs"]; // We could check with ContainsKey... diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs index bbadc55..e3c430c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.ClientStack.Linden public class AvatarPickerSearchModule : INonSharedRegionModule { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; private IPeople m_People; private bool m_Enabled = false; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 774202e..6f5775a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -26,11 +26,14 @@ */ using System; +using System.Timers; using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Reflection; using System.Text; +using System.Web; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -40,11 +43,11 @@ using log4net; using OpenSim.Framework; using OpenSim.Framework.Capabilities; using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Framework.Client; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; @@ -55,14 +58,16 @@ using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.ClientStack.Linden { public delegate void UpLoadedAsset( - string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, - byte[] data, string inventoryType, string assetType); + string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolder, + byte[] data, string inventoryType, string assetType, + int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, + bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask); public delegate UUID UpdateItem(UUID itemID, byte[] data); 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); @@ -87,21 +92,12 @@ namespace OpenSim.Region.ClientStack.Linden LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_Scene; + private UUID m_AgentID; private Caps m_HostCapsObj; + private ModelCost m_ModelCost; - private static readonly string m_requestPath = "0000/"; - // private static readonly string m_mapLayerPath = "0001/"; - private static readonly string m_newInventory = "0002/"; - //private static readonly string m_requestTexture = "0003/"; - private static readonly string m_notecardUpdatePath = "0004/"; - private static readonly string m_notecardTaskUpdatePath = "0005/"; - // private static readonly string m_fetchInventoryPath = "0006/"; - private static readonly string m_copyFromNotecardPath = "0007/"; // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. - private static readonly string m_getObjectPhysicsDataPath = "0101/"; - /* 0102 - 0103 RESERVED */ - private static readonly string m_UpdateAgentInformationPath = "0500/"; - + // These are callbacks which will be setup by the scene so that we can update scene data when we // receive capability calls public NewInventoryItem AddNewInventoryItem = null; @@ -115,12 +111,45 @@ namespace OpenSim.Region.ClientStack.Linden private IAssetService m_assetService; private bool m_dumpAssetsToFile = false; private string m_regionName; + private int m_levelUpload = 0; - public BunchOfCaps(Scene scene, Caps caps) + private bool m_enableFreeTestUpload = false; // allows "TEST-" prefix hack + private bool m_ForceFreeTestUpload = false; // forces all uploads to be test + + private bool m_enableModelUploadTextureToInventory = false; // place uploaded textures also in inventory + // may not be visible till relog + + private bool m_RestrictFreeTestUploadPerms = false; // reduces also the permitions. Needs a creator defined!! + private UUID m_testAssetsCreatorID = UUID.Zero; + + private float m_PrimScaleMin = 0.001f; + + private bool m_AllowCapHomeLocation = true; + private bool m_AllowCapGroupMemberData = true; + private IUserManagement m_UserManager; + + + private enum FileAgentInventoryState : int + { + idle = 0, + processRequest = 1, + waitUpload = 2, + processUpload = 3 + } + private FileAgentInventoryState m_FileAgentInventoryState = FileAgentInventoryState.idle; + + public BunchOfCaps(Scene scene, UUID agentID, Caps caps) { m_Scene = scene; + m_AgentID = agentID; m_HostCapsObj = caps; + + // create a model upload cost provider + m_ModelCost = new ModelCost(scene); + + m_PrimScaleMin = m_ModelCost.PrimScaleMin; + IConfigSource config = m_Scene.Config; if (config != null) { @@ -135,10 +164,45 @@ namespace OpenSim.Region.ClientStack.Linden { m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); } + // economy for model upload + IConfig EconomyConfig = config.Configs["Economy"]; + if (EconomyConfig != null) + { + m_ModelCost.Econfig(EconomyConfig); + + m_enableModelUploadTextureToInventory = EconomyConfig.GetBoolean("MeshModelAllowTextureToInventory", m_enableModelUploadTextureToInventory); + + m_RestrictFreeTestUploadPerms = EconomyConfig.GetBoolean("m_RestrictFreeTestUploadPerms", m_RestrictFreeTestUploadPerms); + m_enableFreeTestUpload = EconomyConfig.GetBoolean("AllowFreeTestUpload", m_enableFreeTestUpload); + m_ForceFreeTestUpload = EconomyConfig.GetBoolean("ForceFreeTestUpload", m_ForceFreeTestUpload); + string testcreator = EconomyConfig.GetString("TestAssetsCreatorID", ""); + if (testcreator != "") + { + UUID id; + UUID.TryParse(testcreator, out id); + if (id != null) + m_testAssetsCreatorID = id; + } + } + + IConfig CapsConfig = config.Configs["ClientStack.LindenCaps"]; + if (CapsConfig != null) + { + string homeLocationUrl = CapsConfig.GetString("Cap_HomeLocation", "localhost"); + if(homeLocationUrl == String.Empty) + m_AllowCapHomeLocation = false; + + string GroupMemberDataUrl = CapsConfig.GetString("Cap_GroupMemberData", "localhost"); + if(GroupMemberDataUrl == String.Empty) + m_AllowCapGroupMemberData = false; + } } m_assetService = m_Scene.AssetService; m_regionName = m_Scene.RegionInfo.RegionName; + m_UserManager = m_Scene.RequestModuleInterface(); + if (m_UserManager == null) + m_log.Error("[CAPS]: GetDisplayNames disabled because user management component not found"); RegisterHandlers(); @@ -146,6 +210,13 @@ namespace OpenSim.Region.ClientStack.Linden ItemUpdatedCall = m_Scene.CapsUpdateInventoryItemAsset; TaskScriptUpdatedCall = m_Scene.CapsUpdateTaskInventoryScriptAsset; GetClient = m_Scene.SceneGraph.GetControllingClient; + + m_FileAgentInventoryState = FileAgentInventoryState.idle; + } + + public string GetNewCapPath() + { + return "/CAPS/" + UUID.Random(); } /// @@ -153,33 +224,67 @@ namespace OpenSim.Region.ClientStack.Linden /// public void RegisterHandlers() { - string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; + // this path is also defined elsewhere so keeping it + string seedcapsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath +"0000/"; - RegisterRegionServiceHandlers(capsBase); - RegisterInventoryServiceHandlers(capsBase); + // the root of all evil path needs to be capsBase + m_requestPath + m_HostCapsObj.RegisterHandler( + "SEED", new RestStreamHandler("POST", seedcapsBase, SeedCapRequest, "SEED", null)); + +// m_log.DebugFormat( +// "[CAPS]: Registered seed capability {0} for {1}", seedcapsBase, m_HostCapsObj.AgentID); + + RegisterRegionServiceHandlers(); + RegisterInventoryServiceHandlers(); + RegisterOtherHandlers(); } - public void RegisterRegionServiceHandlers(string capsBase) + public void RegisterRegionServiceHandlers() { try { - // the root of all evil - m_HostCapsObj.RegisterHandler( - "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); - -// m_log.DebugFormat( -// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); - //m_capsHandlers["MapLayer"] = // new LLSDStreamhandler("POST", - // capsBase + m_mapLayerPath, - // GetMapLayer); - IRequestHandler req - = new RestStreamHandler( - "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); + // GetNewCapPath(), + // GetMapLayer); + + IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler( + "POST", GetNewCapPath(), GetObjectPhysicsData, "GetObjectPhysicsData", null); + m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); + + IRequestHandler getObjectCostHandler = new RestStreamHandler( + "POST", GetNewCapPath(), GetObjectCost, "GetObjectCost", null ); + m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler); + IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler( + "POST", GetNewCapPath(), ResourceCostSelected, "ResourceCostSelected", null); + m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); + + IRequestHandler req = new RestStreamHandler( + "POST", GetNewCapPath(), ScriptTaskInventory, "UpdateScript", null); m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); + + if(m_AllowCapHomeLocation) + { + IRequestHandler HomeLocationHandler = new RestStreamHandler( + "POST", GetNewCapPath(), HomeLocation, "HomeLocation", null); + m_HostCapsObj.RegisterHandler("HomeLocation", HomeLocationHandler); + } + + if(m_AllowCapGroupMemberData) + { + IRequestHandler GroupMemberDataHandler = new RestStreamHandler( + "POST", GetNewCapPath(), GroupMemberData, "GroupMemberData", null); + m_HostCapsObj.RegisterHandler("GroupMemberData", GroupMemberDataHandler); + } + + +// IRequestHandler animSetRequestHandler +// = new RestStreamHandler( +// "POST", capsBase + m_animSetTaskUpdatePath, AnimSetTaskInventory, "UpdateScript", null); + +// m_HostCapsObj.RegisterHandler("UpdateAnimSetTaskInventory", animSetRequestHandler); } catch (Exception e) { @@ -187,68 +292,29 @@ namespace OpenSim.Region.ClientStack.Linden } } - public void RegisterInventoryServiceHandlers(string capsBase) + public void RegisterInventoryServiceHandlers() { try { - // I don't think this one works... - m_HostCapsObj.RegisterHandler( - "NewFileAgentInventory", + m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler( - "POST", - capsBase + m_newInventory, - NewAgentInventoryRequest, - "NewFileAgentInventory", - null)); - - IRequestHandler req - = new RestStreamHandler( - "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); + "POST", GetNewCapPath(), NewAgentInventoryRequest, "NewFileAgentInventory", null)); + IRequestHandler req = new RestStreamHandler( + "POST", GetNewCapPath(), NoteCardAgentInventory, "Update*", null); m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); + m_HostCapsObj.RegisterHandler("UpdateAnimSetAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); - IRequestHandler getObjectPhysicsDataHandler - = new RestStreamHandler( - "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); - m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); - - IRequestHandler UpdateAgentInformationHandler - = new RestStreamHandler( - "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); + IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler( + "POST", GetNewCapPath(), UpdateAgentInformation, "UpdateAgentInformation", null); m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); - m_HostCapsObj.RegisterHandler( - "CopyInventoryFromNotecard", - new RestStreamHandler( - "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null)); - - // As of RC 1.22.9 of the Linden client this is - // supported - - //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); - - // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and - // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires - // enhancements (probably filling out the folder part of the LLSD reply) to our CAPS service, - // but when I went on the Linden grid, the - // simulators I visited (version 1.21) were, surprisingly, no longer supplying this capability. Instead, - // the 1.19.1.4 client appeared to be happily flowing inventory data over UDP - // - // This is very probably just a temporary measure - once the CAPS service appears again on the Linden grid - // we will be - // able to get the data we need to implement the necessary part of the protocol to fix the issue above. - // m_capsHandlers["FetchInventoryDescendents"] = - // new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryRequest); - - // m_capsHandlers["FetchInventoryDescendents"] = - // new LLSDStreamhandler("POST", - // capsBase + m_fetchInventory, - // FetchInventory)); - // m_capsHandlers["RequestTextureDownload"] = new RestStreamHandler("POST", - // capsBase + m_requestTexture, - // RequestTexture); + IRequestHandler CopyInventoryFromNotecardHandler = new RestStreamHandler( + "POST", GetNewCapPath(), CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null); + m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", CopyInventoryFromNotecardHandler); + } catch (Exception e) { @@ -256,6 +322,22 @@ namespace OpenSim.Region.ClientStack.Linden } } + public void RegisterOtherHandlers() + { + try + { + if (m_UserManager != null) + { + IRequestHandler GetDisplayNamesHandler = new RestStreamHandler( + "GET", GetNewCapPath(), GetDisplayNames, "GetDisplayNames", null); + m_HostCapsObj.RegisterHandler("GetDisplayNames", GetDisplayNamesHandler); + } + } + catch (Exception e) + { + m_log.Error("[CAPS]: " + e.ToString()); + } + } /// /// Construct a client response detailing all the capabilities this server can provide. /// @@ -268,8 +350,11 @@ namespace OpenSim.Region.ClientStack.Linden public string SeedCapRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { -// m_log.DebugFormat( -// "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); + m_log.DebugFormat( + "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID); + + if (!m_HostCapsObj.WaitForActivation()) + return string.Empty; if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) { @@ -314,30 +399,28 @@ namespace OpenSim.Region.ClientStack.Linden LLSDTaskScriptUpdate llsdUpdateRequest = new LLSDTaskScriptUpdate(); LLSDHelpers.DeserialiseOSDMap(hash, llsdUpdateRequest); - string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + string uploaderPath = GetNewCapPath(); TaskInventoryScriptUpdater uploader = new TaskInventoryScriptUpdater( llsdUpdateRequest.item_id, llsdUpdateRequest.task_id, llsdUpdateRequest.is_script_running, - capsBase + uploaderPath, + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); uploader.OnUpLoad += TaskScriptUpdated; m_HostCapsObj.HttpListener.AddStreamHandler( new BinaryStreamHandler( - "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); + "POST", uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); string protocol = "http://"; if (m_HostCapsObj.SSLCaps) protocol = "https://"; - string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + - uploaderPath; + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); uploadResponse.uploader = uploaderURL; @@ -400,83 +483,208 @@ 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); + // start by getting the client + IClientAPI client = null; + m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); + + // check current state so we only have one service at a time + lock (m_ModelCost) + { + switch (m_FileAgentInventoryState) + { + case FileAgentInventoryState.processRequest: + case FileAgentInventoryState.processUpload: + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = "Uploader busy processing previus request"; + resperror.identifier = UUID.Zero; + + LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); + errorResponse.uploader = ""; + errorResponse.state = "error"; + errorResponse.error = resperror; + return errorResponse; + break; + case FileAgentInventoryState.waitUpload: + // todo stop current uploader server + break; + case FileAgentInventoryState.idle: + default: + break; + } + + m_FileAgentInventoryState = FileAgentInventoryState.processRequest; + } + + int cost = 0; + int nreqtextures = 0; + int nreqmeshs= 0; + int nreqinstances = 0; + bool IsAtestUpload = false; + + string assetName = llsdRequest.name; + + LLSDAssetUploadResponseData meshcostdata = new LLSDAssetUploadResponseData(); + if (llsdRequest.asset_type == "texture" || llsdRequest.asset_type == "animation" || + llsdRequest.asset_type == "animatn" || // this is the asset name actually used by viewers + llsdRequest.asset_type == "mesh" || llsdRequest.asset_type == "sound") { ScenePresence avatar = null; - IClientAPI client = null; m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); // check user level if (avatar != null) { - client = avatar.ControllingClient; - - if (avatar.UserLevel < m_levelUpload) + if (avatar.GodController.UserLevel < m_levelUpload) { - if (client != null) - client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = "Insufficient permissions to upload"; + resperror.identifier = UUID.Zero; LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); errorResponse.uploader = ""; errorResponse.state = "error"; + errorResponse.error = resperror; + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.idle; return errorResponse; } } - // check funds + // check test upload and funds if (client != null) { IMoneyModule mm = m_Scene.RequestModuleInterface(); + int baseCost = 0; if (mm != null) + baseCost = mm.UploadCharge; + + string warning = String.Empty; + + if (llsdRequest.asset_type == "mesh") { - if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) + string error; + int modelcost; + + + if (!m_ModelCost.MeshModelCost(llsdRequest.asset_resources, baseCost, out modelcost, + meshcostdata, out error, ref warning)) { - client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = error; + resperror.identifier = UUID.Zero; LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); errorResponse.uploader = ""; errorResponse.state = "error"; + errorResponse.error = resperror; + + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.idle; return errorResponse; } + cost = modelcost; + } + else + { + cost = baseCost; } + + if (cost > 0 && mm != null) + { + // check for test upload + + if (m_ForceFreeTestUpload) // all are test + { + if (!(assetName.Length > 5 && assetName.StartsWith("TEST-"))) // has normal name lets change it + assetName = "TEST-" + assetName; + + IsAtestUpload = true; + } + + else if (m_enableFreeTestUpload) // only if prefixed with "TEST-" + { + + IsAtestUpload = (assetName.Length > 5 && assetName.StartsWith("TEST-")); + } + + + if(IsAtestUpload) // let user know, still showing cost estimation + warning += "Upload will have no cost, for testing purposes only. Other uses are prohibited. Items will not work after 48 hours or on other regions"; + + // check funds + else + { + if (!mm.UploadCovered(client.AgentId, (int)cost)) + { + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = "Insuficient funds"; + resperror.identifier = UUID.Zero; + + LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse(); + errorResponse.uploader = ""; + errorResponse.state = "error"; + errorResponse.error = resperror; + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.idle; + return errorResponse; + } + } + } + + if (client != null && warning != String.Empty) + client.SendAgentAlertMessage(warning, true); } } - string assetName = llsdRequest.name; string assetDes = llsdRequest.description; - string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; UUID newAsset = UUID.Random(); UUID newInvItem = UUID.Random(); UUID parentFolder = llsdRequest.folder_id; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + string uploaderPath = GetNewCapPath(); + UUID texturesFolder = UUID.Zero; + + if(!IsAtestUpload && m_enableModelUploadTextureToInventory) + texturesFolder = llsdRequest.texture_folder_id; AssetUploader uploader = new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, - llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); + llsdRequest.asset_type, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost, + texturesFolder, nreqtextures, nreqmeshs, nreqinstances, IsAtestUpload, + llsdRequest.next_owner_mask, llsdRequest.group_mask, llsdRequest.everyone_mask); m_HostCapsObj.HttpListener.AddStreamHandler( new BinaryStreamHandler( "POST", - capsBase + uploaderPath, + uploaderPath, uploader.uploaderCaps, "NewAgentInventoryRequest", m_HostCapsObj.AgentID.ToString())); string protocol = "http://"; - if (m_HostCapsObj.SSLCaps) protocol = "https://"; - string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + - uploaderPath; + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); uploadResponse.uploader = uploaderURL; uploadResponse.state = "upload"; + uploadResponse.upload_price = (int)cost; + + if (llsdRequest.asset_type == "mesh") + { + uploadResponse.data = meshcostdata; + } + uploader.OnUpLoad += UploadCompleteHandler; + + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.waitUpload; + return uploadResponse; } @@ -488,8 +696,14 @@ namespace OpenSim.Region.ClientStack.Linden /// public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, - string assetType) + string assetType, int cost, + UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, + bool IsAtestUpload, ref string error, + ref int nextOwnerMask, ref int groupMask, ref int everyoneMask) { + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.processUpload; + m_log.DebugFormat( "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", assetID, inventoryItem, inventoryType, assetType); @@ -497,6 +711,34 @@ namespace OpenSim.Region.ClientStack.Linden sbyte assType = 0; sbyte inType = 0; + IClientAPI client = null; + + UUID owner_id = m_HostCapsObj.AgentID; + UUID creatorID; + + bool istest = IsAtestUpload && m_enableFreeTestUpload && (cost > 0); + + bool restrictPerms = m_RestrictFreeTestUploadPerms && istest; + + if (istest && m_testAssetsCreatorID != UUID.Zero) + creatorID = m_testAssetsCreatorID; + else + creatorID = owner_id; + + string creatorIDstr = creatorID.ToString(); + + IMoneyModule mm = m_Scene.RequestModuleInterface(); + if (mm != null) + { + // make sure client still has enougth credit + if (!mm.UploadCovered(m_HostCapsObj.AgentID, (int)cost)) + { + error = "Insufficient funds."; + return; + } + } + + // strings to types if (inventoryType == "sound") { inType = (sbyte)InventoryType.Sound; @@ -511,6 +753,12 @@ namespace OpenSim.Region.ClientStack.Linden inType = (sbyte)InventoryType.Animation; assType = (sbyte)AssetType.Animation; } + else if (inventoryType == "animset") + { + inType = (sbyte)CustomInventoryType.AnimationSet; + assType = (sbyte)CustomAssetType.AnimationSet; + m_log.Debug("got animset upload request"); + } else if (inventoryType == "wearable") { inType = (sbyte)InventoryType.Wearable; @@ -526,191 +774,290 @@ namespace OpenSim.Region.ClientStack.Linden } else if (inventoryType == "object") { - inType = (sbyte)InventoryType.Object; - assType = (sbyte)AssetType.Object; - - List positions = new List(); - List rotations = new List(); - OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); - OSDArray instance_list = (OSDArray)request["instance_list"]; - OSDArray mesh_list = (OSDArray)request["mesh_list"]; - OSDArray texture_list = (OSDArray)request["texture_list"]; - SceneObjectGroup grp = null; + if (assetType == "mesh") // this code for now is for mesh models uploads only + { + inType = (sbyte)InventoryType.Object; + assType = (sbyte)AssetType.Object; - InventoryFolderBase textureUploadFolder = null; + List positions = new List(); + List rotations = new List(); + OSDMap request = (OSDMap)OSDParser.DeserializeLLSDXml(data); - List foldersToUpdate = new List(); - List itemsToUpdate = new List(); - IClientInventory clientInv = null; - - if (texture_list.Count > 0) - { - ScenePresence avatar = null; - m_Scene.TryGetScenePresence(m_HostCapsObj.AgentID, out avatar); + // compare and get updated information +/* does nothing still we do need something to avoid special viewer to upload something diferent from the cost estimation + bool mismatchError = true; - if (avatar != null) + while (mismatchError) { - IClientCore core = (IClientCore)avatar.ControllingClient; + mismatchError = false; + } + + if (mismatchError) + { + error = "Upload and fee estimation information don't match"; + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.idle; + + return; + } +*/ + OSDArray instance_list = (OSDArray)request["instance_list"]; + OSDArray mesh_list = (OSDArray)request["mesh_list"]; + OSDArray texture_list = (OSDArray)request["texture_list"]; + SceneObjectGroup grp = null; + + // create and store texture assets + bool doTextInv = (!istest && m_enableModelUploadTextureToInventory && + texturesFolder != UUID.Zero); + + + List textures = new List(); + + +// if (doTextInv) + m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); + + if(client == null) // don't put textures in inventory if there is no client + doTextInv = false; - if (core.TryGet(out clientInv)) + for (int i = 0; i < texture_list.Count; i++) + { + AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, creatorIDstr); + textureAsset.Data = texture_list[i].AsBinary(); + if (istest) + textureAsset.Local = true; + m_assetService.Store(textureAsset); + textures.Add(textureAsset.FullID); + + if (doTextInv) { - var systemTextureFolder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, FolderType.Texture); - textureUploadFolder = new InventoryFolderBase(UUID.Random(), assetName, m_HostCapsObj.AgentID, (short)FolderType.None, systemTextureFolder.ID, 1); - if (m_Scene.InventoryService.AddFolder(textureUploadFolder)) - { - foldersToUpdate.Add(textureUploadFolder); + string name = assetName; + if (name.Length > 25) + name = name.Substring(0, 24); + name += "_Texture#" + i.ToString(); + InventoryItemBase texitem = new InventoryItemBase(); + texitem.Owner = m_HostCapsObj.AgentID; + texitem.CreatorId = creatorIDstr; + texitem.CreatorData = String.Empty; + texitem.ID = UUID.Random(); + texitem.AssetID = textureAsset.FullID; + texitem.Description = "mesh model texture"; + texitem.Name = name; + texitem.AssetType = (int)AssetType.Texture; + texitem.InvType = (int)InventoryType.Texture; + texitem.Folder = texturesFolder; + + texitem.CurrentPermissions + = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); + + texitem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; + texitem.EveryOnePermissions = 0; + texitem.NextPermissions = (uint)PermissionMask.All; + texitem.CreationDate = Util.UnixTimeSinceEpoch(); + + m_Scene.AddInventoryItem(client, texitem); + texitem = null; + } + } - m_log.DebugFormat( - "[BUNCH OF CAPS]: Created new folder '{0}' ({1}) for textures uploaded with mesh object {2}", - textureUploadFolder.Name, textureUploadFolder.ID, assetName); - } - else + // create and store meshs assets + List meshAssets = new List(); + List meshAvatarSkeletons = new List(); + List meshAvatarColliders = new List(); + + bool curAvSkeleton; + bool curAvCollider; + for (int i = 0; i < mesh_list.Count; i++) + { + curAvSkeleton = false; + curAvCollider = false; + + // we do need to parse the mesh now + OSD osd = OSDParser.DeserializeLLSDBinary(mesh_list[i]); + if (osd is OSDMap) + { + OSDMap mosd = (OSDMap)osd; + if (mosd.ContainsKey("skeleton")) { - textureUploadFolder = null; + OSDMap skeleton = (OSDMap)mosd["skeleton"]; + int sksize = skeleton["size"].AsInteger(); + if (sksize > 0) + curAvSkeleton = true; } } - } - } - List textures = new List(); - for (int i = 0; i < texture_list.Count; i++) - { - AssetBase textureAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Texture, ""); - textureAsset.Data = texture_list[i].AsBinary(); - m_assetService.Store(textureAsset); - textures.Add(textureAsset.FullID); + AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, creatorIDstr); + meshAsset.Data = mesh_list[i].AsBinary(); + if (istest) + meshAsset.Local = true; + m_assetService.Store(meshAsset); + meshAssets.Add(meshAsset.FullID); + meshAvatarSkeletons.Add(curAvSkeleton); + meshAvatarColliders.Add(curAvCollider); + + // test code + if (curAvSkeleton && client != null) + { + string name = assetName; + if (name.Length > 25) + name = name.Substring(0, 24); + name += "_Mesh#" + i.ToString(); + InventoryItemBase meshitem = new InventoryItemBase(); + meshitem.Owner = m_HostCapsObj.AgentID; + meshitem.CreatorId = creatorIDstr; + meshitem.CreatorData = String.Empty; + meshitem.ID = UUID.Random(); + meshitem.AssetID = meshAsset.FullID; + meshitem.Description = "mesh "; + meshitem.Name = name; + meshitem.AssetType = (int)AssetType.Mesh; + meshitem.InvType = (int)InventoryType.Mesh; + // meshitem.Folder = UUID.Zero; // send to default + + meshitem.Folder = parentFolder; // dont let it go to folder Meshes that viewers dont show + + // If we set PermissionMask.All then when we rez the item the next permissions will replace the current + // (owner) permissions. This becomes a problem if next permissions are changed. + meshitem.CurrentPermissions + = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer); + + meshitem.BasePermissions = (uint)PermissionMask.All; + meshitem.EveryOnePermissions = 0; + meshitem.NextPermissions = (uint)PermissionMask.All; + meshitem.CreationDate = Util.UnixTimeSinceEpoch(); + + m_Scene.AddInventoryItem(client, meshitem); + meshitem = null; + } + } - if (textureUploadFolder != null) + int skipedMeshs = 0; + // build prims from instances + for (int i = 0; i < instance_list.Count; i++) { - InventoryItemBase textureItem = new InventoryItemBase(); - textureItem.Owner = m_HostCapsObj.AgentID; - textureItem.CreatorId = m_HostCapsObj.AgentID.ToString(); - textureItem.CreatorData = String.Empty; - textureItem.ID = UUID.Random(); - textureItem.AssetID = textureAsset.FullID; - textureItem.Description = assetDescription; - textureItem.Name = assetName + " - Texture " + (i + 1).ToString(); - textureItem.AssetType = (int)AssetType.Texture; - textureItem.InvType = (int)InventoryType.Texture; - textureItem.Folder = textureUploadFolder.ID; - textureItem.CurrentPermissions - = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); - textureItem.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; - textureItem.EveryOnePermissions = 0; - textureItem.NextPermissions = (uint)PermissionMask.All; - textureItem.CreationDate = Util.UnixTimeSinceEpoch(); - m_Scene.InventoryService.AddItem(textureItem); - itemsToUpdate.Add(textureItem); - - m_log.DebugFormat( - "[BUNCH OF CAPS]: Created new inventory item '{0}' ({1}) for texture uploaded with mesh object {2}", - textureItem.Name, textureItem.ID, assetName); - } - } + OSDMap inner_instance_list = (OSDMap)instance_list[i]; - if (clientInv != null && (foldersToUpdate.Count > 0 || itemsToUpdate.Count > 0)) - { - clientInv.SendBulkUpdateInventory(foldersToUpdate.ToArray(), itemsToUpdate.ToArray()); - } + // skip prims that are 2 small + Vector3 scale = inner_instance_list["scale"].AsVector3(); - for (int i = 0; i < mesh_list.Count; i++) - { - PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); + if (scale.X < m_PrimScaleMin || scale.Y < m_PrimScaleMin || scale.Z < m_PrimScaleMin) + { + skipedMeshs++; + continue; + } - Primitive.TextureEntry textureEntry - = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); - OSDMap inner_instance_list = (OSDMap)instance_list[i]; + OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; - OSDArray face_list = (OSDArray)inner_instance_list["face_list"]; - for (uint face = 0; face < face_list.Count; face++) - { - OSDMap faceMap = (OSDMap)face_list[(int)face]; - Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face); - if(faceMap.ContainsKey("fullbright")) - f.Fullbright = faceMap["fullbright"].AsBoolean(); - if (faceMap.ContainsKey ("diffuse_color")) - f.RGBA = faceMap["diffuse_color"].AsColor4(); + PrimitiveBaseShape pbs = null; + if (inner_instance_list.ContainsKey("mesh")) // seems to happen always but ... + { + int meshindx = inner_instance_list["mesh"].AsInteger(); + if (meshAssets.Count > meshindx) + pbs = PrimitiveBaseShape.CreateMesh(face_list.Count, meshAssets[meshindx]); + } + if(pbs == null) // fallback + pbs = PrimitiveBaseShape.CreateBox(); + + Primitive.TextureEntry textureEntry + = new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE); - int textureNum = faceMap["image"].AsInteger(); - float imagerot = faceMap["imagerot"].AsInteger(); - float offsets = (float)faceMap["offsets"].AsReal(); - float offsett = (float)faceMap["offsett"].AsReal(); - float scales = (float)faceMap["scales"].AsReal(); - float scalet = (float)faceMap["scalet"].AsReal(); + for (uint face = 0; face < face_list.Count; face++) + { + OSDMap faceMap = (OSDMap)face_list[(int)face]; - if(imagerot != 0) - f.Rotation = imagerot; + Primitive.TextureEntryFace f = textureEntry.CreateFace(face); //clone the default + if (faceMap.ContainsKey("fullbright")) + f.Fullbright = faceMap["fullbright"].AsBoolean(); + if (faceMap.ContainsKey("diffuse_color")) + f.RGBA = faceMap["diffuse_color"].AsColor4(); - if(offsets != 0) - f.OffsetU = offsets; + int textureNum = faceMap["image"].AsInteger(); + float imagerot = faceMap["imagerot"].AsInteger(); + float offsets = (float)faceMap["offsets"].AsReal(); + float offsett = (float)faceMap["offsett"].AsReal(); + float scales = (float)faceMap["scales"].AsReal(); + float scalet = (float)faceMap["scalet"].AsReal(); - if (offsett != 0) - f.OffsetV = offsett; + if (imagerot != 0) + f.Rotation = imagerot; - if (scales != 0) - f.RepeatU = scales; + if (offsets != 0) + f.OffsetU = offsets; - if (scalet != 0) - f.RepeatV = scalet; + if (offsett != 0) + f.OffsetV = offsett; - if (textures.Count > textureNum) - f.TextureID = textures[textureNum]; + if (scales != 0) + f.RepeatU = scales; + + if (scalet != 0) + f.RepeatV = scalet; + + if (textures.Count > textureNum) + f.TextureID = textures[textureNum]; + + textureEntry.FaceTextures[face] = f; + } + pbs.TextureEntry = textureEntry.GetBytes(); + + Vector3 position = inner_instance_list["position"].AsVector3(); + Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); + + // for now viwers do send fixed defaults + // but this may change +// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); + byte physicsShapeType = (byte)PhysShapeType.convex; // default is simple convex +// int material = inner_instance_list["material"].AsInteger(); + byte material = (byte)Material.Wood; + + SceneObjectPart prim + = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); + + prim.Scale = scale; + rotations.Add(rotation); + positions.Add(position); + prim.UUID = UUID.Random(); + prim.CreatorID = creatorID; + prim.OwnerID = owner_id; + prim.GroupID = UUID.Zero; + prim.LastOwnerID = creatorID; + prim.RezzerID = creatorID; + prim.CreationDate = Util.UnixTimeSinceEpoch(); + + if (grp == null) + prim.Name = assetName; else - f.TextureID = Primitive.TextureEntry.WHITE_TEXTURE; + prim.Name = assetName + "#" + i.ToString(); - textureEntry.FaceTextures[face] = f; - } + prim.EveryoneMask = 0; + prim.GroupMask = 0; - pbs.TextureEntry = textureEntry.GetBytes(); - - AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, (sbyte)AssetType.Mesh, ""); - meshAsset.Data = mesh_list[i].AsBinary(); - m_assetService.Store(meshAsset); - - pbs.SculptEntry = true; - pbs.SculptTexture = meshAsset.FullID; - pbs.SculptType = (byte)SculptType.Mesh; - pbs.SculptData = meshAsset.Data; - - Vector3 position = inner_instance_list["position"].AsVector3(); - Vector3 scale = inner_instance_list["scale"].AsVector3(); - Quaternion rotation = inner_instance_list["rotation"].AsQuaternion(); - -// no longer used - begin ------------------------ -// int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger(); -// int material = inner_instance_list["material"].AsInteger(); -// int mesh = inner_instance_list["mesh"].AsInteger(); - -// OSDMap permissions = (OSDMap)inner_instance_list["permissions"]; -// int base_mask = permissions["base_mask"].AsInteger(); -// int everyone_mask = permissions["everyone_mask"].AsInteger(); -// UUID creator_id = permissions["creator_id"].AsUUID(); -// UUID group_id = permissions["group_id"].AsUUID(); -// int group_mask = permissions["group_mask"].AsInteger(); -// bool is_owner_group = permissions["is_owner_group"].AsBoolean(); -// UUID last_owner_id = permissions["last_owner_id"].AsUUID(); -// int next_owner_mask = permissions["next_owner_mask"].AsInteger(); -// UUID owner_id = permissions["owner_id"].AsUUID(); -// int owner_mask = permissions["owner_mask"].AsInteger(); -// no longer used - end ------------------------ - - UUID owner_id = m_HostCapsObj.AgentID; - - SceneObjectPart prim - = new SceneObjectPart(owner_id, pbs, position, Quaternion.Identity, Vector3.Zero); - - prim.Scale = scale; - //prim.OffsetPosition = position; - rotations.Add(rotation); - positions.Add(position); - prim.UUID = UUID.Random(); - prim.CreatorID = owner_id; - prim.OwnerID = owner_id; - prim.GroupID = UUID.Zero; - prim.LastOwnerID = prim.OwnerID; - prim.CreationDate = Util.UnixTimeSinceEpoch(); - prim.Name = assetName; - prim.Description = ""; + if (restrictPerms) + { + prim.BaseMask = (uint)(PermissionMask.Move | PermissionMask.Modify); + prim.OwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify); + prim.NextOwnerMask = 0; + } + else + { + prim.BaseMask = (uint)PermissionMask.All | (uint)PermissionMask.Export; + prim.OwnerMask = (uint)PermissionMask.All | (uint)PermissionMask.Export; + prim.GroupMask = prim.BaseMask & (uint)groupMask; + prim.EveryoneMask = prim.BaseMask & (uint)everyoneMask; + prim.NextOwnerMask = prim.BaseMask & (uint)nextOwnerMask; + // If the viewer gives us bogus permissions, revert to the SL + // default of transfer only. + if ((prim.NextOwnerMask & (uint)PermissionMask.All) == 0) + prim.NextOwnerMask = (uint)PermissionMask.Transfer; + } + + if(istest) + prim.Description = "For testing only. Other uses are prohibited"; + else + prim.Description = ""; + + prim.Material = material; + prim.PhysicsShapeType = physicsShapeType; // prim.BaseMask = (uint)base_mask; // prim.EveryoneMask = (uint)everyone_mask; @@ -718,52 +1065,65 @@ namespace OpenSim.Region.ClientStack.Linden // prim.NextOwnerMask = (uint)next_owner_mask; // prim.OwnerMask = (uint)owner_mask; - if (grp == null) - grp = new SceneObjectGroup(prim); - else - grp.AddPart(prim); - } + if (grp == null) + { + grp = new SceneObjectGroup(prim); + grp.LastOwnerID = creatorID; + grp.RezzerID = creatorID; + } + else + grp.AddPart(prim); + } - Vector3 rootPos = positions[0]; + Vector3 rootPos = positions[0]; - if (grp.Parts.Length > 1) - { - // Fix first link number - grp.RootPart.LinkNum++; + if (grp.Parts.Length > 1) + { + // Fix first link number + grp.RootPart.LinkNum++; - Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); - Quaternion tmprot; - Vector3 offset; + Quaternion rootRotConj = Quaternion.Conjugate(rotations[0]); + Quaternion tmprot; + Vector3 offset; - // fix children rotations and positions - for (int i = 1; i < rotations.Count; i++) - { - tmprot = rotations[i]; - tmprot = rootRotConj * tmprot; + // fix children rotations and positions + for (int i = 1; i < rotations.Count; i++) + { + tmprot = rotations[i]; + tmprot = rootRotConj * tmprot; - grp.Parts[i].RotationOffset = tmprot; + grp.Parts[i].RotationOffset = tmprot; - offset = positions[i] - rootPos; + offset = positions[i] - rootPos; + + offset *= rootRotConj; + grp.Parts[i].OffsetPosition = offset; + } - offset *= rootRotConj; - grp.Parts[i].OffsetPosition = offset; + grp.AbsolutePosition = rootPos; + grp.UpdateGroupRotationR(rotations[0]); + } + else + { + grp.AbsolutePosition = rootPos; + grp.UpdateGroupRotationR(rotations[0]); } - grp.AbsolutePosition = rootPos; - grp.UpdateGroupRotationR(rotations[0]); + data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp)); } - else + + else // not a mesh model { - grp.AbsolutePosition = rootPos; - grp.UpdateGroupRotationR(rotations[0]); + m_log.ErrorFormat("[CAPS Asset Upload] got unsuported assetType for object upload"); + return; } - - data = ASCIIEncoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(grp)); } AssetBase asset; - asset = new AssetBase(assetID, assetName, assType, m_HostCapsObj.AgentID.ToString()); + asset = new AssetBase(assetID, assetName, assType, creatorIDstr); asset.Data = data; + if (istest) + asset.Local = true; if (AddNewAsset != null) AddNewAsset(asset); else if (m_assetService != null) @@ -771,11 +1131,17 @@ namespace OpenSim.Region.ClientStack.Linden InventoryItemBase item = new InventoryItemBase(); item.Owner = m_HostCapsObj.AgentID; - item.CreatorId = m_HostCapsObj.AgentID.ToString(); + item.CreatorId = creatorIDstr; item.CreatorData = String.Empty; item.ID = inventoryItem; item.AssetID = asset.FullID; - item.Description = assetDescription; + if (istest) + { + item.Description = "For testing only. Other uses are prohibited"; + item.Flags = (uint) (InventoryItemFlags.SharedSingleReference); + } + else + item.Description = assetDescription; item.Name = assetName; item.AssetType = assType; item.InvType = inType; @@ -783,18 +1149,69 @@ namespace OpenSim.Region.ClientStack.Linden // If we set PermissionMask.All then when we rez the item the next permissions will replace the current // (owner) permissions. This becomes a problem if next permissions are changed. - item.CurrentPermissions - = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Export); - item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; - item.EveryOnePermissions = 0; - item.NextPermissions = (uint)PermissionMask.All; + if (inType == (sbyte)CustomInventoryType.AnimationSet) + { + AnimationSet.setCreateItemPermitions(item); + } + + else if (restrictPerms) + { + item.BasePermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); + item.CurrentPermissions = (uint)(PermissionMask.Move | PermissionMask.Modify); + item.GroupPermissions = 0; + item.EveryOnePermissions = 0; + item.NextPermissions = 0; + } + else + { + item.BasePermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; + item.CurrentPermissions = (uint)PermissionMask.All | (uint)PermissionMask.Export; + item.GroupPermissions = item.BasePermissions & (uint)groupMask; + item.EveryOnePermissions = item.BasePermissions & (uint)everyoneMask; + item.NextPermissions = item.BasePermissions & (uint)nextOwnerMask; + if ((item.NextPermissions & (uint)PermissionMask.All) == 0) + item.NextPermissions = (uint)PermissionMask.Transfer; + } + item.CreationDate = Util.UnixTimeSinceEpoch(); + everyoneMask = (int)item.EveryOnePermissions; + groupMask = (int)item.GroupPermissions; + nextOwnerMask = (int)item.NextPermissions; + + m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); + if (AddNewInventoryItem != null) { - AddNewInventoryItem(m_HostCapsObj.AgentID, item); + if (istest) + { + m_Scene.AddInventoryItem(client, item); +/* + AddNewInventoryItem(m_HostCapsObj.AgentID, item, 0); + if (client != null) + client.SendAgentAlertMessage("Upload will have no cost, for personal test purposes only. Other uses are forbiden. Items may not work on a another region" , true); + */ + } + else + { + AddNewInventoryItem(m_HostCapsObj.AgentID, item, (uint)cost); +// if (client != null) +// { +// // let users see anything.. i don't so far +// string str; +// if (cost > 0) +// // dont remember where is money unit name to put here +// str = "Upload complete. charged " + cost.ToString() + "$"; +// else +// str = "Upload complete"; +// client.SendAgentAlertMessage(str, true); +// } + } } + + lock (m_ModelCost) + m_FileAgentInventoryState = FileAgentInventoryState.idle; } /// @@ -857,24 +1274,22 @@ namespace OpenSim.Region.ClientStack.Linden LLSDItemUpdate llsdRequest = new LLSDItemUpdate(); LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); - string capsBase = "/CAPS/" + m_HostCapsObj.CapsObjectPath; - string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); + string uploaderPath = GetNewCapPath(); ItemUpdater uploader = - new ItemUpdater(llsdRequest.item_id, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); + new ItemUpdater(llsdRequest.item_id, uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); uploader.OnUpLoad += ItemUpdated; m_HostCapsObj.HttpListener.AddStreamHandler( new BinaryStreamHandler( - "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); + "POST", uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); string protocol = "http://"; if (m_HostCapsObj.SSLCaps) protocol = "https://"; - string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + - uploaderPath; + string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + uploaderPath; LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); uploadResponse.uploader = uploaderURL; @@ -930,29 +1345,22 @@ namespace OpenSim.Region.ClientStack.Linden IClientAPI client = null; m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); - item = m_Scene.InventoryService.GetItem(new InventoryItemBase(itemID)); + item = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID); if (item != null) { string message; copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); - if (client != null) + if (copyItem != null && client != null) { - if (copyItem != null) - { - m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); - client.SendBulkUpdateInventory(copyItem); - } - else - { - client.SendAgentAlertMessage(message, false); - } + m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); + client.SendBulkUpdateInventory(copyItem); } } else { m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); if (client != null) - client.SendAgentAlertMessage("Failed to retrieve item", false); + client.SendAlertMessage("Failed to retrieve item"); } } catch (Exception e) @@ -995,26 +1403,483 @@ namespace OpenSim.Region.ClientStack.Linden return response; } - public string UpdateAgentInformation(string request, string path, + public string GetObjectCost(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); - OSDMap accessPrefs = (OSDMap)req["access_prefs"]; - string desiredMaturity = accessPrefs["max"]; + OSDMap resp = new OSDMap(); + + OSDArray object_ids = (OSDArray)req["object_ids"]; + + for (int i = 0; i < object_ids.Count; i++) + { + UUID uuid = object_ids[i].AsUUID(); + + SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid); + SceneObjectGroup grp = null; + if (part != null) + grp = part.ParentGroup; + if (grp != null) + { + float linksetCost; + float linksetPhysCost; + float partCost; + float partPhysCost; + + grp.GetResourcesCosts(part,out linksetCost,out linksetPhysCost,out partCost,out partPhysCost); + + OSDMap object_data = new OSDMap(); + object_data["linked_set_resource_cost"] = linksetCost; + object_data["resource_cost"] = partCost; + object_data["physics_cost"] = partPhysCost; + object_data["linked_set_physics_cost"] = linksetPhysCost; + object_data["resource_limiting_type"] = "legacy"; + resp[uuid.ToString()] = object_data; + } + } + if(resp.Count == 0) + { + OSDMap object_data = new OSDMap(); + object_data["linked_set_resource_cost"] = 0; + object_data["resource_cost"] = 0; + object_data["physics_cost"] = 0; + object_data["linked_set_physics_cost"] = 0; + resp[UUID.Zero.ToString()] = object_data; + } + string response = OSDParser.SerializeLLSDXmlString(resp); + return response; + } + + public string ResourceCostSelected(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + OSDMap resp = new OSDMap(); + + + float phys=0; + float stream=0; + float simul=0; + + if (req.ContainsKey("selected_roots")) + { + OSDArray object_ids = (OSDArray)req["selected_roots"]; + + // should go by SOG suming costs for all parts + // ll v3 works ok with several objects select we get the list and adds ok + // FS calls per object so results are wrong guess fs bug + for (int i = 0; i < object_ids.Count; i++) + { + UUID uuid = object_ids[i].AsUUID(); + float Physc; + float simulc; + float streamc; + + SceneObjectGroup grp = m_Scene.GetGroupByPrim(uuid); + if (grp != null) + { + grp.GetSelectedCosts(out Physc, out streamc, out simulc); + phys += Physc; + stream += streamc; + simul += simulc; + } + } + } + else if (req.ContainsKey("selected_prims")) + { + OSDArray object_ids = (OSDArray)req["selected_prims"]; + + // don't see in use in any of the 2 viewers + // guess it should be for edit linked but... nothing + // should go to SOP per part + for (int i = 0; i < object_ids.Count; i++) + { + UUID uuid = object_ids[i].AsUUID(); + + SceneObjectPart part = m_Scene.GetSceneObjectPart(uuid); + if (part != null) + { + phys += part.PhysicsCost; + stream += part.StreamingCost; + simul += part.SimulationCost; + } + } + } + + OSDMap object_data = new OSDMap(); + + object_data["physics"] = phys; + object_data["streaming"] = stream; + object_data["simulation"] = simul; + + resp["selected"] = object_data; +// resp["transaction_id"] = "undef"; + string response = OSDParser.SerializeLLSDXmlString(resp); + return response; + } + public string UpdateAgentInformation(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { +// OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); OSDMap resp = new OSDMap(); - OSDMap respAccessPrefs = new OSDMap(); - respAccessPrefs["max"] = desiredMaturity; // echoing the maturity back means success - resp["access_prefs"] = respAccessPrefs; + + OSDMap accessPrefs = new OSDMap(); + accessPrefs["max"] = "A"; + + resp["access_prefs"] = accessPrefs; string response = OSDParser.SerializeLLSDXmlString(resp); - return response; + return response; + } + + public bool OSDMapTOVector3(OSDMap map, out Vector3 v) + { + v = Vector3.Zero; + if(!map.ContainsKey("X")) + return false; + if(!map.ContainsKey("Y")) + return false; + if(!map.ContainsKey("Z")) + return false; + v.X = (float)map["X"].AsReal(); + v.Y = (float)map["Y"].AsReal(); + v.Z = (float)map["Z"].AsReal(); + return true; + } + + public string HomeLocation(string request, string path, string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + OSDMap resp = new OSDMap(); + + resp["success"] = "false"; + + + bool fail = true; + string message = "Set Home request failed"; + int locationID = 1; + Vector3 pos = Vector3.Zero; + Vector3 lookAt = Vector3.Zero; + + IClientAPI client = null; + ScenePresence sp; + + while(true) + { + if(m_Scene.GridUserService == null) + break; + + if(m_Scene.UserManagementModule == null) + break; + + m_Scene.TryGetScenePresence(m_AgentID, out sp); + if(sp == null || sp.IsChildAgent || sp.IsDeleted) + break; + + if(sp.IsInTransit && !sp.IsInLocalTransit) + break; + + client = sp.ControllingClient; + + if(!m_Scene.UserManagementModule.IsLocalGridUser(m_AgentID)) + break; + + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + if(!req.ContainsKey("HomeLocation")) + break; + + OSDMap HLocation = (OSDMap)req["HomeLocation"]; + if(!HLocation.ContainsKey("LocationPos")) + break; + if(!HLocation.ContainsKey("LocationLookAt")) + break; + + locationID = HLocation["LocationId"].AsInteger(); + + if(!OSDMapTOVector3((OSDMap)HLocation["LocationPos"], out pos)) + break; + + if(!OSDMapTOVector3((OSDMap)HLocation["LocationLookAt"], out lookAt)) + break; + + ILandObject land = m_Scene.LandChannel.GetLandObject(pos); + if(land == null) + break; + + ulong gpowers = client.GetGroupPowers(land.LandData.GroupID); + SceneObjectGroup telehub = null; + if (m_Scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) + // Does the telehub exist in the scene? + telehub = m_Scene.GetSceneObjectGroup(m_Scene.RegionInfo.RegionSettings.TelehubObject); + + if (!m_Scene.Permissions.IsAdministrator(m_AgentID) && // (a) gods and land managers can set home + !m_Scene.Permissions.IsGod(m_AgentID) && + m_AgentID != land.LandData.OwnerID && // (b) land owners can set home + // (c) members of the land-associated group in roles that can set home + ((gpowers & (ulong)GroupPowers.AllowSetHome) != (ulong)GroupPowers.AllowSetHome) && + // (d) parcels with telehubs can be the home of anyone + (telehub == null || !land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))) + { + message = "You are not allowed to set your home location in this parcel."; + break; + } + + string userId; + UUID test; + if (!m_Scene.UserManagementModule.GetUserUUI(m_AgentID, out userId)) + { + message = "Set Home request failed. (User Lookup)"; + break; + } + + if (!UUID.TryParse(userId, out test)) + { + message = "Set Home request failed. (HG visitor)"; + break; + } + + if (m_Scene.GridUserService.SetHome(userId, land.RegionUUID, pos, lookAt)) + fail = false; + + break; + } + + string response; + + if(fail) + { + if(client != null) + client.SendAlertMessage(message); + response = OSDParser.SerializeLLSDXmlString(resp); + return response; + } + + // so its http but still needs a udp reply to inform user? crap :p + if(client != null) + client.SendAlertMessage("Home position set.","HomePositionSet"); + + resp["success"] = "true"; + OSDMap homeloc = new OSDMap(); + OSDMap homelocpos = new OSDMap(); + // for some odd reason viewers send pos as reals but read as integer + homelocpos["X"] = new OSDReal(pos.X); + homelocpos["Y"] = new OSDReal(pos.Y); + homelocpos["Z"] = new OSDReal(pos.Z); + homeloc["LocationPos"] = homelocpos; + + resp["HomeLocation"] = homeloc; + + response = OSDParser.SerializeLLSDXmlString(resp); + return response; + } + + private static int CompareRolesByMembersDesc(GroupRolesData x, GroupRolesData y) + { + return -(x.Members.CompareTo(y.Members)); + } + + public string GroupMemberData(string request, string path, string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + OSDMap resp = new OSDMap(); + + string response; + + bool fail = true; + IClientAPI client = null; + ScenePresence sp; + IGroupsModule m_GroupsModule; + UUID groupID = UUID.Zero; + + while(true) + { + m_GroupsModule = m_Scene.RequestModuleInterface(); + if(m_GroupsModule == null) + break; + + m_Scene.TryGetScenePresence(m_AgentID, out sp); + if(sp == null || sp.IsChildAgent || sp.IsDeleted) + break; + + if(sp.IsInTransit && !sp.IsInLocalTransit) + break; + + client = sp.ControllingClient; + + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + if(!req.ContainsKey("group_id")) + break; + + groupID = req["group_id"].AsUUID(); + if(groupID == UUID.Zero) + break; + + List roles = m_GroupsModule.GroupRoleDataRequest(client, groupID); + if(roles == null || roles.Count == 0) + break; + + List members = m_GroupsModule.GroupMembersRequest(client, groupID); + if(members == null || members.Count == 0) + break; + + int memberCount = members.Count; + + Dictionary titles = new Dictionary(); + int i = 0; + + ulong defaultPowers = 0; + + + // build titles array and index + roles.Sort(CompareRolesByMembersDesc); + + OSDArray osdtitles = new OSDArray(); + foreach(GroupRolesData grd in roles) + { + if(grd.Title == null) + continue; + string title = grd.Title; + if(i==0) + defaultPowers = grd.Powers; + + if(!titles.ContainsKey(title)) + { + titles[title] = i++; + osdtitles.Add(new OSDString(title)); + } + } + + if(titles.Count == 0) + break; + + OSDMap osdmembers = new OSDMap(); + foreach(GroupMembersData gmd in members) + { + OSDMap m = new OSDMap(); + if(gmd.OnlineStatus != null && gmd.OnlineStatus != "") + m["last_login"] = new OSDString(gmd.OnlineStatus); + if(gmd.AgentPowers != defaultPowers) + m["powers"] = new OSDString((gmd.AgentPowers).ToString("X")); + if(gmd.Title != null && titles.ContainsKey(gmd.Title) && titles[gmd.Title] != 0) + m["title"] = new OSDInteger(titles[gmd.Title]); + if(gmd.IsOwner) + m["owner"] = new OSDString("true"); + if(gmd.Contribution != 0) + m["donated_square_meters"] = new OSDInteger(gmd.Contribution); + + osdmembers[(gmd.AgentID).ToString()] = m; + } + + OSDMap osddefaults = new OSDMap(); + osddefaults["default_powers"] = new OSDString(defaultPowers.ToString("X")); + + resp["group_id"] = new OSDUUID(groupID); + resp["agent_id"] = new OSDUUID(m_AgentID); + resp["member_count"] = new OSDInteger(memberCount); + resp["defaults"] = osddefaults; + resp["titles"] = osdtitles; + resp["members"] = osdmembers; + + fail = false; + break; + } + + if(fail) + { + resp["group_id"] = new OSDUUID(groupID); + resp["agent_id"] = new OSDUUID(m_AgentID); + resp["member_count"] = new OSDInteger(0); + resp["defaults"] = new OSDMap(); + resp["titles"] = new OSDArray(); + resp["members"] = new OSDMap(); + } + + response = OSDParser.SerializeLLSDXmlString(resp); + return response; + } + + public string GetDisplayNames(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.Gone; + httpResponse.ContentType = "text/plain"; + + ScenePresence sp = m_Scene.GetScenePresence(m_AgentID); + if(sp == null || sp.IsDeleted) + return ""; + + if(sp.IsInTransit && !sp.IsInLocalTransit) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable; + httpResponse.AddHeader("Retry-After","30"); + return ""; + } + + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string[] ids = query.GetValues("ids"); + + Dictionary names = m_UserManager.GetUsersNames(ids); + + OSDMap osdReply = new OSDMap(); + OSDArray agents = new OSDArray(); + + osdReply["agents"] = agents; + foreach (KeyValuePair kvp in names) + { + if (string.IsNullOrEmpty(kvp.Value)) + continue; + if(kvp.Key == UUID.Zero) + continue; + + string[] parts = kvp.Value.Split(new char[] {' '}); + OSDMap osdname = new OSDMap(); + + // dont tell about unknown users, we can't send them back on Bad either + if(parts[0] == "Unknown") + continue; +/* + if(parts[0] == "Unknown") + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); + } + else +*/ + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); + } + osdname["display_name"] = OSD.FromString(kvp.Value); + osdname["legacy_first_name"] = parts[0]; + osdname["legacy_last_name"] = parts[1]; + osdname["username"] = OSD.FromString(kvp.Value); + osdname["id"] = OSD.FromUUID(kvp.Key); + osdname["is_display_name_default"] = OSD.FromBoolean(true); + + agents.Add(osdname); + } + + // Full content request + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; + //httpResponse.ContentLength = ??; + httpResponse.ContentType = "application/llsd+xml"; + + string reply = OSDParser.SerializeLLSDXmlString(osdReply); + return reply; } } public class AssetUploader { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public event UpLoadedAsset OnUpLoad; private UpLoadedAsset handlerUpLoad = null; @@ -1029,10 +1894,26 @@ namespace OpenSim.Region.ClientStack.Linden private string m_invType = String.Empty; private string m_assetType = String.Empty; + private int m_cost; + private string m_error = String.Empty; + + private Timer m_timeoutTimer = new Timer(); + private UUID m_texturesFolder; + private int m_nreqtextures; + private int m_nreqmeshs; + private int m_nreqinstances; + private bool m_IsAtestUpload; + + private int m_nextOwnerMask; + private int m_groupMask; + private int m_everyoneMask; + public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, UUID parentFolderID, string invType, string assetType, string path, - IHttpServer httpServer, bool dumpAssetsToFile) + IHttpServer httpServer, bool dumpAssetsToFile, + int totalCost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances, + bool IsAtestUpload, int nextOwnerMask, int groupMask, int everyoneMask) { m_assetName = assetName; m_assetDes = description; @@ -1044,6 +1925,22 @@ namespace OpenSim.Region.ClientStack.Linden m_assetType = assetType; m_invType = invType; m_dumpAssetsToFile = dumpAssetsToFile; + m_cost = totalCost; + + m_texturesFolder = texturesFolder; + m_nreqtextures = nreqtextures; + m_nreqmeshs = nreqmeshs; + m_nreqinstances = nreqinstances; + m_IsAtestUpload = IsAtestUpload; + + m_timeoutTimer.Elapsed += TimedOut; + m_timeoutTimer.Interval = 120000; + m_timeoutTimer.AutoReset = false; + m_timeoutTimer.Start(); + + m_nextOwnerMask = nextOwnerMask; + m_groupMask = groupMask; + m_everyoneMask = everyoneMask; } /// @@ -1058,12 +1955,14 @@ namespace OpenSim.Region.ClientStack.Linden UUID inv = inventoryItemID; string res = String.Empty; LLSDAssetUploadComplete uploadComplete = new LLSDAssetUploadComplete(); +/* uploadComplete.new_asset = newAssetID.ToString(); uploadComplete.new_inventory_item = inv; uploadComplete.state = "complete"; res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); - +*/ + m_timeoutTimer.Stop(); httpListener.RemoveStreamHandler("POST", uploaderPath); // TODO: probably make this a better set of extensions here @@ -1080,12 +1979,55 @@ namespace OpenSim.Region.ClientStack.Linden handlerUpLoad = OnUpLoad; if (handlerUpLoad != null) { - handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType); + handlerUpLoad(m_assetName, m_assetDes, newAssetID, inv, parentFolder, data, m_invType, m_assetType, + m_cost, m_texturesFolder, m_nreqtextures, m_nreqmeshs, m_nreqinstances, m_IsAtestUpload, + ref m_error, ref m_nextOwnerMask, ref m_groupMask, ref m_everyoneMask); } + uploadComplete.new_next_owner_mask = m_nextOwnerMask; + uploadComplete.new_group_mask = m_groupMask; + uploadComplete.new_everyone_mask = m_everyoneMask; + + if (m_IsAtestUpload) + { + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = "Upload SUCESSEFULL for testing purposes only. Other uses are prohibited. Item will not work after 48 hours or on other regions"; + resperror.identifier = inv; + + uploadComplete.error = resperror; + uploadComplete.state = "Upload4Testing"; + } + else + { + if (m_error == String.Empty) + { + uploadComplete.new_asset = newAssetID.ToString(); + uploadComplete.new_inventory_item = inv; + // if (m_texturesFolder != UUID.Zero) + // uploadComplete.new_texture_folder_id = m_texturesFolder; + uploadComplete.state = "complete"; + } + else + { + LLSDAssetUploadError resperror = new LLSDAssetUploadError(); + resperror.message = m_error; + resperror.identifier = inv; + + uploadComplete.error = resperror; + uploadComplete.state = "failed"; + } + } + + res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 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) //{ diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs index c241075..683c3d5 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCapsModule.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden { } - public void Close() { } + public void Close() { } public void AddRegion(Scene scene) { @@ -80,11 +80,11 @@ namespace OpenSim.Region.ClientStack.Linden } public void PostInitialise() { } - #endregion + #endregion private void OnRegisterCaps(UUID agentID, Caps caps) { - new BunchOfCaps(m_Scene, caps); + new BunchOfCaps(m_Scene, agentID, caps); } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs new file mode 100644 index 0000000..eb1ab45 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/MeshCost.cs @@ -0,0 +1,746 @@ +/* + * 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.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Capabilities; + +using ComponentAce.Compression.Libs.zlib; + +using OSDArray = OpenMetaverse.StructuredData.OSDArray; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +using Nini.Config; + +namespace OpenSim.Region.ClientStack.Linden +{ + public struct ModelPrimLimits + { + + } + + public class ModelCost + { + + // upload fee defaults + // fees are normalized to 1.0 + // this parameters scale them to basic cost ( so 1.0 translates to 10 ) + + public float ModelMeshCostFactor = 0.0f; // scale total cost relative to basic (excluding textures) + public float ModelTextureCostFactor = 1.0f; // scale textures fee to basic. + public float ModelMinCostFactor = 0.0f; // 0.5f; // minimum total model free excluding textures + + // itens costs in normalized values + // ie will be multiplied by basicCost and factors above + public float primCreationCost = 0.002f; // extra cost for each prim creation overhead + // weigthed size to normalized cost + public float bytecost = 1e-5f; + + // mesh upload fees based on compressed data sizes + // several data sections are counted more that once + // to promote user optimization + // following parameters control how many extra times they are added + // to global size. + // LOD meshs + const float medSizeWth = 1f; // 2x + const float lowSizeWth = 1.5f; // 2.5x + const float lowestSizeWth = 2f; // 3x + // favor potencially physical optimized meshs versus automatic decomposition + const float physMeshSizeWth = 6f; // counts 7x + const float physHullSizeWth = 8f; // counts 9x + + // stream cost area factors + // more or less like SL + const float highLodFactor = 17.36f; + const float midLodFactor = 277.78f; + const float lowLodFactor = 1111.11f; + + // physics cost is below, identical to SL, assuming shape type convex + // server cost is below identical to SL assuming non scripted non physical object + + // internal + const int bytesPerCoord = 6; // 3 coords, 2 bytes per each + + // control prims dimensions + public float PrimScaleMin = 0.001f; + public float NonPhysicalPrimScaleMax = 256f; + public float PhysicalPrimScaleMax = 10f; + public int ObjectLinkedPartsMax = 512; + + + public ModelCost(Scene scene) + { + PrimScaleMin = scene.m_minNonphys; + NonPhysicalPrimScaleMax = scene.m_maxNonphys; + PhysicalPrimScaleMax = scene.m_maxPhys; + ObjectLinkedPartsMax = scene.m_linksetCapacity; + } + + public void Econfig(IConfig EconomyConfig) + { + ModelMeshCostFactor = EconomyConfig.GetFloat("MeshModelUploadCostFactor", ModelMeshCostFactor); + ModelTextureCostFactor = EconomyConfig.GetFloat("MeshModelUploadTextureCostFactor", ModelTextureCostFactor); + ModelMinCostFactor = EconomyConfig.GetFloat("MeshModelMinCostFactor", ModelMinCostFactor); + // next 2 are normalized so final cost is afected by modelUploadFactor above and normal cost + primCreationCost = EconomyConfig.GetFloat("ModelPrimCreationCost", primCreationCost); + bytecost = EconomyConfig.GetFloat("ModelMeshByteCost", bytecost); + } + + // storage for a single mesh asset cost parameters + private class ameshCostParam + { + // LOD sizes for size dependent streaming cost + public int highLODSize; + public int medLODSize; + public int lowLODSize; + public int lowestLODSize; + // normalized fee based on compressed data sizes + public float costFee; + // physics cost + public float physicsCost; + } + + // calculates a mesh model costs + // returns false on error, with a reason on parameter error + // resources input LLSD request + // basicCost input region assets upload cost + // totalcost returns model total upload fee + // meshcostdata returns detailed costs for viewer + // avatarSkeleton if mesh includes a avatar skeleton + // useAvatarCollider if we should use physics mesh for avatar + public bool MeshModelCost(LLSDAssetResource resources, int basicCost, out int totalcost, + LLSDAssetUploadResponseData meshcostdata, out string error, ref string warning) + { + totalcost = 0; + error = string.Empty; + + bool avatarSkeleton = false; + + if (resources == null || + resources.instance_list == null || + resources.instance_list.Array.Count == 0) + { + error = "missing model information."; + return false; + } + + int numberInstances = resources.instance_list.Array.Count; + + if (ObjectLinkedPartsMax != 0 && numberInstances > ObjectLinkedPartsMax) + { + error = "Model would have more than " + ObjectLinkedPartsMax.ToString() + " linked prims"; + return false; + } + + meshcostdata.model_streaming_cost = 0.0; + meshcostdata.simulation_cost = 0.0; + meshcostdata.physics_cost = 0.0; + meshcostdata.resource_cost = 0.0; + + meshcostdata.upload_price_breakdown.mesh_instance = 0; + meshcostdata.upload_price_breakdown.mesh_physics = 0; + meshcostdata.upload_price_breakdown.mesh_streaming = 0; + meshcostdata.upload_price_breakdown.model = 0; + + int itmp; + + // textures cost + if (resources.texture_list != null && resources.texture_list.Array.Count > 0) + { + float textures_cost = (float)(resources.texture_list.Array.Count * basicCost); + textures_cost *= ModelTextureCostFactor; + + itmp = (int)(textures_cost + 0.5f); // round + meshcostdata.upload_price_breakdown.texture = itmp; + totalcost += itmp; + } + + // meshs assets cost + float meshsfee = 0; + int numberMeshs = 0; + bool haveMeshs = false; + + bool curskeleton; + bool curAvatarPhys; + + List meshsCosts = new List(); + + if (resources.mesh_list != null && resources.mesh_list.Array.Count > 0) + { + numberMeshs = resources.mesh_list.Array.Count; + + for (int i = 0; i < numberMeshs; i++) + { + ameshCostParam curCost = new ameshCostParam(); + byte[] data = (byte[])resources.mesh_list.Array[i]; + + if (!MeshCost(data, curCost,out curskeleton, out curAvatarPhys, out error)) + { + return false; + } + + if (curskeleton) + { + if (avatarSkeleton) + { + error = "model can only contain a avatar skeleton"; + return false; + } + avatarSkeleton = true; + } + meshsCosts.Add(curCost); + meshsfee += curCost.costFee; + } + haveMeshs = true; + } + + // instances (prims) cost + + + int mesh; + int skipedSmall = 0; + for (int i = 0; i < numberInstances; i++) + { + Hashtable inst = (Hashtable)resources.instance_list.Array[i]; + + ArrayList ascale = (ArrayList)inst["scale"]; + Vector3 scale; + double tmp; + tmp = (double)ascale[0]; + scale.X = (float)tmp; + tmp = (double)ascale[1]; + scale.Y = (float)tmp; + tmp = (double)ascale[2]; + scale.Z = (float)tmp; + + if (scale.X < PrimScaleMin || scale.Y < PrimScaleMin || scale.Z < PrimScaleMin) + { + skipedSmall++; + continue; + } + + if (scale.X > NonPhysicalPrimScaleMax || scale.Y > NonPhysicalPrimScaleMax || scale.Z > NonPhysicalPrimScaleMax) + { + error = "Model contains parts with sides larger than " + NonPhysicalPrimScaleMax.ToString() + "m. Please ajust scale"; + return false; + } + + if (haveMeshs && inst.ContainsKey("mesh")) + { + mesh = (int)inst["mesh"]; + + if (mesh >= numberMeshs) + { + error = "Incoerent model information."; + return false; + } + + // streamming cost + + float sqdiam = scale.LengthSquared(); + + ameshCostParam curCost = meshsCosts[mesh]; + float mesh_streaming = streamingCost(curCost, sqdiam); + + meshcostdata.model_streaming_cost += mesh_streaming; + meshcostdata.physics_cost += curCost.physicsCost; + } + else // instance as no mesh ?? + { + // to do later if needed + meshcostdata.model_streaming_cost += 0.5f; + meshcostdata.physics_cost += 1.0f; + } + + // assume unscripted and static prim server cost + meshcostdata.simulation_cost += 0.5f; + // charge for prims creation + meshsfee += primCreationCost; + } + + if (skipedSmall > 0) + { + if (skipedSmall > numberInstances / 2) + { + error = "Model contains too many prims smaller than " + PrimScaleMin.ToString() + + "m minimum allowed size. Please check scalling"; + return false; + } + else + warning += skipedSmall.ToString() + " of the requested " +numberInstances.ToString() + + " model prims will not upload because they are smaller than " + PrimScaleMin.ToString() + + "m minimum allowed size. Please check scalling "; + } + + if (meshcostdata.physics_cost <= meshcostdata.model_streaming_cost) + meshcostdata.resource_cost = meshcostdata.model_streaming_cost; + else + meshcostdata.resource_cost = meshcostdata.physics_cost; + + if (meshcostdata.resource_cost < meshcostdata.simulation_cost) + meshcostdata.resource_cost = meshcostdata.simulation_cost; + + // scale cost + // at this point a cost of 1.0 whould mean basic cost + meshsfee *= ModelMeshCostFactor; + + if (meshsfee < ModelMinCostFactor) + meshsfee = ModelMinCostFactor; + + // actually scale it to basic cost + meshsfee *= (float)basicCost; + + meshsfee += 0.5f; // rounding + + totalcost += (int)meshsfee; + + // breakdown prices + // don't seem to be in use so removed code for now + + return true; + } + + // single mesh asset cost + private bool MeshCost(byte[] data, ameshCostParam cost,out bool skeleton, out bool avatarPhys, out string error) + { + cost.highLODSize = 0; + cost.medLODSize = 0; + cost.lowLODSize = 0; + cost.lowestLODSize = 0; + cost.physicsCost = 0.0f; + cost.costFee = 0.0f; + + error = string.Empty; + + skeleton = false; + avatarPhys = false; + + if (data == null || data.Length == 0) + { + error = "Missing model information."; + return false; + } + + OSD meshOsd = null; + int start = 0; + + error = "Invalid model data"; + + using (MemoryStream ms = new MemoryStream(data)) + { + try + { + OSD osd = OSDParser.DeserializeLLSDBinary(ms); + if (osd is OSDMap) + meshOsd = (OSDMap)osd; + else + return false; + } + catch + { + return false; + } + start = (int)ms.Position; + } + + OSDMap map = (OSDMap)meshOsd; + OSDMap tmpmap; + + int highlod_size = 0; + int medlod_size = 0; + int lowlod_size = 0; + int lowestlod_size = 0; + int skin_size = 0; + + int hulls_size = 0; + int phys_nhulls; + int phys_hullsvertices = 0; + + int physmesh_size = 0; + int phys_ntriangles = 0; + + int submesh_offset = -1; + + if (map.ContainsKey("skeleton")) + { + tmpmap = (OSDMap)map["skeleton"]; + if (tmpmap.ContainsKey("offset") && tmpmap.ContainsKey("size")) + { + int sksize = tmpmap["size"].AsInteger(); + if(sksize > 0) + skeleton = true; + } + } + + if (map.ContainsKey("physics_convex")) + { + tmpmap = (OSDMap)map["physics_convex"]; + if (tmpmap.ContainsKey("offset")) + submesh_offset = tmpmap["offset"].AsInteger() + start; + if (tmpmap.ContainsKey("size")) + hulls_size = tmpmap["size"].AsInteger(); + } + + if (submesh_offset < 0 || hulls_size == 0) + { + error = "Missing physics_convex block"; + return false; + } + + if (!hulls(data, submesh_offset, hulls_size, out phys_hullsvertices, out phys_nhulls)) + { + error = "Bad physics_convex block"; + return false; + } + + submesh_offset = -1; + + // only look for LOD meshs sizes + + if (map.ContainsKey("high_lod")) + { + tmpmap = (OSDMap)map["high_lod"]; + // see at least if there is a offset for this one + if (tmpmap.ContainsKey("offset")) + submesh_offset = tmpmap["offset"].AsInteger() + start; + if (tmpmap.ContainsKey("size")) + highlod_size = tmpmap["size"].AsInteger(); + } + + if (submesh_offset < 0 || highlod_size <= 0) + { + error = "Missing high_lod block"; + return false; + } + + bool haveprev = true; + + if (map.ContainsKey("medium_lod")) + { + tmpmap = (OSDMap)map["medium_lod"]; + if (tmpmap.ContainsKey("size")) + medlod_size = tmpmap["size"].AsInteger(); + else + haveprev = false; + } + + if (haveprev && map.ContainsKey("low_lod")) + { + tmpmap = (OSDMap)map["low_lod"]; + if (tmpmap.ContainsKey("size")) + lowlod_size = tmpmap["size"].AsInteger(); + else + haveprev = false; + } + + if (haveprev && map.ContainsKey("lowest_lod")) + { + tmpmap = (OSDMap)map["lowest_lod"]; + if (tmpmap.ContainsKey("size")) + lowestlod_size = tmpmap["size"].AsInteger(); + } + + if (map.ContainsKey("skin")) + { + tmpmap = (OSDMap)map["skin"]; + if (tmpmap.ContainsKey("size")) + skin_size = tmpmap["size"].AsInteger(); + } + + cost.highLODSize = highlod_size; + cost.medLODSize = medlod_size; + cost.lowLODSize = lowlod_size; + cost.lowestLODSize = lowestlod_size; + + submesh_offset = -1; + + tmpmap = null; + if(map.ContainsKey("physics_mesh")) + tmpmap = (OSDMap)map["physics_mesh"]; + else if (map.ContainsKey("physics_shape")) // old naming + tmpmap = (OSDMap)map["physics_shape"]; + + if(tmpmap != null) + { + if (tmpmap.ContainsKey("offset")) + submesh_offset = tmpmap["offset"].AsInteger() + start; + if (tmpmap.ContainsKey("size")) + physmesh_size = tmpmap["size"].AsInteger(); + + if (submesh_offset >= 0 || physmesh_size > 0) + { + + if (!submesh(data, submesh_offset, physmesh_size, out phys_ntriangles)) + { + error = "Model data parsing error"; + return false; + } + } + } + + // upload is done in convex shape type so only one hull + phys_hullsvertices++; + cost.physicsCost = 0.04f * phys_hullsvertices; + + float sfee; + + sfee = data.Length; // start with total compressed data size + + // penalize lod meshs that should be more builder optimized + sfee += medSizeWth * medlod_size; + sfee += lowSizeWth * lowlod_size; + sfee += lowestSizeWth * lowlod_size; + + // physics + // favor potencial optimized meshs versus automatic decomposition + if (physmesh_size != 0) + sfee += physMeshSizeWth * (physmesh_size + hulls_size / 4); // reduce cost of mandatory convex hull + else + sfee += physHullSizeWth * hulls_size; + + // bytes to money + sfee *= bytecost; + + cost.costFee = sfee; + return true; + } + + // parses a LOD or physics mesh component + private bool submesh(byte[] data, int offset, int size, out int ntriangles) + { + ntriangles = 0; + + OSD decodedMeshOsd = new OSD(); + byte[] meshBytes = new byte[size]; + System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); + try + { + using (MemoryStream inMs = new MemoryStream(meshBytes)) + { + using (MemoryStream outMs = new MemoryStream()) + { + using (ZOutputStream zOut = new ZOutputStream(outMs)) + { + byte[] readBuffer = new byte[4096]; + int readLen = 0; + while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) + { + zOut.Write(readBuffer, 0, readLen); + } + zOut.Flush(); + outMs.Seek(0, SeekOrigin.Begin); + + byte[] decompressedBuf = outMs.GetBuffer(); + decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + } + } + } + } + catch + { + return false; + } + + OSDArray decodedMeshOsdArray = null; + + byte[] dummy; + + decodedMeshOsdArray = (OSDArray)decodedMeshOsd; + foreach (OSD subMeshOsd in decodedMeshOsdArray) + { + if (subMeshOsd is OSDMap) + { + OSDMap subtmpmap = (OSDMap)subMeshOsd; + if (subtmpmap.ContainsKey("NoGeometry") && ((OSDBoolean)subtmpmap["NoGeometry"])) + continue; + + if (!subtmpmap.ContainsKey("Position")) + return false; + + if (subtmpmap.ContainsKey("TriangleList")) + { + dummy = subtmpmap["TriangleList"].AsBinary(); + ntriangles += dummy.Length / bytesPerCoord; + } + else + return false; + } + } + + return true; + } + + // parses convex hulls component + private bool hulls(byte[] data, int offset, int size, out int nvertices, out int nhulls) + { + nvertices = 0; + nhulls = 1; + + OSD decodedMeshOsd = new OSD(); + byte[] meshBytes = new byte[size]; + System.Buffer.BlockCopy(data, offset, meshBytes, 0, size); + try + { + using (MemoryStream inMs = new MemoryStream(meshBytes)) + { + using (MemoryStream outMs = new MemoryStream()) + { + using (ZOutputStream zOut = new ZOutputStream(outMs)) + { + byte[] readBuffer = new byte[4096]; + int readLen = 0; + while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) + { + zOut.Write(readBuffer, 0, readLen); + } + zOut.Flush(); + outMs.Seek(0, SeekOrigin.Begin); + + byte[] decompressedBuf = outMs.GetBuffer(); + decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + } + } + } + } + catch + { + return false; + } + + OSDMap cmap = (OSDMap)decodedMeshOsd; + if (cmap == null) + return false; + + byte[] dummy; + + // must have one of this + if (cmap.ContainsKey("BoundingVerts")) + { + dummy = cmap["BoundingVerts"].AsBinary(); + nvertices = dummy.Length / bytesPerCoord; + } + else + return false; + +/* upload is done with convex shape type + if (cmap.ContainsKey("HullList")) + { + dummy = cmap["HullList"].AsBinary(); + nhulls += dummy.Length; + } + + + if (cmap.ContainsKey("Positions")) + { + dummy = cmap["Positions"].AsBinary(); + nvertices = dummy.Length / bytesPerCoord; + } + */ + + return true; + } + + // returns streaming cost from on mesh LODs sizes in curCost and square of prim size length + private float streamingCost(ameshCostParam curCost, float sqdiam) + { + // compute efective areas + float ma = 262144f; + + float mh = sqdiam * highLodFactor; + if (mh > ma) + mh = ma; + float mm = sqdiam * midLodFactor; + if (mm > ma) + mm = ma; + + float ml = sqdiam * lowLodFactor; + if (ml > ma) + ml = ma; + + float mlst = ma; + + mlst -= ml; + ml -= mm; + mm -= mh; + + if (mlst < 1.0f) + mlst = 1.0f; + if (ml < 1.0f) + ml = 1.0f; + if (mm < 1.0f) + mm = 1.0f; + if (mh < 1.0f) + mh = 1.0f; + + ma = mlst + ml + mm + mh; + + // get LODs compressed sizes + // giving 384 bytes bonus + int lst = curCost.lowestLODSize - 384; + int l = curCost.lowLODSize - 384; + int m = curCost.medLODSize - 384; + int h = curCost.highLODSize - 384; + + // use previus higher LOD size on missing ones + if (m <= 0) + m = h; + if (l <= 0) + l = m; + if (lst <= 0) + lst = l; + + // force minumum sizes + if (lst < 16) + lst = 16; + if (l < 16) + l = 16; + if (m < 16) + m = 16; + if (h < 16) + h = 16; + + // compute cost weighted by relative effective areas + float cost = (float)lst * mlst + (float)l * ml + (float)m * mm + (float)h * mh; + cost /= ma; + + cost *= 0.004f; // overall tunning parameter + + return cost; + } + } +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 9b9f6a7..7c9a1c4 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -74,13 +74,12 @@ namespace OpenSim.Region.ClientStack.Linden private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); protected Scene m_scene; - + private Dictionary m_ids = new Dictionary(); private Dictionary> queues = new Dictionary>(); - private Dictionary m_QueueUUIDAvatarMapping = new Dictionary(); private Dictionary m_AvatarQueueUUIDMapping = new Dictionary(); - + #region INonSharedRegionModule methods public virtual void Initialise(IConfigSource config) { @@ -171,7 +170,7 @@ namespace OpenSim.Region.ClientStack.Linden foreach (KeyValuePair> kvp in queues) { MainConsole.Instance.OutputFormat( - "For agent {0} there are {1} messages queued for send.", + "For agent {0} there are {1} messages queued for send.", kvp.Key, kvp.Value.Count); } } @@ -190,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden { if (DebugLevel > 0) m_log.DebugFormat( - "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", + "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); queues[agentId] = new Queue(); @@ -201,6 +200,7 @@ namespace OpenSim.Region.ClientStack.Linden } /// + /// May return a null queue /// /// @@ -231,26 +231,20 @@ namespace OpenSim.Region.ClientStack.Linden lock (queue) queue.Enqueue(ev); } - else if (DebugLevel > 0) + else { - ScenePresence sp = m_scene.GetScenePresence(avatarID); - - // This assumes that an NPC should never have a queue. - if (sp != null && sp.PresenceType != PresenceType.Npc) - { OSDMap evMap = (OSDMap)ev; m_log.WarnFormat( - "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}", - sp.Name, sp.UUID, evMap["message"], m_scene.Name); - } + "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", + avatarID, evMap["message"], m_scene.Name); } - } + } catch (NullReferenceException e) { m_log.Error("[EVENTQUEUE] Caught exception: " + e); return false; } - + return true; } @@ -263,28 +257,13 @@ namespace OpenSim.Region.ClientStack.Linden lock (queues) queues.Remove(agentID); - List removeitems = new List(); lock (m_AvatarQueueUUIDMapping) m_AvatarQueueUUIDMapping.Remove(agentID); - UUID searchval = UUID.Zero; - - removeitems.Clear(); - - lock (m_QueueUUIDAvatarMapping) + lock (m_ids) { - foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) - { - searchval = m_QueueUUIDAvatarMapping[ky]; - - if (searchval == agentID) - { - removeitems.Add(ky); - } - } - - foreach (UUID ky in removeitems) - m_QueueUUIDAvatarMapping.Remove(ky); + if (!m_ids.ContainsKey(agentID)) + m_ids.Remove(agentID); } // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); @@ -309,55 +288,95 @@ namespace OpenSim.Region.ClientStack.Linden "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}", agentID, caps, m_scene.RegionInfo.RegionName); - // Let's instantiate a Queue for this agent right now - TryGetQueue(agentID); - UUID eventQueueGetUUID; + Queue queue; + Random rnd = new Random(Environment.TickCount); + int nrnd = rnd.Next(30000000); + if (nrnd < 0) + nrnd = -nrnd; - lock (m_AvatarQueueUUIDMapping) + lock (queues) { - // Reuse open queues. The client does! - if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + if (queues.ContainsKey(agentID)) + queue = queues[agentID]; + else + queue = null; + + if (queue == null) { - //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); - eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + queue = new Queue(); + queues[agentID] = queue; + + // push markers to handle old responses still waiting + // this will cost at most viewer getting two forced noevents + // even being a new queue better be safe + queue.Enqueue(null); + queue.Enqueue(null); // one should be enough + + lock (m_AvatarQueueUUIDMapping) + { + eventQueueGetUUID = UUID.Random(); + if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + { + // oops this should not happen ? + m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID without a queue"); + eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + } + m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); + } + lock (m_ids) + { + if (!m_ids.ContainsKey(agentID)) + m_ids.Add(agentID, nrnd); + else + m_ids[agentID] = nrnd; + } } else { - eventQueueGetUUID = UUID.Random(); - //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); + // push markers to handle old responses still waiting + // this will cost at most viewer getting two forced noevents + // even being a new queue better be safe + queue.Enqueue(null); + queue.Enqueue(null); // one should be enough + + // reuse or not to reuse TODO FIX + lock (m_AvatarQueueUUIDMapping) + { + // Reuse open queues. The client does! + // Its reuse caps path not queues those are been reused already + if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) + { + m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); + eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + } + else + { + eventQueueGetUUID = UUID.Random(); + m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); + m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); + } + } + lock (m_ids) + { + // change to negative numbers so they are changed at end of sending first marker + // old data on a queue may be sent on a response for a new caps + // but at least will be sent with coerent IDs + if (!m_ids.ContainsKey(agentID)) + m_ids.Add(agentID, -nrnd); // should not happen + else + m_ids[agentID] = -m_ids[agentID]; + } } } - lock (m_QueueUUIDAvatarMapping) - { - if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) - m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); - } - - lock (m_AvatarQueueUUIDMapping) - { - if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) - m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); - } - caps.RegisterPollHandler( "EventQueueGet", new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); - - Random rnd = new Random(Environment.TickCount); - lock (m_ids) - { - if (!m_ids.ContainsKey(agentID)) - m_ids.Add(agentID, rnd.Next(30000000)); - } } public bool HasEvents(UUID requestID, UUID agentID) { - // Don't use this, because of race conditions at agent closing time - //Queue queue = TryGetQueue(agentID); - Queue queue = GetQueue(agentID); if (queue != null) lock (queue) @@ -366,7 +385,8 @@ namespace OpenSim.Region.ClientStack.Linden return queue.Count > 0; } - return false; + //m_log.WarnFormat("POLLED FOR EVENTS BY {0} unknown agent", agentID); + return true; } /// @@ -383,6 +403,10 @@ namespace OpenSim.Region.ClientStack.Linden ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); } } + public void Drop(UUID requestID, UUID pAgentId) + { + // do nothing for now, hope client close will do it + } public Hashtable GetEvents(UUID requestID, UUID pAgentId) { @@ -395,55 +419,65 @@ namespace OpenSim.Region.ClientStack.Linden return NoEvents(requestID, pAgentId); } - OSD element; + OSD element = null;; + OSDArray array = new OSDArray(); + int thisID = 0; + bool negativeID = false; + lock (queue) { if (queue.Count == 0) return NoEvents(requestID, pAgentId); - element = queue.Dequeue(); // 15s timeout - } - - int thisID = 0; - lock (m_ids) - thisID = m_ids[pAgentId]; - OSDArray array = new OSDArray(); - if (element == null) // didn't have an event in 15s - { - // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! - array.Add(EventQueueHelper.KeepAliveEvent()); - //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", pAgentId, m_scene.RegionInfo.RegionName); - } - else - { - if (DebugLevel > 0) - LogOutboundDebugMessage(element, pAgentId); + lock (m_ids) + thisID = m_ids[pAgentId]; - array.Add(element); + if (thisID < 0) + { + negativeID = true; + thisID = -thisID; + } - lock (queue) + while (queue.Count > 0) { - while (queue.Count > 0) - { - element = queue.Dequeue(); + element = queue.Dequeue(); + // add elements until a marker is found + // so they get into a response + if (element == null) + break; + if (DebugLevel > 0) + LogOutboundDebugMessage(element, pAgentId); + array.Add(element); + thisID++; + } + } - if (DebugLevel > 0) - LogOutboundDebugMessage(element, pAgentId); + OSDMap events = null; - array.Add(element); - thisID++; - } - } + if (array.Count > 0) + { + events = new OSDMap(); + events.Add("events", array); + events.Add("id", new OSDInteger(thisID)); } - OSDMap events = new OSDMap(); - events.Add("events", array); + if (negativeID && element == null) + { + Random rnd = new Random(Environment.TickCount); + thisID = rnd.Next(30000000); + if (thisID < 0) + thisID = -thisID; + } - events.Add("id", new OSDInteger(thisID)); lock (m_ids) { m_ids[pAgentId] = thisID + 1; } + + // if there where no elements before a marker send a NoEvents + if (array.Count == 0) + return NoEvents(requestID, pAgentId); + Hashtable responsedata = new Hashtable(); responsedata["int_response_code"] = 200; responsedata["content_type"] = "application/xml"; @@ -461,266 +495,18 @@ namespace OpenSim.Region.ClientStack.Linden responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; responsedata["reusecontext"] = false; - responsedata["str_response_string"] = "Upstream error: "; - responsedata["error_status_text"] = "Upstream error:"; + responsedata["str_response_string"] = ""; + responsedata["error_status_text"] = ""; responsedata["http_protocol_version"] = "HTTP/1.0"; return responsedata; } - -// public Hashtable ProcessQueue(Hashtable request, UUID agentID, Caps caps) -// { -// // TODO: this has to be redone to not busy-wait (and block the thread), -// // TODO: as soon as we have a non-blocking way to handle HTTP-requests. -// -//// if (m_log.IsDebugEnabled) -//// { -//// String debug = "[EVENTQUEUE]: Got request for agent {0} in region {1} from thread {2}: [ "; -//// foreach (object key in request.Keys) -//// { -//// debug += key.ToString() + "=" + request[key].ToString() + " "; -//// } -//// m_log.DebugFormat(debug + " ]", agentID, m_scene.RegionInfo.RegionName, System.Threading.Thread.CurrentThread.Name); -//// } -// -// Queue queue = TryGetQueue(agentID); -// OSD element; -// -// lock (queue) -// element = queue.Dequeue(); // 15s timeout -// -// Hashtable responsedata = new Hashtable(); -// -// int thisID = 0; -// lock (m_ids) -// thisID = m_ids[agentID]; -// -// if (element == null) -// { -// //m_log.ErrorFormat("[EVENTQUEUE]: Nothing to process in " + m_scene.RegionInfo.RegionName); -// if (thisID == -1) // close-request -// { -// m_log.ErrorFormat("[EVENTQUEUE]: 404 in " + m_scene.RegionInfo.RegionName); -// responsedata["int_response_code"] = 404; //501; //410; //404; -// responsedata["content_type"] = "text/plain"; -// responsedata["keepalive"] = false; -// responsedata["str_response_string"] = "Closed EQG"; -// return responsedata; -// } -// responsedata["int_response_code"] = 502; -// responsedata["content_type"] = "text/plain"; -// responsedata["keepalive"] = false; -// responsedata["str_response_string"] = "Upstream error: "; -// responsedata["error_status_text"] = "Upstream error:"; -// responsedata["http_protocol_version"] = "HTTP/1.0"; -// return responsedata; -// } -// -// OSDArray array = new OSDArray(); -// if (element == null) // didn't have an event in 15s -// { -// // Send it a fake event to keep the client polling! It doesn't like 502s like the proxys say! -// array.Add(EventQueueHelper.KeepAliveEvent()); -// //m_log.DebugFormat("[EVENTQUEUE]: adding fake event for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); -// } -// else -// { -// array.Add(element); -// -// if (element is OSDMap) -// { -// OSDMap ev = (OSDMap)element; -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", -// ev["message"], m_scene.GetScenePresence(agentID).Name); -// } -// -// lock (queue) -// { -// while (queue.Count > 0) -// { -// element = queue.Dequeue(); -// -// if (element is OSDMap) -// { -// OSDMap ev = (OSDMap)element; -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", -// ev["message"], m_scene.GetScenePresence(agentID).Name); -// } -// -// array.Add(element); -// thisID++; -// } -// } -// } -// -// OSDMap events = new OSDMap(); -// events.Add("events", array); -// -// events.Add("id", new OSDInteger(thisID)); -// lock (m_ids) -// { -// m_ids[agentID] = thisID + 1; -// } -// -// responsedata["int_response_code"] = 200; -// responsedata["content_type"] = "application/xml"; -// responsedata["keepalive"] = false; -// responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(events); -// -// m_log.DebugFormat("[EVENTQUEUE]: sending response for {0} in region {1}: {2}", agentID, m_scene.RegionInfo.RegionName, responsedata["str_response_string"]); -// -// return responsedata; -// } - -// public Hashtable EventQueuePath2(Hashtable request) -// { -// string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); -// // pull off the last "/" in the path. -// Hashtable responsedata = new Hashtable(); -// capuuid = capuuid.Substring(0, capuuid.Length - 1); -// capuuid = capuuid.Replace("/CAPS/EQG/", ""); -// UUID AvatarID = UUID.Zero; -// UUID capUUID = UUID.Zero; -// -// // parse the path and search for the avatar with it registered -// if (UUID.TryParse(capuuid, out capUUID)) -// { -// lock (m_QueueUUIDAvatarMapping) -// { -// if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) -// { -// AvatarID = m_QueueUUIDAvatarMapping[capUUID]; -// } -// } -// -// if (AvatarID != UUID.Zero) -// { -// return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); -// } -// else -// { -// responsedata["int_response_code"] = 404; -// responsedata["content_type"] = "text/plain"; -// responsedata["keepalive"] = false; -// responsedata["str_response_string"] = "Not Found"; -// responsedata["error_status_text"] = "Not Found"; -// responsedata["http_protocol_version"] = "HTTP/1.0"; -// return responsedata; -// // return 404 -// } -// } -// else -// { -// responsedata["int_response_code"] = 404; -// responsedata["content_type"] = "text/plain"; -// responsedata["keepalive"] = false; -// responsedata["str_response_string"] = "Not Found"; -// responsedata["error_status_text"] = "Not Found"; -// responsedata["http_protocol_version"] = "HTTP/1.0"; -// return responsedata; -// // return 404 -// } -// } - - public OSD EventQueueFallBack(string path, OSD request, string endpoint) - { - // This is a fallback element to keep the client from loosing EventQueueGet - // Why does CAPS fail sometimes!? - m_log.Warn("[EVENTQUEUE]: In the Fallback handler! We lost the Queue in the rest handler!"); - string capuuid = path.Replace("/CAPS/EQG/",""); - capuuid = capuuid.Substring(0, capuuid.Length - 1); - -// UUID AvatarID = UUID.Zero; - UUID capUUID = UUID.Zero; - if (UUID.TryParse(capuuid, out capUUID)) - { -/* Don't remove this yet code cleaners! - * Still testing this! - * - lock (m_QueueUUIDAvatarMapping) - { - if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) - { - AvatarID = m_QueueUUIDAvatarMapping[capUUID]; - } - } - - - if (AvatarID != UUID.Zero) - { - // Repair the CAP! - //OpenSim.Framework.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); - //string capsBase = "/CAPS/EQG/"; - //caps.RegisterHandler("EventQueueGet", - //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", - //delegate(Hashtable m_dhttpMethod) - //{ - // return ProcessQueue(m_dhttpMethod, AvatarID, caps); - //})); - // start new ID sequence. - Random rnd = new Random(System.Environment.TickCount); - lock (m_ids) - { - if (!m_ids.ContainsKey(AvatarID)) - m_ids.Add(AvatarID, rnd.Next(30000000)); - } - - - int thisID = 0; - lock (m_ids) - thisID = m_ids[AvatarID]; - - BlockingLLSDQueue queue = GetQueue(AvatarID); - OSDArray array = new OSDArray(); - LLSD element = queue.Dequeue(15000); // 15s timeout - if (element == null) - { - - array.Add(EventQueueHelper.KeepAliveEvent()); - } - else - { - array.Add(element); - while (queue.Count() > 0) - { - array.Add(queue.Dequeue(1)); - thisID++; - } - } - OSDMap events = new OSDMap(); - events.Add("events", array); - - events.Add("id", new LLSDInteger(thisID)); - - lock (m_ids) - { - m_ids[AvatarID] = thisID + 1; - } - - return events; - } - else - { - return new LLSD(); - } -* -*/ - } - else - { - //return new LLSD(); - } - - return new OSDString("shutdown404!"); - } - +/* this is not a event message public void DisableSimulator(ulong handle, UUID avatarID) { OSD item = EventQueueHelper.DisableSimulator(handle); Enqueue(item, avatarID); } - +*/ public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) { if (DebugLevel > 0) @@ -732,7 +518,7 @@ namespace OpenSim.Region.ClientStack.Linden } public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath, - ulong regionHandle, int regionSizeX, int regionSizeY) + ulong regionHandle, int regionSizeX, int regionSizeY) { if (DebugLevel > 0) m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, endPoint={2}, avatarID={3}", @@ -742,9 +528,9 @@ namespace OpenSim.Region.ClientStack.Linden Enqueue(item, avatarID); } - public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, + public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, - uint locationID, uint flags, string capsURL, + uint locationID, uint flags, string capsURL, UUID avatarID, int regionSizeX, int regionSizeY) { if (DebugLevel > 0) @@ -774,33 +560,40 @@ namespace OpenSim.Region.ClientStack.Linden uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket) { - OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, - timeStamp, offline, parentEstateID, position, ttl, transactionID, + OSD item = EventQueueHelper.ChatterboxInvitation(sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, + timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket); Enqueue(item, toAgent); //m_log.InfoFormat("########### eq ChatterboxInvitation #############\n{0}", item); } - public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, - bool isModerator, bool textMute) + public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, + bool isModerator, bool textMute, bool isEnterorLeave) { OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, - isModerator, textMute); - Enqueue(item, fromAgent); + isModerator, textMute, isEnterorLeave); + Enqueue(item, toAgent); //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); } + public void ChatterBoxForceClose(UUID toAgent, UUID sessionID, string reason) + { + OSD item = EventQueueHelper.ChatterBoxForceClose(sessionID, reason); + + Enqueue(item, toAgent); + } + public void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) { OSD item = EventQueueHelper.ParcelProperties(parcelPropertiesMessage); Enqueue(item, avatarID); } - public void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) + public void GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data) { - OSD item = EventQueueHelper.GroupMembership(groupUpdate); - Enqueue(item, avatarID); + OSD item = EventQueueHelper.GroupMembershipData(receiverAgent, data); + Enqueue(item, receiverAgent); } public void QueryReply(PlacesReplyPacket groupUpdate, UUID avatarID) @@ -827,4 +620,4 @@ namespace OpenSim.Region.ClientStack.Linden Enqueue(item, avatarID); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs index 384af74..461f776 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueHelper.cs @@ -32,6 +32,8 @@ using OpenMetaverse.Packets; using OpenMetaverse.StructuredData; using OpenMetaverse.Messages.Linden; +using OpenSim.Framework; + namespace OpenSim.Region.ClientStack.Linden { public class EventQueueHelper @@ -76,9 +78,9 @@ namespace OpenSim.Region.ClientStack.Linden llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle))); llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes())); - llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port)); - llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX)); - llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY)); + llsdSimInfo.Add("Port", OSD.FromInteger(endPoint.Port)); + llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); + llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); OSDArray arr = new OSDArray(1); arr.Add(llsdSimInfo); @@ -88,7 +90,7 @@ namespace OpenSim.Region.ClientStack.Linden return BuildEvent("EnableSimulator", llsdBody); } - +/* public static OSD DisableSimulator(ulong handle) { //OSDMap llsdSimInfo = new OSDMap(1); @@ -103,7 +105,7 @@ namespace OpenSim.Region.ClientStack.Linden return BuildEvent("DisableSimulator", llsdBody); } - +*/ public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID agentID, UUID sessionID, @@ -157,6 +159,12 @@ namespace OpenSim.Region.ClientStack.Linden uint locationID, uint flags, string capsURL, UUID agentID, int regionSizeX, int regionSizeY) { + // not sure why flags get overwritten here + if ((flags & (uint)TeleportFlags.IsFlying) != 0) + flags = (uint)TeleportFlags.ViaLocation | (uint)TeleportFlags.IsFlying; + else + flags = (uint)TeleportFlags.ViaLocation; + OSDMap info = new OSDMap(); info.Add("AgentID", OSD.FromUUID(agentID)); info.Add("LocationID", OSD.FromInteger(4)); // TODO what is this? @@ -165,7 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden info.Add("SimAccess", OSD.FromInteger(simAccess)); info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes())); info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port)); - info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation +// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation + info.Add("TeleportFlags", OSD.FromUInteger(flags)); info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX)); info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY)); @@ -185,13 +194,13 @@ namespace OpenSim.Region.ClientStack.Linden script.Add("ItemID", OSD.FromUUID(itemID)); script.Add("Running", OSD.FromBoolean(running)); script.Add("Mono", OSD.FromBoolean(mono)); - + OSDArray scriptArr = new OSDArray(); scriptArr.Add(script); - + OSDMap body = new OSDMap(); body.Add("Script", scriptArr); - + return BuildEvent("ScriptRunningReply", body); } @@ -204,8 +213,8 @@ namespace OpenSim.Region.ClientStack.Linden {"sim-ip-and-port", new OSDString(simIpAndPort)}, {"seed-capability", new OSDString(seedcap)}, {"region-handle", OSD.FromULong(regionHandle)}, - {"region-size-x", OSD.FromInteger(regionSizeX)}, - {"region-size-y", OSD.FromInteger(regionSizeY)} + {"region-size-x", OSD.FromUInteger((uint)regionSizeX)}, + {"region-size-y", OSD.FromUInteger((uint)regionSizeY)} }; return BuildEvent("EstablishAgentCommunication", body); @@ -234,7 +243,7 @@ namespace OpenSim.Region.ClientStack.Linden { OSDMap messageParams = new OSDMap(15); messageParams.Add("type", new OSDInteger((int)dialog)); - + OSDArray positionArray = new OSDArray(3); positionArray.Add(OSD.FromReal(position.X)); positionArray.Add(OSD.FromReal(position.Y)); @@ -299,20 +308,29 @@ namespace OpenSim.Region.ClientStack.Linden } public static OSD ChatterBoxSessionAgentListUpdates(UUID sessionID, - UUID agentID, bool canVoiceChat, bool isModerator, bool textMute) + UUID agentID, bool canVoiceChat, bool isModerator, bool textMute, bool isEnterorLeave) { OSDMap body = new OSDMap(); OSDMap agentUpdates = new OSDMap(); OSDMap infoDetail = new OSDMap(); OSDMap mutes = new OSDMap(); + // this should be a list of agents and parameters + // foreach agent mutes.Add("text", OSD.FromBoolean(textMute)); infoDetail.Add("can_voice_chat", OSD.FromBoolean(canVoiceChat)); infoDetail.Add("is_moderator", OSD.FromBoolean(isModerator)); infoDetail.Add("mutes", mutes); OSDMap info = new OSDMap(); info.Add("info", infoDetail); + if(isEnterorLeave) + info.Add("transition",OSD.FromString("ENTER")); + else + info.Add("transition",OSD.FromString("LEAVE")); agentUpdates.Add(agentID.ToString(), info); + + // foreach end + body.Add("agent_updates", agentUpdates); body.Add("session_id", OSD.FromUUID(sessionID)); body.Add("updates", new OSD()); @@ -324,40 +342,54 @@ namespace OpenSim.Region.ClientStack.Linden return chatterBoxSessionAgentListUpdates; } - public static OSD GroupMembership(AgentGroupDataUpdatePacket groupUpdatePacket) + public static OSD ChatterBoxForceClose(UUID sessionID, string reason) { - OSDMap groupUpdate = new OSDMap(); - groupUpdate.Add("message", OSD.FromString("AgentGroupDataUpdate")); + OSDMap body = new OSDMap(2); + body.Add("session_id", new OSDUUID(sessionID)); + body.Add("reason", new OSDString(reason)); - OSDMap body = new OSDMap(); - OSDArray agentData = new OSDArray(); - OSDMap agentDataMap = new OSDMap(); - agentDataMap.Add("AgentID", OSD.FromUUID(groupUpdatePacket.AgentData.AgentID)); - agentData.Add(agentDataMap); - body.Add("AgentData", agentData); + OSDMap chatterBoxForceClose = new OSDMap(2); + chatterBoxForceClose.Add("message", new OSDString("ForceCloseChatterBoxSession")); + chatterBoxForceClose.Add("body", body); + return chatterBoxForceClose; + } - OSDArray groupData = new OSDArray(); + public static OSD GroupMembershipData(UUID receiverAgent, GroupMembershipData[] data) + { + OSDArray AgentData = new OSDArray(1); + OSDMap AgentDataMap = new OSDMap(1); + AgentDataMap.Add("AgentID", OSD.FromUUID(receiverAgent)); + AgentData.Add(AgentDataMap); - foreach (AgentGroupDataUpdatePacket.GroupDataBlock groupDataBlock in groupUpdatePacket.GroupData) + OSDArray GroupData = new OSDArray(data.Length); + OSDArray NewGroupData = new OSDArray(data.Length); + + foreach (GroupMembershipData membership in data) { - OSDMap groupDataMap = new OSDMap(); - groupDataMap.Add("ListInProfile", OSD.FromBoolean(false)); - groupDataMap.Add("GroupID", OSD.FromUUID(groupDataBlock.GroupID)); - groupDataMap.Add("GroupInsigniaID", OSD.FromUUID(groupDataBlock.GroupInsigniaID)); - groupDataMap.Add("Contribution", OSD.FromInteger(groupDataBlock.Contribution)); - groupDataMap.Add("GroupPowers", OSD.FromBinary(ulongToByteArray(groupDataBlock.GroupPowers))); - groupDataMap.Add("GroupName", OSD.FromString(Utils.BytesToString(groupDataBlock.GroupName))); - groupDataMap.Add("AcceptNotices", OSD.FromBoolean(groupDataBlock.AcceptNotices)); + OSDMap GroupDataMap = new OSDMap(6); + OSDMap NewGroupDataMap = new OSDMap(1); + + GroupDataMap.Add("GroupID", OSD.FromUUID(membership.GroupID)); + GroupDataMap.Add("GroupPowers", OSD.FromULong(membership.GroupPowers)); + GroupDataMap.Add("AcceptNotices", OSD.FromBoolean(membership.AcceptNotices)); + GroupDataMap.Add("GroupInsigniaID", OSD.FromUUID(membership.GroupPicture)); + GroupDataMap.Add("Contribution", OSD.FromInteger(membership.Contribution)); + GroupDataMap.Add("GroupName", OSD.FromString(membership.GroupName)); + NewGroupDataMap.Add("ListInProfile", OSD.FromBoolean(membership.ListInProfile)); + + GroupData.Add(GroupDataMap); + NewGroupData.Add(NewGroupDataMap); + } - groupData.Add(groupDataMap); + OSDMap llDataStruct = new OSDMap(3); + llDataStruct.Add("AgentData", AgentData); + llDataStruct.Add("GroupData", GroupData); + llDataStruct.Add("NewGroupData", NewGroupData); - } - body.Add("GroupData", groupData); - groupUpdate.Add("body", body); + return BuildEvent("AgentGroupDataUpdate", llDataStruct); - return groupUpdate; } - + public static OSD PlacesQuery(PlacesReplyPacket PlacesReply) { OSDMap placesReply = new OSDMap(); @@ -391,7 +423,7 @@ namespace OpenSim.Region.ClientStack.Linden QueryDataMap.Add("SnapShotID", OSD.FromUUID(groupDataBlock.SnapshotID)); QueryDataMap.Add("ProductSku", OSD.FromInteger(0)); QueryDataMap.Add("Price", OSD.FromInteger(groupDataBlock.Price)); - + QueryData.Add(QueryDataMap); } body.Add("QueryData", QueryData); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 16a902d..ee3f4f1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -71,7 +71,6 @@ namespace OpenSim.Region.ClientStack.Linden.Tests IConfigSource config = new IniConfigSource(); config.AddConfig("Startup"); - config.Configs["Startup"].Set("EventQueue", "true"); CapabilitiesModule capsModule = new CapabilitiesModule(); m_eqgMod = new EventQueueGetModule(); @@ -126,6 +125,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + // initial queue as null events + eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + { + eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + if((int)eventsResponse["int_response_code"] != (int)HttpStatusCode.OK) + eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID); + } + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); // Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); @@ -172,7 +180,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); - UUID npcId + UUID npcId = m_npcMod.CreateNPC( "John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance()); @@ -187,4 +195,4 @@ namespace OpenSim.Region.ClientStack.Linden.Tests Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway)); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs deleted file mode 100644 index 6617bbc..0000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetDisplayNamesModule.cs +++ /dev/null @@ -1,144 +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.Drawing; -using System.Drawing.Imaging; -using System.Reflection; -using System.IO; -using System.Web; -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; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; -using Caps = OpenSim.Framework.Capabilities.Caps; -using OpenSim.Capabilities.Handlers; - -namespace OpenSim.Region.ClientStack.Linden -{ - - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetDisplayNamesModule")] - public class GetDisplayNamesModule : INonSharedRegionModule - { - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private Scene m_scene; - private IUserManagement m_UserManager; - - private bool m_Enabled = false; - - private string m_URL; - - #region ISharedRegionModule Members - - public void Initialise(IConfigSource source) - { - IConfig config = source.Configs["ClientStack.LindenCaps"]; - if (config == null) - return; - - m_URL = config.GetString("Cap_GetDisplayNames", string.Empty); - if (m_URL != string.Empty) - m_Enabled = true; - } - - public void AddRegion(Scene s) - { - if (!m_Enabled) - return; - - m_scene = s; - } - - public void RemoveRegion(Scene s) - { - if (!m_Enabled) - return; - - m_scene.EventManager.OnRegisterCaps -= RegisterCaps; - m_scene = null; - } - - public void RegionLoaded(Scene s) - { - if (!m_Enabled) - return; - - m_UserManager = m_scene.RequestModuleInterface(); - m_scene.EventManager.OnRegisterCaps += RegisterCaps; - } - - public void PostInitialise() - { - } - - public void Close() { } - - public string Name { get { return "GetDisplayNamesModule"; } } - - public Type ReplaceableInterface - { - get { return null; } - } - - #endregion - - public void RegisterCaps(UUID agentID, Caps caps) - { - UUID capID = UUID.Random(); - - if (m_URL == "localhost") - { - m_log.DebugFormat("[GET_DISPLAY_NAMES]: /CAPS/agents/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); - caps.RegisterHandler( - "GetDisplayNames", - new GetDisplayNamesHandler("/CAPS/agents" + capID + "/", m_UserManager, "GetDisplayNames", agentID.ToString())); - } - else - { -// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); - IExternalCapsModule handler = m_scene.RequestModuleInterface(); - if (handler != null) - handler.RegisterExternalUserCapsHandler(agentID,caps,"GetDisplayNames", m_URL); - else - caps.RegisterHandler("GetDisplayNames", m_URL); - } - } - - } -} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index f57d857..ba917e39 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs @@ -27,11 +27,14 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; using System.IO; +using System.Threading; using System.Web; using Mono.Addins; +using OpenSim.Framework.Monitoring; using log4net; using Nini.Config; using OpenMetaverse; @@ -52,15 +55,46 @@ namespace OpenSim.Region.ClientStack.Linden { // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; private IAssetService m_AssetService; private bool m_Enabled = true; private string m_URL; + private string m_URL2; private string m_RedirectURL = null; private string m_RedirectURL2 = null; + struct aPollRequest + { + public PollServiceMeshEventArgs thepoll; + public UUID reqID; + public Hashtable request; + } + + public class aPollResponse + { + public Hashtable response; + public int bytes; + public int lod; + } + + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static GetMeshHandler m_getMeshHandler; + + private IAssetService m_assetService = null; + + private Dictionary m_capsDict = new Dictionary(); + private static Thread[] m_workerThreads = null; + private static int m_NumberScenes = 0; + private static OpenSim.Framework.BlockingQueue m_queue = + new OpenSim.Framework.BlockingQueue(); + + private Dictionary m_pollservices = new Dictionary(); + + #region Region Module interfaceBase Members public Type ReplaceableInterface @@ -87,6 +121,7 @@ namespace OpenSim.Region.ClientStack.Linden if (m_URL2 != string.Empty) { m_Enabled = true; + m_RedirectURL2 = config.GetString("GetMesh2RedirectURL"); } } @@ -97,6 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden return; m_scene = pScene; + + m_assetService = pScene.AssetService; } public void RemoveRegion(Scene scene) @@ -105,6 +142,9 @@ namespace OpenSim.Region.ClientStack.Linden return; m_scene.EventManager.OnRegisterCaps -= RegisterCaps; + m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; + m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; + m_NumberScenes--; m_scene = null; } @@ -115,55 +155,302 @@ namespace OpenSim.Region.ClientStack.Linden m_AssetService = m_scene.RequestModuleInterface(); m_scene.EventManager.OnRegisterCaps += RegisterCaps; - } + // We'll reuse the same handler for all requests. + m_getMeshHandler = new GetMeshHandler(m_assetService); + m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; + m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; + m_NumberScenes++; + + if (m_workerThreads == null) + { + m_workerThreads = new Thread[2]; + + for (uint i = 0; i < 2; i++) + { + m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests, + String.Format("GetMeshWorker{0}", i), + ThreadPriority.Normal, + true, + false, + null, + int.MaxValue); + } + } + } - public void Close() { } + public void Close() + { + if(m_NumberScenes <= 0 && m_workerThreads != null) + { + m_log.DebugFormat("[GetMeshModule] Closing"); + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + // This will fail on region shutdown. Its harmless. + // Prevent red ink. + try + { + m_queue.Clear(); + } + catch {} + } + } public string Name { get { return "GetMeshModule"; } } #endregion + private static void DoMeshRequests() + { + while(true) + { + aPollRequest poolreq = m_queue.Dequeue(4500); + Watchdog.UpdateThread(); + if(m_NumberScenes <= 0) + return; + if(poolreq.reqID != UUID.Zero) + poolreq.thepoll.Process(poolreq); + } + } - public void RegisterCaps(UUID agentID, Caps caps) + // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. + public void ThrottleUpdate(ScenePresence p) { - UUID capID = UUID.Random(); - bool getMeshRegistered = false; + UUID user = p.UUID; + int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset); + PollServiceMeshEventArgs args; + if (m_pollservices.TryGetValue(user, out args)) + { + args.UpdateThrottle(imagethrottle); + } + } + + private class PollServiceMeshEventArgs : PollServiceEventArgs + { + private List requests = + new List(); + private Dictionary responses = + new Dictionary(); + + private Scene m_scene; + private MeshCapsDataThrottler m_throttler; + public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) : + base(null, uri, null, null, null, pId, int.MaxValue) + { + m_scene = scene; + m_throttler = new MeshCapsDataThrottler(100000); + // x is request id, y is userid + HasEvents = (x, y) => + { + lock (responses) + { + bool ret = m_throttler.hasEvents(x, responses); + return ret; + + } + }; + GetEvents = (x, y) => + { + lock (responses) + { + try + { + return responses[x].response; + } + finally + { + responses.Remove(x); + m_throttler.PassTime(); + } + } + }; + // x is request id, y is request data hashtable + Request = (x, y) => + { + aPollRequest reqinfo = new aPollRequest(); + reqinfo.thepoll = this; + reqinfo.reqID = x; + reqinfo.request = y; + + m_queue.Enqueue(reqinfo); + m_throttler.PassTime(); + }; - if (m_URL == string.Empty) + // this should never happen except possible on shutdown + NoEvents = (x, y) => + { + /* + lock (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(aPollRequest requestinfo) { + Hashtable response; + + UUID requestID = requestinfo.reqID; + + if(m_scene.ShuttingDown) + return; + + // 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; + + lock (responses) + responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 }; + + return; + } + + response = m_getMeshHandler.Handle(requestinfo.request); + lock (responses) + { + responses[requestID] = new aPollResponse() + { + bytes = (int)response["int_bytes"], + lod = (int)response["int_lod"], + response = response + }; + + } + m_throttler.PassTime(); + } + internal void UpdateThrottle(int pthrottle) + { + int tmp = 2 * pthrottle; + if(tmp < 10000) + tmp = 10000; + m_throttler.ThrottleBytes = tmp; } - else if (m_URL == "localhost") + } + + public void RegisterCaps(UUID agentID, Caps caps) + { +// UUID capID = UUID.Random(); + if (m_URL == "localhost") { - getMeshRegistered = true; - caps.RegisterHandler( - "GetMesh", - new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL)); + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + // Register this as a poll service + PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene); + + args.Type = PollServiceEventArgs.EventType.Mesh; + 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("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + m_pollservices[agentID] = args; + m_capsDict[agentID] = capUrl; } else { caps.RegisterHandler("GetMesh", m_URL); } + } - if(m_URL2 == string.Empty) + private void DeregisterCaps(UUID agentID, Caps caps) + { + string capUrl; + PollServiceMeshEventArgs args; + if (m_capsDict.TryGetValue(agentID, out capUrl)) + { + MainServer.Instance.RemoveHTTPHandler("", capUrl); + m_capsDict.Remove(agentID); + } + if (m_pollservices.TryGetValue(agentID, out args)) { + m_pollservices.Remove(agentID); + } + } + + internal sealed class MeshCapsDataThrottler + { + private double lastTimeElapsed = 0; + private double BytesSent = 0; + public MeshCapsDataThrottler(int pBytes) + { + if(pBytes < 10000) + pBytes = 10000; + ThrottleBytes = pBytes; + lastTimeElapsed = Util.GetTimeStampMS(); } - else if (m_URL2 == "localhost") + + public bool hasEvents(UUID key, Dictionary responses) { - if (!getMeshRegistered) + PassTime(); + // Note, this is called IN LOCK + bool haskey = responses.ContainsKey(key); + + if (!haskey) + { + return false; + } + aPollResponse response; + if (responses.TryGetValue(key, out response)) { - caps.RegisterHandler( - "GetMesh2", - new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh2", agentID.ToString(), m_RedirectURL2)); + // Normal + if (BytesSent <= ThrottleBytes) + { + BytesSent += response.bytes; + return true; + } + else + { + return false; + } } + return haskey; } - else + + public void PassTime() { - caps.RegisterHandler("GetMesh2", m_URL2); + double currenttime = Util.GetTimeStampMS(); + double timeElapsed = currenttime - lastTimeElapsed; + if(timeElapsed < 50.0) + return; + int add = (int)(ThrottleBytes * timeElapsed * 0.001); + if (add >= 1000) + { + lastTimeElapsed = currenttime; + BytesSent -= add; + if (BytesSent < 0) BytesSent = 0; + } } - } + public int ThrottleBytes; + } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index bb932f2..b01c7dc 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs @@ -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,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 { @@ -54,27 +50,49 @@ namespace OpenSim.Region.ClientStack.Linden [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")] public class GetTextureModule : INonSharedRegionModule { -// private static readonly ILog m_log = -// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + + struct aPollRequest + { + public PollServiceTextureEventArgs thepoll; + public UUID reqID; + public Hashtable request; + public bool send503; + } + + public class aPollResponse + { + public Hashtable response; + public int bytes; + } + + + 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; + + private IAssetService m_assetService = null; + + private Dictionary m_capsDict = new Dictionary(); + private static Thread[] m_workerThreads = null; + private static int m_NumberScenes = 0; + private static OpenSim.Framework.BlockingQueue m_queue = + new OpenSim.Framework.BlockingQueue(); - // TODO: Change this to a config option - private string m_RedirectURL = null; + private Dictionary m_pollservices = new Dictionary(); - private string m_URL; + private string m_Url = "localhost"; #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) @@ -82,39 +100,108 @@ namespace OpenSim.Region.ClientStack.Linden m_Enabled = true; m_RedirectURL = config.GetString("GetTextureRedirectURL"); } +*/ + m_Url = config.GetString("Cap_GetTexture", "localhost"); } 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.EventManager.OnThrottleUpdate -= ThrottleUpdate; + m_NumberScenes--; 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(); m_scene.EventManager.OnRegisterCaps += RegisterCaps; + m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; + m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; + + m_NumberScenes++; + + if (m_workerThreads == null) + { + m_workerThreads = new Thread[2]; + + for (uint i = 0; i < 2; i++) + { + m_workerThreads[i] = WorkManager.StartThread(DoTextureRequests, + String.Format("GetTextureWorker{0}", i), + ThreadPriority.Normal, + true, + false, + null, + int.MaxValue); + } + } + } + private int ExtractImageThrottle(byte[] pthrottles) + { + + byte[] adjData; + int pos = 0; + + if (!BitConverter.IsLittleEndian) + { + byte[] newData = new byte[7 * 4]; + Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4); + + for (int i = 0; i < 7; i++) + Array.Reverse(newData, i * 4, 4); + + adjData = newData; + } + else + { + adjData = pthrottles; + } + + pos = pos + 20; + int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4; + //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); + return texture; + } + + // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. + public void ThrottleUpdate(ScenePresence p) + { + byte[] throttles = p.ControllingClient.GetThrottlesPacked(1); + UUID user = p.UUID; + int imagethrottle = ExtractImageThrottle(throttles); + PollServiceTextureEventArgs args; + if (m_pollservices.TryGetValue(user,out args)) + { + args.UpdateThrottle(imagethrottle); + } } public void PostInitialise() { } - public void Close() { } + public void Close() + { + if(m_NumberScenes <= 0 && m_workerThreads != null) + { + m_log.DebugFormat("[GetTextureModule] Closing"); + + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + + m_queue.Clear(); + } + } public string Name { get { return "GetTextureModule"; } } @@ -125,28 +212,277 @@ namespace OpenSim.Region.ClientStack.Linden #endregion - public void RegisterCaps(UUID agentID, Caps caps) + private class PollServiceTextureEventArgs : PollServiceEventArgs { - UUID capID = UUID.Random(); + private List requests = + new List(); + private Dictionary responses = + new Dictionary(); + + private Scene m_scene; + private CapsDataThrottler m_throttler = new CapsDataThrottler(100000); + public PollServiceTextureEventArgs(UUID pId, Scene scene) : + base(null, "", null, null, null, pId, int.MaxValue) + { + m_scene = scene; + // x is request id, y is userid + HasEvents = (x, y) => + { + lock (responses) + { + bool ret = m_throttler.hasEvents(x, responses); + return ret; + + } + }; + GetEvents = (x, y) => + { + lock (responses) + { + try + { + return responses[x].response; + } + finally + { + responses.Remove(x); + m_throttler.PassTime(); + } + } + }; + // x is request id, y is request data hashtable + Request = (x, y) => + { + aPollRequest reqinfo = new aPollRequest(); + reqinfo.thepoll = this; + reqinfo.reqID = x; + reqinfo.request = y; + reqinfo.send503 = false; + + lock (responses) + { + if (responses.Count > 0) + { + if (m_queue.Count() >= 4) + { + // Never allow more than 4 fetches to wait + reqinfo.send503 = true; + } + } + } + m_queue.Enqueue(reqinfo); + m_throttler.PassTime(); + }; + + // this should never happen except possible on shutdown + NoEvents = (x, y) => + { +/* + lock (requests) + { + Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); + requests.Remove(request); + } +*/ + Hashtable response = new Hashtable(); - //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); - if (m_URL == "localhost") + 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(aPollRequest requestinfo) { -// 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_RedirectURL)); + Hashtable response; + + UUID requestID = requestinfo.reqID; + + if(m_scene.ShuttingDown) + return; + + if (requestinfo.send503) + { + response = new Hashtable(); + + response["int_response_code"] = 503; + response["str_response_string"] = "Throttled"; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; + + Hashtable headers = new Hashtable(); + headers["Retry-After"] = 30; + response["headers"] = headers; + + lock (responses) + responses[requestID] = new aPollResponse() {bytes = 0, response = response}; + + return; + } + + // 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; + + lock (responses) + responses[requestID] = new aPollResponse() {bytes = 0, response = response}; + + return; + } + + response = m_getTextureHandler.Handle(requestinfo.request); + lock (responses) + { + responses[requestID] = new aPollResponse() + { + bytes = (int) response["int_bytes"], + response = response + }; + + } + m_throttler.PassTime(); } - else + + internal void UpdateThrottle(int pimagethrottle) { -// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); + int tmp = 2 * pimagethrottle; + if(tmp < 10000) + tmp = 10000; + m_throttler.ThrottleBytes = tmp; + } + } + + private void RegisterCaps(UUID agentID, Caps caps) + { + if (m_Url == "localhost") + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + // Register this as a poll service + 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"; + } IExternalCapsModule handler = m_scene.RequestModuleInterface(); if (handler != null) - handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture", m_URL); + handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl); else - caps.RegisterHandler("GetTexture", m_URL); + caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + m_pollservices[agentID] = args; + m_capsDict[agentID] = capUrl; + } + else + { + caps.RegisterHandler("GetTexture", m_Url); + } + } + + private void DeregisterCaps(UUID agentID, Caps caps) + { + PollServiceTextureEventArgs args; + + MainServer.Instance.RemoveHTTPHandler("", m_Url); + m_capsDict.Remove(agentID); + + if (m_pollservices.TryGetValue(agentID, out args)) + { + m_pollservices.Remove(agentID); + } + } + + private static void DoTextureRequests() + { + while (true) + { + aPollRequest poolreq = m_queue.Dequeue(4500); + Watchdog.UpdateThread(); + if(m_NumberScenes <= 0) + return; + if(poolreq.reqID != UUID.Zero) + poolreq.thepoll.Process(poolreq); } } + internal sealed class CapsDataThrottler + { + private double lastTimeElapsed = 0; + private volatile int BytesSent = 0; + public CapsDataThrottler(int pBytes) + { + if(pBytes < 10000) + pBytes = 10000; + ThrottleBytes = pBytes; + lastTimeElapsed = Util.GetTimeStampMS(); + } + public bool hasEvents(UUID key, Dictionary responses) + { + PassTime(); + // Note, this is called IN LOCK + bool haskey = responses.ContainsKey(key); + if (!haskey) + { + return false; + } + GetTextureModule.aPollResponse response; + if (responses.TryGetValue(key, out response)) + { + // This is any error response + if (response.bytes == 0) + return true; + + // Normal + if (BytesSent <= ThrottleBytes) + { + BytesSent += response.bytes; + return true; + } + else + { + return false; + } + } + + return haskey; + } + + public void PassTime() + { + double currenttime = Util.GetTimeStampMS(); + double timeElapsed = currenttime - lastTimeElapsed; + if(timeElapsed < 50.0) + return; + int add = (int)(ThrottleBytes * timeElapsed * 0.001); + if (add >= 1000) + { + lastTimeElapsed = currenttime; + BytesSent -= add; + if (BytesSent < 0) BytesSent = 0; + } + } + public int ThrottleBytes; + } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs index 45d33cd..44bf1a5 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs @@ -129,23 +129,23 @@ namespace OpenSim.Region.ClientStack.Linden // m_log.DebugFormat("[MESH UPLOAD FLAG MODULE]: MeshUploadFlag request"); OSDMap data = new OSDMap(); - ScenePresence sp = m_scene.GetScenePresence(agentID); - data["username"] = sp.Firstname + "." + sp.Lastname; - data["display_name_next_update"] = new OSDDate(DateTime.Now); - data["legacy_first_name"] = sp.Firstname; - data["mesh_upload_status"] = "valid"; - data["display_name"] = sp.Firstname + " " + sp.Lastname; - data["legacy_last_name"] = sp.Lastname; - data["id"] = agentID; - data["is_display_name_default"] = true; +// ScenePresence sp = m_scene.GetScenePresence(m_agentID); +// data["username"] = sp.Firstname + "." + sp.Lastname; +// data["display_name_next_update"] = new OSDDate(DateTime.Now); +// data["legacy_first_name"] = sp.Firstname; + data["mesh_upload_status"] = "valid"; +// data["display_name"] = sp.Firstname + " " + sp.Lastname; +// data["legacy_last_name"] = sp.Lastname; +// data["id"] = m_agentID; +// data["is_display_name_default"] = true; //Send back data Hashtable responsedata = new Hashtable(); - responsedata["int_response_code"] = 200; + responsedata["int_response_code"] = 200; responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; responsedata["str_response_string"] = OSDParser.SerializeLLSDXmlString(data); return responsedata; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs deleted file mode 100644 index f69a0bb..0000000 --- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs +++ /dev/null @@ -1,297 +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; -using PermissionMask = OpenSim.Framework.PermissionMask; - -namespace OpenSim.Region.ClientStack.Linden -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "NewFileAgentInventoryVariablePriceModule")] - 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 Region Module interfaceBase 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(); - m_scene.EventManager.OnRegisterCaps += RegisterCaps; - } - - #endregion - - - #region Region Module interface - - - - 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( - "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(); - - 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); - } - } -} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 94f8bc1..b044e56 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.ClientStack.Linden { // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; #region INonSharedRegionModule Members @@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden } public void Close() - { + { } public string Name @@ -121,6 +121,9 @@ namespace OpenSim.Region.ClientStack.Linden OSD r = OSDParser.DeserializeLLSDXml((string)request["requestbody"]); + if (r.Type != OSDType.Map) // not a proper req + return responsedata; + //UUID session_id = UUID.Zero; bool bypass_raycast = false; uint everyone_mask = 0; @@ -157,9 +160,6 @@ namespace OpenSim.Region.ClientStack.Linden int state = 0; int lastattach = 0; - if (r.Type != OSDType.Map) // not a proper req - return responsedata; - OSDMap rm = (OSDMap)r; if (rm.ContainsKey("ObjectData")) //v2 @@ -307,8 +307,6 @@ namespace OpenSim.Region.ClientStack.Linden } } - - Vector3 pos = m_scene.GetNewRezLocation(ray_start, ray_end, ray_target_id, rotation, (bypass_raycast) ? (byte)1 : (byte)0, (ray_end_is_intersection) ? (byte)1 : (byte)0, true, scale, false); PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox(); @@ -359,6 +357,8 @@ namespace OpenSim.Region.ClientStack.Linden rootpart.NextOwnerMask = next_owner_mask; rootpart.Material = (byte)material; + obj.InvalidateDeepEffectivePerms(); + m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor); responsedata["int_response_code"] = 200; //501; //410; //404; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 769fe28..116c51f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs @@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.Linden if (i == 0) { rootpos = obj.Position; -// rootrot = obj.Rotation; +// rootrot = obj.Rotation; } // Combine the extraparams data into it's ugly blob again.... @@ -284,6 +284,7 @@ namespace OpenSim.Region.ClientStack.Linden prim.OwnerID = AgentId; prim.GroupID = obj.GroupID; prim.LastOwnerID = prim.OwnerID; + prim.RezzerID = AgentId; prim.CreationDate = Util.UnixTimeSinceEpoch(); prim.Name = obj.Name; prim.Description = ""; @@ -320,7 +321,7 @@ namespace OpenSim.Region.ClientStack.Linden pbs.TextureEntry = tmp.GetBytes(); prim.Shape = pbs; prim.Scale = obj.Scale; - + SceneObjectGroup grp = new SceneObjectGroup(); grp.SetRootPart(prim); @@ -328,21 +329,22 @@ namespace OpenSim.Region.ClientStack.Linden if (i == 0) { rootGroup = grp; - + } grp.AttachToScene(m_scene); grp.AbsolutePosition = obj.Position; prim.RotationOffset = obj.Rotation; - + + // Required for linking grp.RootPart.ClearUpdateSchedule(); - + if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos)) { m_scene.AddSceneObject(grp); grp.AbsolutePosition = obj.Position; } - + allparts[i] = grp; } @@ -358,7 +360,7 @@ namespace OpenSim.Region.ClientStack.Linden pos = m_scene.GetNewRezLocation( Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale, false); - + responsedata["int_response_code"] = 200; //501; //410; //404; responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; @@ -366,7 +368,7 @@ namespace OpenSim.Region.ClientStack.Linden return responsedata; } - + private string ConvertUintToBytes(uint val) { byte[] resultbytes = Utils.UIntToBytes(val); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 0adfa1a..f36826b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Region.ClientStack.LindenCaps")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,9 +25,9 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("0.8.3.*")] +[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index a133a69..e8387e3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs @@ -58,12 +58,14 @@ namespace OpenSim.Region.ClientStack.Linden { // private static readonly ILog m_log = // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + private Scene m_scene; private IEventQueue m_eventQueue; private Commands m_commands = new Commands(); public ICommands Commands { get { return m_commands; } } + public event ConsoleMessage OnConsoleMessage; + public void Initialise(IConfigSource source) { m_commands.AddCommand( "Help", false, "help", "help []", "Display help on a particular command or on a list of commands in a category", Help); @@ -102,7 +104,7 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { - if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID)) + if (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(agentID) && !m_scene.Permissions.IsGod(agentID)) return; UUID capID = UUID.Random(); @@ -118,6 +120,11 @@ namespace OpenSim.Region.ClientStack.Linden OSD osd = OSD.FromString(message); m_eventQueue.Enqueue(EventQueueHelper.BuildEvent("SimConsoleResponse", osd), agentID); + + ConsoleMessage handlerConsoleMessage = OnConsoleMessage; + + if (handlerConsoleMessage != null) + handlerConsoleMessage( agentID, message); } public bool RunCommand(string command, UUID invokerID) @@ -148,7 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden SendConsoleOutput(agentID, reply); } - + public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) { m_commands.AddCommand(module, shared, command, help, longhelp, fn); @@ -178,8 +185,9 @@ namespace OpenSim.Region.ClientStack.Linden protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - StreamReader reader = new StreamReader(request); - string message = reader.ReadToEnd(); + string message; + using(StreamReader reader = new StreamReader(request)) + message = reader.ReadToEnd(); OSD osd = OSDParser.DeserializeLLSDXml(message); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index e258bcb..39f5baf 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs @@ -50,12 +50,12 @@ namespace OpenSim.Region.ClientStack.Linden /// This is required for uploading Mesh. /// Since is accepts an open-ended response, we also send more information /// for viewers that care to interpret it. - /// + /// /// NOTE: Part of this code was adapted from the Aurora project, specifically /// the normal part of the response in the capability handler. /// [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimulatorFeaturesModule")] - public class SimulatorFeaturesModule : ISharedRegionModule, ISimulatorFeaturesModule + public class SimulatorFeaturesModule : INonSharedRegionModule, ISimulatorFeaturesModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -82,7 +82,7 @@ namespace OpenSim.Region.ClientStack.Linden IConfig config = source.Configs["SimulatorFeatures"]; if (config != null) - { + { // // All this is obsolete since getting these features from the grid service!! // Will be removed after the next release @@ -126,10 +126,6 @@ namespace OpenSim.Region.ClientStack.Linden GetGridExtraFeatures(s); } - public void PostInitialise() - { - } - public void Close() { } public string Name { get { return "SimulatorFeaturesModule"; } } @@ -155,6 +151,7 @@ namespace OpenSim.Region.ClientStack.Linden m_features["MeshRezEnabled"] = true; m_features["MeshUploadEnabled"] = true; m_features["MeshXferEnabled"] = true; + m_features["PhysicsMaterialsEnabled"] = true; OSDMap typesMap = new OSDMap(); @@ -173,6 +170,10 @@ namespace OpenSim.Region.ClientStack.Linden else extrasMap = new OSDMap(); + extrasMap["AvatarSkeleton"] = true; + extrasMap["AnimationSet"] = true; + + // TODO: Take these out of here into their respective modules, like map-server-url if (m_SearchURL != string.Empty) extrasMap["search-server-url"] = m_SearchURL; if (!string.IsNullOrEmpty(m_DestinationGuideURL)) @@ -250,7 +251,7 @@ namespace OpenSim.Region.ClientStack.Linden //Send back data Hashtable responsedata = new Hashtable(); - responsedata["int_response_code"] = 200; + responsedata["int_response_code"] = 200; responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs index dd4a691..6ffed4d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Tests/WebFetchInvDescModuleTests.cs @@ -52,6 +52,7 @@ using OSDMap = OpenMetaverse.StructuredData.OSDMap; namespace OpenSim.Region.ClientStack.Linden.Caps.Tests { + /* [TestFixture] public class WebFetchInvDescModuleTests : OpenSimTestCase { @@ -150,10 +151,11 @@ namespace OpenSim.Region.ClientStack.Linden.Caps.Tests OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody); OSDArray foldersOsd = (OSDArray)responseOsd["folders"]; OSDMap folderOsd = (OSDMap)foldersOsd[0]; - + // A sanity check that the response has the expected number of descendents for a default inventory // TODO: Need a more thorough check. Assert.That((int)folderOsd["descendents"], Is.EqualTo(16)); } } + */ } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 8cdebcd..b406b37 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs @@ -63,23 +63,23 @@ namespace OpenSim.Region.ClientStack.Linden private static readonly string m_uploadBakedTexturePath = "0010/";// This is in the LandManagementModule. private Scene m_scene; - private bool m_persistBakedTextures; - private IBakedTextureModule m_BakedTextureModule; + private string m_URL; public void Initialise(IConfigSource source) { - IConfig appearanceConfig = source.Configs["Appearance"]; - if (appearanceConfig != null) - m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty); +// IConfig appearanceConfig = source.Configs["Appearance"]; } public void AddRegion(Scene s) { m_scene = s; - } public void RemoveRegion(Scene s) @@ -87,188 +87,28 @@ namespace OpenSim.Region.ClientStack.Linden s.EventManager.OnRegisterCaps -= RegisterCaps; s.EventManager.OnNewPresence -= RegisterNewPresence; s.EventManager.OnRemovePresence -= DeRegisterPresence; - m_BakedTextureModule = null; m_scene = null; } - - public void RegionLoaded(Scene s) { m_scene.EventManager.OnRegisterCaps += RegisterCaps; m_scene.EventManager.OnNewPresence += RegisterNewPresence; m_scene.EventManager.OnRemovePresence += DeRegisterPresence; - } private void DeRegisterPresence(UUID agentId) { - ScenePresence presence = null; - if (m_scene.TryGetScenePresence(agentId, out presence)) - { - presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings; - } - } private void RegisterNewPresence(ScenePresence presence) { - presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings; - - } - - private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) - { - int maxCacheitemsLoop = cacheItems.Length; - if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES) - { - maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES; - m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES); - } - - m_BakedTextureModule = m_scene.RequestModuleInterface(); - if (cacheItems.Length > 0) - { -// m_log.Debug("[Cacheitems]: " + cacheItems.Length); -// for (int iter = 0; iter < maxCacheitemsLoop; iter++) -// { -// m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" + -// cacheItems[iter].TextureID); -// } - - ScenePresence p = null; - if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p)) - { - - WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems; - if (existingitems == null) - { - if (m_BakedTextureModule != null) - { - WearableCacheItem[] savedcache = null; - try - { - if (p.Appearance.WearableCacheItemsDirty) - { - savedcache = m_BakedTextureModule.Get(p.UUID); - p.Appearance.WearableCacheItems = savedcache; - p.Appearance.WearableCacheItemsDirty = false; - } - - } - /* - * The following Catch types DO NOT WORK with m_BakedTextureModule.Get - * it jumps to the General Packet Exception Handler if you don't catch Exception! - * - catch (System.Net.Sockets.SocketException) - { - cacheItems = null; - } - catch (WebException) - { - cacheItems = null; - } - catch (InvalidOperationException) - { - cacheItems = null; - } */ - catch (Exception) - { - // The service logs a sufficient error message. - } - - - if (savedcache != null) - existingitems = savedcache; - } - } - // Existing items null means it's a fully new appearance - if (existingitems == null) - { - - for (int i = 0; i < maxCacheitemsLoop; i++) - { - if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) - { - Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; - if (face == null) - { - textureEntry.CreateFace(cacheItems[i].TextureIndex); - textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = - AppearanceManager.DEFAULT_AVATAR_TEXTURE; - continue; - } - cacheItems[i].TextureID =face.TextureID; - if (m_scene.AssetService != null) - cacheItems[i].TextureAsset = - m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); - } - else - { - m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); - } - - - } - } - else - - - { - // for each uploaded baked texture - for (int i = 0; i < maxCacheitemsLoop; i++) - { - if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex) - { - Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex]; - if (face == null) - { - textureEntry.CreateFace(cacheItems[i].TextureIndex); - textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID = - AppearanceManager.DEFAULT_AVATAR_TEXTURE; - continue; - } - cacheItems[i].TextureID = - face.TextureID; - } - else - { - m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length); - } - } - - for (int i = 0; i < maxCacheitemsLoop; i++) - { - if (cacheItems[i].TextureAsset == null) - { - cacheItems[i].TextureAsset = - m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString()); - } - } - } - - - - p.Appearance.WearableCacheItems = cacheItems; - - - - if (m_BakedTextureModule != null) - { - m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems); - p.Appearance.WearableCacheItemsDirty = true; - - } - } - } } public void PostInitialise() { } - - public void Close() { } public string Name { get { return "UploadBakedTextureModule"; } } @@ -280,23 +120,26 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { - UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( - caps, m_scene.AssetService, m_persistBakedTextures); + //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); + if (m_URL == "localhost") + { + UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler( + caps, m_scene.AssetService); - - - caps.RegisterHandler( - "UploadBakedTexture", - new RestStreamHandler( - "POST", - "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, - avatarhandler.UploadBakedTexture, + caps.RegisterHandler( "UploadBakedTexture", - agentID.ToString())); - - - + new RestStreamHandler( + "POST", + "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, + avatarhandler.UploadBakedTexture, + "UploadBakedTexture", + agentID.ToString())); + } + else + { + caps.RegisterHandler("UploadBakedTexture", m_URL); + } } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 025ffea..8d4e561 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -34,9 +34,7 @@ using log4net; using Nini.Config; using Mono.Addins; using OpenMetaverse; -using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; @@ -45,6 +43,9 @@ using OpenSim.Framework.Capabilities; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OpenSim.Capabilities.Handlers; +using OpenSim.Framework.Monitoring; + +using OpenMetaverse.StructuredData; namespace OpenSim.Region.ClientStack.Linden { @@ -63,7 +64,7 @@ namespace OpenSim.Region.ClientStack.Linden public List folders; } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Control whether requests will be processed asynchronously. @@ -92,14 +93,16 @@ namespace OpenSim.Region.ClientStack.Linden private bool m_Enabled; private string m_fetchInventoryDescendents2Url; - private string m_webFetchInventoryDescendentsUrl; +// private string m_webFetchInventoryDescendentsUrl; private static FetchInvDescHandler m_webFetchHandler; private static Thread[] m_workerThreads = null; - private static DoubleQueue m_queue = - new DoubleQueue(); + private static OpenSim.Framework.BlockingQueue m_queue = + new OpenSim.Framework.BlockingQueue(); + + private static int m_NumberScenes = 0; #region ISharedRegionModule Members @@ -117,9 +120,10 @@ namespace OpenSim.Region.ClientStack.Linden return; m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); - m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); +// m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); - if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) +// if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) + if (m_fetchInventoryDescendents2Url != string.Empty) { m_Enabled = true; } @@ -143,17 +147,7 @@ namespace OpenSim.Region.ClientStack.Linden StatsManager.DeregisterStat(s_processedRequestsStat); StatsManager.DeregisterStat(s_queuedRequestsStat); - if (ProcessQueuedRequestsAsync) - { - if (m_workerThreads != null) - { - foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); - - m_workerThreads = null; - } - } - + m_NumberScenes--; Scene = null; } @@ -187,7 +181,7 @@ namespace OpenSim.Region.ClientStack.Linden "httpfetch", StatType.Pull, MeasuresOfInterest.AverageChangeOverTime, - stat => { stat.Value = m_queue.Count; }, + stat => { stat.Value = m_queue.Count(); }, StatVerbosity.Debug); StatsManager.RegisterStat(s_processedRequestsStat); @@ -201,6 +195,8 @@ namespace OpenSim.Region.ClientStack.Linden Scene.EventManager.OnRegisterCaps += RegisterCaps; + m_NumberScenes++; + int nworkers = 2; // was 2 if (ProcessQueuedRequestsAsync && m_workerThreads == null) { @@ -211,7 +207,7 @@ namespace OpenSim.Region.ClientStack.Linden m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, String.Format("InventoryWorkerThread{0}", i), ThreadPriority.Normal, - false, + true, true, null, int.MaxValue); @@ -223,7 +219,23 @@ namespace OpenSim.Region.ClientStack.Linden { } - public void Close() { } + public void Close() + { + if (!m_Enabled) + return; + + if (ProcessQueuedRequestsAsync) + { + if (m_NumberScenes <= 0 && m_workerThreads != null) + { + m_log.DebugFormat("[WebFetchInvDescModule] Closing"); + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + + m_workerThreads = null; + } + } + } public string Name { get { return "WebFetchInvDescModule"; } } @@ -312,16 +324,17 @@ namespace OpenSim.Region.ClientStack.Linden { if (!reqinfo.folders.Contains(folderID)) { - //TODO: Port COF handling from Avination + if (sp.COF != UUID.Zero && sp.COF == folderID) + highPriority = true; reqinfo.folders.Add(folderID); } } } if (highPriority) - m_queue.EnqueueHigh(reqinfo); + m_queue.PriorityEnqueue(reqinfo); else - m_queue.EnqueueLow(reqinfo); + m_queue.Enqueue(reqinfo); }; NoEvents = (x, y) => @@ -347,6 +360,9 @@ namespace OpenSim.Region.ClientStack.Linden public void Process(aPollRequest requestinfo) { + if(m_module == null || m_module.Scene == null || m_module.Scene.ShuttingDown) + return; + UUID requestID = requestinfo.reqID; Hashtable response = new Hashtable(); @@ -365,7 +381,8 @@ namespace OpenSim.Region.ClientStack.Linden m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); responses[requestID] = response; } - + requestinfo.folders.Clear(); + requestinfo.request.Clear(); WebFetchInvDescModule.ProcessedRequestsCount++; } } @@ -422,31 +439,25 @@ namespace OpenSim.Region.ClientStack.Linden // } // } - private void DoInventoryRequests() + private static void DoInventoryRequests() { while (true) { + aPollRequest poolreq = m_queue.Dequeue(4500); Watchdog.UpdateThread(); - WaitProcessQueuedInventoryRequest(); - } - } - - public void WaitProcessQueuedInventoryRequest() - { - aPollRequest poolreq = m_queue.Dequeue(); - - if (poolreq != null && poolreq.thepoll != null) - { - try - { - poolreq.thepoll.Process(poolreq); - } - catch (Exception e) + if (poolreq != null && poolreq.thepoll != null) { - m_log.ErrorFormat( - "[INVENTORY]: Failed to process queued inventory request {0} for {1} in {2}. Exception {3}", - poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", Scene.Name, e); + try + { + poolreq.thepoll.Process(poolreq); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[INVENTORY]: Failed to process queued inventory request {0} for {1}. Exception {2}", + poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name : "unknown", e); + } } } } -- cgit v1.1