aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/Caps
diff options
context:
space:
mode:
authorMelanie2012-09-16 04:21:18 +0100
committerMelanie2012-09-16 04:21:18 +0100
commit66bf1376b5f9a0c9b5a3bdb58ac7eca09b6389ba (patch)
treef5ce10e917fa3ab24ed98cc10ca5a87057da71a9 /OpenSim/Region/ClientStack/Linden/Caps
parentMerge branch 'master' into careminster (diff)
parentRevamp the HTTP textures handler to allow a maximum of four fetches (diff)
downloadopensim-SC-66bf1376b5f9a0c9b5a3bdb58ac7eca09b6389ba.zip
opensim-SC-66bf1376b5f9a0c9b5a3bdb58ac7eca09b6389ba.tar.gz
opensim-SC-66bf1376b5f9a0c9b5a3bdb58ac7eca09b6389ba.tar.bz2
opensim-SC-66bf1376b5f9a0c9b5a3bdb58ac7eca09b6389ba.tar.xz
Merge branch 'avination' into careminster
Conflicts: OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs111
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs223
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs296
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs198
4 files changed, 400 insertions, 428 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 88c4d7f..580c005 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Timers;
29using System.Collections; 30using System.Collections;
30using System.Collections.Generic; 31using System.Collections.Generic;
31using System.IO; 32using System.IO;
@@ -60,7 +61,7 @@ namespace OpenSim.Region.ClientStack.Linden
60 61
61 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors); 62 public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
62 63
63 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item); 64 public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
64 65
65 public delegate void NewAsset(AssetBase asset); 66 public delegate void NewAsset(AssetBase asset);
66 67
@@ -386,6 +387,37 @@ namespace OpenSim.Region.ClientStack.Linden
386 return UUID.Zero; 387 return UUID.Zero;
387 } 388 }
388 389
390 private delegate void UploadWithCostCompleteDelegate(string assetName,
391 string assetDescription, UUID assetID, UUID inventoryItem,
392 UUID parentFolder, byte[] data, string inventoryType,
393 string assetType, uint cost);
394
395 private class AssetUploaderWithCost : AssetUploader
396 {
397 private uint m_cost;
398
399 public event UploadWithCostCompleteDelegate OnUpLoad;
400
401 public AssetUploaderWithCost(string assetName, string description, UUID assetID,
402 UUID inventoryItem, UUID parentFolderID, string invType, string assetType,
403 string path, IHttpServer httpServer, bool dumpAssetsToFile, uint cost) :
404 base(assetName, description, assetID, inventoryItem, parentFolderID,
405 invType, assetType, path, httpServer, dumpAssetsToFile)
406 {
407 m_cost = cost;
408
409 base.OnUpLoad += UploadCompleteHandler;
410 }
411
412 private void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
413 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
414 string assetType)
415 {
416 OnUpLoad(assetName, assetDescription, assetID, inventoryItem, parentFolder,
417 data, inventoryType, assetType, m_cost);
418 }
419 }
420
389 /// <summary> 421 /// <summary>
390 /// 422 ///
391 /// </summary> 423 /// </summary>
@@ -396,8 +428,11 @@ namespace OpenSim.Region.ClientStack.Linden
396 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString()); 428 //m_log.Debug("[CAPS]: NewAgentInventoryRequest Request is: " + llsdRequest.ToString());
397 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type); 429 //m_log.Debug("asset upload request via CAPS" + llsdRequest.inventory_type + " , " + llsdRequest.asset_type);
398 430
431 uint cost = 0;
432
399 if (llsdRequest.asset_type == "texture" || 433 if (llsdRequest.asset_type == "texture" ||
400 llsdRequest.asset_type == "animation" || 434 llsdRequest.asset_type == "animation" ||
435 llsdRequest.asset_type == "mesh" ||
401 llsdRequest.asset_type == "sound") 436 llsdRequest.asset_type == "sound")
402 { 437 {
403 ScenePresence avatar = null; 438 ScenePresence avatar = null;
@@ -428,7 +463,33 @@ namespace OpenSim.Region.ClientStack.Linden
428 463
429 if (mm != null) 464 if (mm != null)
430 { 465 {
431 if (!mm.UploadCovered(client.AgentId, mm.UploadCharge)) 466 // XPTO: The cost should be calculated about here
467
468 if (llsdRequest.asset_type == "mesh")
469 {
470 cost += 20; // Constant for now to test showing a price
471
472 if (llsdRequest.asset_resources == null)
473 {
474 client.SendAgentAlertMessage("Unable to upload asset. missing information.", false);
475
476 LLSDAssetUploadResponse errorResponse = new LLSDAssetUploadResponse();
477 errorResponse.uploader = "";
478 errorResponse.state = "error";
479 return errorResponse;
480 }
481
482 uint textures_cost = (uint)llsdRequest.asset_resources.texture_list.Array.Count;
483 textures_cost *= (uint)mm.UploadCharge;
484
485 cost += textures_cost;
486 }
487 else
488 {
489 cost = (uint)mm.UploadCharge;
490 }
491
492 if (!mm.UploadCovered(client.AgentId, (int)cost))
432 { 493 {
433 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); 494 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
434 495
@@ -449,9 +510,9 @@ namespace OpenSim.Region.ClientStack.Linden
449 UUID parentFolder = llsdRequest.folder_id; 510 UUID parentFolder = llsdRequest.folder_id;
450 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 511 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
451 512
452 AssetUploader uploader = 513 AssetUploaderWithCost uploader =
453 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, 514 new AssetUploaderWithCost(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
454 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); 515 llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile, cost);
455 516
456 m_HostCapsObj.HttpListener.AddStreamHandler( 517 m_HostCapsObj.HttpListener.AddStreamHandler(
457 new BinaryStreamHandler( 518 new BinaryStreamHandler(
@@ -469,11 +530,31 @@ namespace OpenSim.Region.ClientStack.Linden
469 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase + 530 string uploaderURL = protocol + m_HostCapsObj.HostName + ":" + m_HostCapsObj.Port.ToString() + capsBase +
470 uploaderPath; 531 uploaderPath;
471 532
533
472 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse(); 534 LLSDAssetUploadResponse uploadResponse = new LLSDAssetUploadResponse();
473 uploadResponse.uploader = uploaderURL; 535 uploadResponse.uploader = uploaderURL;
474 uploadResponse.state = "upload"; 536 uploadResponse.state = "upload";
537 uploadResponse.upload_price = (int)cost;
538
539 // use fake values for now
540 if (llsdRequest.asset_type == "mesh")
541 {
542 uploadResponse.data = new LLSDAssetUploadResponseData();
543 uploadResponse.data.model_streaming_cost = 1.0;
544 uploadResponse.data.simulation_cost = 1.5;
545
546 uploadResponse.data.physics_cost = 2.0;
547 uploadResponse.data.resource_cost = 3.0;
548 uploadResponse.data.upload_price_breakdown.mesh_instance = 1;
549 uploadResponse.data.upload_price_breakdown.mesh_physics = 2;
550 uploadResponse.data.upload_price_breakdown.mesh_streaming = 3;
551 uploadResponse.data.upload_price_breakdown.texture = 5;
552 uploadResponse.data.upload_price_breakdown.model = 4;
553 }
554
475 uploader.OnUpLoad += UploadCompleteHandler; 555 uploader.OnUpLoad += UploadCompleteHandler;
476 return uploadResponse; 556 return uploadResponse;
557
477 } 558 }
478 559
479 /// <summary> 560 /// <summary>
@@ -484,7 +565,7 @@ namespace OpenSim.Region.ClientStack.Linden
484 /// <param name="data"></param> 565 /// <param name="data"></param>
485 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID, 566 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
486 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType, 567 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
487 string assetType) 568 string assetType, uint cost)
488 { 569 {
489 m_log.DebugFormat( 570 m_log.DebugFormat(
490 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}", 571 "[BUNCH OF CAPS]: Uploaded asset {0} for inventory item {1}, inv type {2}, asset type {3}",
@@ -703,7 +784,7 @@ namespace OpenSim.Region.ClientStack.Linden
703 784
704 if (AddNewInventoryItem != null) 785 if (AddNewInventoryItem != null)
705 { 786 {
706 AddNewInventoryItem(m_HostCapsObj.AgentID, item); 787 AddNewInventoryItem(m_HostCapsObj.AgentID, item, cost);
707 } 788 }
708 } 789 }
709 790
@@ -1014,6 +1095,9 @@ namespace OpenSim.Region.ClientStack.Linden
1014 1095
1015 public class AssetUploader 1096 public class AssetUploader
1016 { 1097 {
1098 private static readonly ILog m_log =
1099 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1100
1017 public event UpLoadedAsset OnUpLoad; 1101 public event UpLoadedAsset OnUpLoad;
1018 private UpLoadedAsset handlerUpLoad = null; 1102 private UpLoadedAsset handlerUpLoad = null;
1019 1103
@@ -1028,6 +1112,7 @@ namespace OpenSim.Region.ClientStack.Linden
1028 1112
1029 private string m_invType = String.Empty; 1113 private string m_invType = String.Empty;
1030 private string m_assetType = String.Empty; 1114 private string m_assetType = String.Empty;
1115 private Timer m_timeoutTimer = new Timer();
1031 1116
1032 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem, 1117 public AssetUploader(string assetName, string description, UUID assetID, UUID inventoryItem,
1033 UUID parentFolderID, string invType, string assetType, string path, 1118 UUID parentFolderID, string invType, string assetType, string path,
@@ -1043,6 +1128,11 @@ namespace OpenSim.Region.ClientStack.Linden
1043 m_assetType = assetType; 1128 m_assetType = assetType;
1044 m_invType = invType; 1129 m_invType = invType;
1045 m_dumpAssetsToFile = dumpAssetsToFile; 1130 m_dumpAssetsToFile = dumpAssetsToFile;
1131
1132 m_timeoutTimer.Elapsed += TimedOut;
1133 m_timeoutTimer.Interval = 120000;
1134 m_timeoutTimer.AutoReset = false;
1135 m_timeoutTimer.Start();
1046 } 1136 }
1047 1137
1048 /// <summary> 1138 /// <summary>
@@ -1064,6 +1154,7 @@ namespace OpenSim.Region.ClientStack.Linden
1064 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete); 1154 res = LLSDHelpers.SerialiseLLSDReply(uploadComplete);
1065 1155
1066 httpListener.RemoveStreamHandler("POST", uploaderPath); 1156 httpListener.RemoveStreamHandler("POST", uploaderPath);
1157 m_timeoutTimer.Stop();
1067 1158
1068 // TODO: probably make this a better set of extensions here 1159 // TODO: probably make this a better set of extensions here
1069 string extension = ".jp2"; 1160 string extension = ".jp2";
@@ -1085,6 +1176,12 @@ namespace OpenSim.Region.ClientStack.Linden
1085 return res; 1176 return res;
1086 } 1177 }
1087 1178
1179 private void TimedOut(object sender, ElapsedEventArgs args)
1180 {
1181 m_log.InfoFormat("[CAPS]: Removing URL and handler for timed out mesh upload");
1182 httpListener.RemoveStreamHandler("POST", uploaderPath);
1183 }
1184
1088 ///Left this in and commented in case there are unforseen issues 1185 ///Left this in and commented in case there are unforseen issues
1089 //private void SaveAssetToFile(string filename, byte[] data) 1186 //private void SaveAssetToFile(string filename, byte[] data)
1090 //{ 1187 //{
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 5ae9cc3..5b125ea 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -27,18 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 31using System.Reflection;
34using System.IO; 32using System.Threading;
35using System.Web;
36using log4net; 33using log4net;
37using Nini.Config; 34using Nini.Config;
38using Mono.Addins; 35using Mono.Addins;
39using OpenMetaverse; 36using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework; 37using OpenSim.Framework;
43using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
@@ -47,64 +42,73 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
50 46
51namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
52{ 48{
53 49
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] 50 /// <summary>
51 /// This module implements both WebFetchTextureDescendents and FetchTextureDescendents2 capabilities.
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 54 public class GetTextureModule : INonSharedRegionModule
56 { 55 {
57// private static readonly ILog m_log = 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57
59
60 private Scene m_scene; 58 private Scene m_scene;
61 private IAssetService m_assetService;
62 59
63 private bool m_Enabled = false; 60 private static GetTextureHandler m_getTextureHandler;
61
62 private IAssetService m_assetService = null;
64 63
65 // TODO: Change this to a config option 64 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
66 const string REDIRECT_URL = null; 65 private static Thread[] m_workerThreads = null;
67 66
68 private string m_URL; 67 private static OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs> m_queue =
68 new OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs>();
69 69
70 #region ISharedRegionModule Members 70 #region ISharedRegionModule Members
71 71
72 public void Initialise(IConfigSource source) 72 public void Initialise(IConfigSource source)
73 { 73 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 } 74 }
83 75
84 public void AddRegion(Scene s) 76 public void AddRegion(Scene s)
85 { 77 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 78 m_scene = s;
79 m_assetService = s.AssetService;
90 } 80 }
91 81
92 public void RemoveRegion(Scene s) 82 public void RemoveRegion(Scene s)
93 { 83 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 84 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
85 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
98 m_scene = null; 86 m_scene = null;
99 } 87 }
100 88
101 public void RegionLoaded(Scene s) 89 public void RegionLoaded(Scene s)
102 { 90 {
103 if (!m_Enabled) 91 // We'll reuse the same handler for all requests.
104 return; 92 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 93
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 94 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
95 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
96
97 if (m_workerThreads == null)
98 {
99 m_workerThreads = new Thread[4];
100
101 for (uint i = 0; i < 4; i++)
102 {
103 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
104 String.Format("TextureWorkerThread{0}", i),
105 ThreadPriority.Normal,
106 false,
107 true,
108 null,
109 int.MaxValue);
110 }
111 }
108 } 112 }
109 113
110 public void PostInitialise() 114 public void PostInitialise()
@@ -122,24 +126,155 @@ namespace OpenSim.Region.ClientStack.Linden
122 126
123 #endregion 127 #endregion
124 128
125 public void RegisterCaps(UUID agentID, Caps caps) 129 ~GetTextureModule()
130 {
131 foreach (Thread t in m_workerThreads)
132 t.Abort();
133 }
134
135 private class PollServiceTextureEventArgs : PollServiceEventArgs
126 { 136 {
127 UUID capID = UUID.Random(); 137 private List<Hashtable> requests =
138 new List<Hashtable>();
139 private Dictionary<UUID, Hashtable> responses =
140 new Dictionary<UUID, Hashtable>();
141
142 private Scene m_scene;
128 143
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 144 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
130 if (m_URL == "localhost") 145 base(null, null, null, null, pId, 30000)
131 { 146 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 147 m_scene = scene;
133 caps.RegisterHandler( 148
134 "GetTexture", 149 HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 150 GetEvents = (x, y, s) =>
151 {
152 try
153 {
154 return this.responses[x];
155 }
156 finally
157 {
158 responses.Remove(x);
159 }
160 };
161
162 Request = (x, y) =>
163 {
164 y["RequestID"] = x.ToString();
165 lock (this.requests)
166 this.requests.Add(y);
167
168 m_queue.Enqueue(this);
169 };
170
171 NoEvents = (x, y) =>
172 {
173 lock (this.requests)
174 {
175 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
176 requests.Remove(request);
177 }
178
179 Hashtable response = new Hashtable();
180
181 response["int_response_code"] = 500;
182 response["str_response_string"] = "Script timeout";
183 response["content_type"] = "text/plain";
184 response["keepalive"] = false;
185 response["reusecontext"] = false;
186
187 return response;
188 };
136 } 189 }
137 else 190
191 public void Process()
138 { 192 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 193 Hashtable response;
140 caps.RegisterHandler("GetTexture", m_URL); 194 Hashtable request = null;
195
196 try
197 {
198 lock (this.requests)
199 {
200 request = requests[0];
201 requests.RemoveAt(0);
202 }
203 }
204 catch
205 {
206 return;
207 }
208
209 UUID requestID = new UUID(request["RequestID"].ToString());
210
211 // If the avatar is gone, don't bother to get the texture
212 if (m_scene.GetScenePresence(Id) == null)
213 {
214 response = new Hashtable();
215
216 response["int_response_code"] = 500;
217 response["str_response_string"] = "Script timeout";
218 response["content_type"] = "text/plain";
219 response["keepalive"] = false;
220 response["reusecontext"] = false;
221
222 responses[requestID] = response;
223 return;
224 }
225
226 response = m_getTextureHandler.Handle(request);
227
228 responses[requestID] = response;
229 }
230 }
231
232 private void RegisterCaps(UUID agentID, Caps caps)
233 {
234 string capUrl = "/CAPS/" + UUID.Random() + "/";
235
236 // Register this as a poll service
237 // absurd large timeout to tune later to make a bit less than viewer
238 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
239
240 args.Type = PollServiceEventArgs.EventType.Texture;
241 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
242
243 string hostName = m_scene.RegionInfo.ExternalHostName;
244 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
245 string protocol = "http";
246
247 if (MainServer.Instance.UseSSL)
248 {
249 hostName = MainServer.Instance.SSLCommonName;
250 port = MainServer.Instance.SSLPort;
251 protocol = "https";
141 } 252 }
253 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
254
255 m_capsDict[agentID] = capUrl;
142 } 256 }
143 257
258 private void DeregisterCaps(UUID agentID, Caps caps)
259 {
260 string capUrl;
261
262 if (m_capsDict.TryGetValue(agentID, out capUrl))
263 {
264 MainServer.Instance.RemoveHTTPHandler("", capUrl);
265 m_capsDict.Remove(agentID);
266 }
267 }
268
269 private void DoTextureRequests()
270 {
271 while (true)
272 {
273 PollServiceTextureEventArgs args = m_queue.Dequeue();
274
275 args.Process();
276 }
277 }
144 } 278 }
279
145} 280}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
deleted file mode 100644
index 52c4f44..0000000
--- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs
+++ /dev/null
@@ -1,296 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using Mono.Addins;
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using OpenSim.Framework;
40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Services.Interfaces;
45using Caps = OpenSim.Framework.Capabilities.Caps;
46using OpenSim.Framework.Capabilities;
47
48namespace OpenSim.Region.ClientStack.Linden
49{
50 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
51 public class NewFileAgentInventoryVariablePriceModule : INonSharedRegionModule
52 {
53// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 private Scene m_scene;
56// private IAssetService m_assetService;
57 private bool m_dumpAssetsToFile = false;
58 private bool m_enabled = true;
59 private int m_levelUpload = 0;
60
61 #region IRegionModuleBase Members
62
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 IConfig meshConfig = source.Configs["Mesh"];
72 if (meshConfig == null)
73 return;
74
75 m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
76 m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
77 }
78
79 public void AddRegion(Scene pScene)
80 {
81 m_scene = pScene;
82 }
83
84 public void RemoveRegion(Scene scene)
85 {
86
87 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
88 m_scene = null;
89 }
90
91 public void RegionLoaded(Scene scene)
92 {
93
94// m_assetService = m_scene.RequestModuleInterface<IAssetService>();
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 }
97
98 #endregion
99
100
101 #region IRegionModule Members
102
103
104
105 public void Close() { }
106
107 public string Name { get { return "NewFileAgentInventoryVariablePriceModule"; } }
108
109
110 public void RegisterCaps(UUID agentID, Caps caps)
111 {
112 if(!m_enabled)
113 return;
114
115 UUID capID = UUID.Random();
116
117// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
118 caps.RegisterHandler(
119 "NewFileAgentInventoryVariablePrice",
120 new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
121 "POST",
122 "/CAPS/" + capID.ToString(),
123 req => NewAgentInventoryRequest(req, agentID),
124 "NewFileAgentInventoryVariablePrice",
125 agentID.ToString()));
126 }
127
128 #endregion
129
130 public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
131 {
132 //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
133 // you need to be aware of this
134
135 //if (llsdRequest.asset_type == "texture" ||
136 // llsdRequest.asset_type == "animation" ||
137 // llsdRequest.asset_type == "sound")
138 // {
139 // check user level
140
141 ScenePresence avatar = null;
142 IClientAPI client = null;
143 m_scene.TryGetScenePresence(agentID, out avatar);
144
145 if (avatar != null)
146 {
147 client = avatar.ControllingClient;
148
149 if (avatar.UserLevel < m_levelUpload)
150 {
151 if (client != null)
152 client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
153
154 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
155 errorResponse.rsvp = "";
156 errorResponse.state = "error";
157 return errorResponse;
158 }
159 }
160
161 // check funds
162 IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
163
164 if (mm != null)
165 {
166 if (!mm.UploadCovered(agentID, mm.UploadCharge))
167 {
168 if (client != null)
169 client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
170
171 LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
172 errorResponse.rsvp = "";
173 errorResponse.state = "error";
174 return errorResponse;
175 }
176 }
177
178 // }
179
180 string assetName = llsdRequest.name;
181 string assetDes = llsdRequest.description;
182 string capsBase = "/CAPS/NewFileAgentInventoryVariablePrice/";
183 UUID newAsset = UUID.Random();
184 UUID newInvItem = UUID.Random();
185 UUID parentFolder = llsdRequest.folder_id;
186 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000") + "/";
187
188 AssetUploader uploader =
189 new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
190 llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
191
192 MainServer.Instance.AddStreamHandler(
193 new BinaryStreamHandler(
194 "POST",
195 capsBase + uploaderPath,
196 uploader.uploaderCaps,
197 "NewFileAgentInventoryVariablePrice",
198 agentID.ToString()));
199
200 string protocol = "http://";
201
202 if (MainServer.Instance.UseSSL)
203 protocol = "https://";
204
205 string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
206 uploaderPath;
207
208
209 LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
210
211 uploadResponse.rsvp = uploaderURL;
212 uploadResponse.state = "upload";
213 uploadResponse.resource_cost = 0;
214 uploadResponse.upload_price = 0;
215
216 uploader.OnUpLoad += //UploadCompleteHandler;
217
218 delegate(
219 string passetName, string passetDescription, UUID passetID,
220 UUID pinventoryItem, UUID pparentFolder, byte[] pdata, string pinventoryType,
221 string passetType)
222 {
223 UploadCompleteHandler(passetName, passetDescription, passetID,
224 pinventoryItem, pparentFolder, pdata, pinventoryType,
225 passetType,agentID);
226 };
227
228 return uploadResponse;
229 }
230
231 public void UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
232 UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
233 string assetType,UUID AgentID)
234 {
235// m_log.DebugFormat(
236// "[NEW FILE AGENT INVENTORY VARIABLE PRICE MODULE]: Upload complete for {0}", inventoryItem);
237
238 sbyte assType = 0;
239 sbyte inType = 0;
240
241 if (inventoryType == "sound")
242 {
243 inType = 1;
244 assType = 1;
245 }
246 else if (inventoryType == "animation")
247 {
248 inType = 19;
249 assType = 20;
250 }
251 else if (inventoryType == "wearable")
252 {
253 inType = 18;
254 switch (assetType)
255 {
256 case "bodypart":
257 assType = 13;
258 break;
259 case "clothing":
260 assType = 5;
261 break;
262 }
263 }
264 else if (inventoryType == "mesh")
265 {
266 inType = (sbyte)InventoryType.Mesh;
267 assType = (sbyte)AssetType.Mesh;
268 }
269
270 AssetBase asset;
271 asset = new AssetBase(assetID, assetName, assType, AgentID.ToString());
272 asset.Data = data;
273
274 if (m_scene.AssetService != null)
275 m_scene.AssetService.Store(asset);
276
277 InventoryItemBase item = new InventoryItemBase();
278 item.Owner = AgentID;
279 item.CreatorId = AgentID.ToString();
280 item.ID = inventoryItem;
281 item.AssetID = asset.FullID;
282 item.Description = assetDescription;
283 item.Name = assetName;
284 item.AssetType = assType;
285 item.InvType = inType;
286 item.Folder = parentFolder;
287 item.CurrentPermissions
288 = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
289 item.BasePermissions = (uint)PermissionMask.All;
290 item.EveryOnePermissions = 0;
291 item.NextPermissions = (uint)PermissionMask.All;
292 item.CreationDate = Util.UnixTimeSinceEpoch();
293 m_scene.AddInventoryItem(item);
294 }
295 }
296}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index e996fe8..4908c2c 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -42,6 +42,7 @@ using OpenSim.Region.Framework.Scenes;
42using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
43using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
44using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
45 46
46namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
47{ 48{
@@ -58,13 +59,13 @@ namespace OpenSim.Region.ClientStack.Linden
58 private IInventoryService m_InventoryService; 59 private IInventoryService m_InventoryService;
59 private ILibraryService m_LibraryService; 60 private ILibraryService m_LibraryService;
60 61
61 private WebFetchInvDescHandler m_webFetchHandler; 62 private static WebFetchInvDescHandler m_webFetchHandler;
62
63 private object m_lock = new object();
64 63
65 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); 64 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
66 private Dictionary<UUID, Hashtable> m_requests = new Dictionary<UUID, Hashtable>(); 65 private static Thread[] m_workerThreads = null;
67 bool m_busy = false; 66
67 private static OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs> m_queue =
68 new OpenMetaverse.BlockingQueue<PollServiceInventoryEventArgs>();
68 69
69 #region ISharedRegionModule Members 70 #region ISharedRegionModule Members
70 71
@@ -94,6 +95,22 @@ namespace OpenSim.Region.ClientStack.Linden
94 95
95 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 96 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; 97 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
98
99 if (m_workerThreads == null)
100 {
101 m_workerThreads = new Thread[2];
102
103 for (uint i = 0; i < 2; i++)
104 {
105 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
106 String.Format("InventoryWorkerThread{0}", i),
107 ThreadPriority.Normal,
108 false,
109 true,
110 null,
111 int.MaxValue);
112 }
113 }
97 } 114 }
98 115
99 public void PostInitialise() 116 public void PostInitialise()
@@ -111,13 +128,103 @@ namespace OpenSim.Region.ClientStack.Linden
111 128
112 #endregion 129 #endregion
113 130
131 ~WebFetchInvDescModule()
132 {
133 foreach (Thread t in m_workerThreads)
134 t.Abort();
135 }
136
137 private class PollServiceInventoryEventArgs : PollServiceEventArgs
138 {
139 private List<Hashtable> requests =
140 new List<Hashtable>();
141 private Dictionary<UUID, Hashtable> responses =
142 new Dictionary<UUID, Hashtable>();
143
144 public PollServiceInventoryEventArgs(UUID pId) :
145 base(null, null, null, null, pId, 30000)
146 {
147 HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
148 GetEvents = (x, y, s) =>
149 {
150 try
151 {
152 return this.responses[x];
153 }
154 finally
155 {
156 responses.Remove(x);
157 }
158 };
159
160 Request = (x, y) =>
161 {
162 y["RequestID"] = x.ToString();
163 lock (this.requests)
164 this.requests.Add(y);
165
166 m_queue.Enqueue(this);
167 };
168
169 NoEvents = (x, y) =>
170 {
171 lock (this.requests)
172 {
173 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
174 requests.Remove(request);
175 }
176
177 Hashtable response = new Hashtable();
178
179 response["int_response_code"] = 500;
180 response["str_response_string"] = "Script timeout";
181 response["content_type"] = "text/plain";
182 response["keepalive"] = false;
183 response["reusecontext"] = false;
184
185 return response;
186 };
187 }
188
189 public void Process()
190 {
191 Hashtable request = null;
192
193 try
194 {
195 lock (this.requests)
196 {
197 request = requests[0];
198 requests.RemoveAt(0);
199 }
200 }
201 catch
202 {
203 return;
204 }
205
206 UUID requestID = new UUID(request["RequestID"].ToString());
207
208 Hashtable response = new Hashtable();
209
210 response["int_response_code"] = 200;
211 response["content_type"] = "text/plain";
212 response["keepalive"] = false;
213 response["reusecontext"] = false;
214
215 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(request["body"].ToString(), String.Empty, String.Empty, null, null);
216
217 responses[requestID] = response;
218 }
219 }
220
114 private void RegisterCaps(UUID agentID, Caps caps) 221 private void RegisterCaps(UUID agentID, Caps caps)
115 { 222 {
116 string capUrl = "/CAPS/" + UUID.Random() + "/"; 223 string capUrl = "/CAPS/" + UUID.Random() + "/";
117 224
118 // Register this as a poll service 225 // Register this as a poll service
119 // absurd large timeout to tune later to make a bit less than viewer 226 // absurd large timeout to tune later to make a bit less than viewer
120 PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, agentID, 300000); 227 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(agentID);
121 228
122 args.Type = PollServiceEventArgs.EventType.Inventory; 229 args.Type = PollServiceEventArgs.EventType.Inventory;
123 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); 230 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
@@ -135,8 +242,6 @@ namespace OpenSim.Region.ClientStack.Linden
135 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); 242 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
136 243
137 m_capsDict[agentID] = capUrl; 244 m_capsDict[agentID] = capUrl;
138
139 m_busy = false;
140 } 245 }
141 246
142 private void DeregisterCaps(UUID agentID, Caps caps) 247 private void DeregisterCaps(UUID agentID, Caps caps)
@@ -150,83 +255,14 @@ namespace OpenSim.Region.ClientStack.Linden
150 } 255 }
151 } 256 }
152 257
153 public void HttpRequestHandler(UUID requestID, Hashtable request) 258 private void DoInventoryRequests()
154 { 259 {
155// m_log.DebugFormat("[FETCH2]: Received request {0}", requestID); 260 while (true)
156 lock(m_lock)
157 m_requests[requestID] = request;
158 }
159
160 private bool HasEvents(UUID requestID, UUID sessionID)
161 {
162 lock (m_lock)
163 { 261 {
164 return !m_busy; 262 PollServiceInventoryEventArgs args = m_queue.Dequeue();
165 }
166 }
167
168 private Hashtable NoEvents(UUID requestID, UUID sessionID)
169 {
170 lock(m_lock)
171 m_requests.Remove(requestID);
172
173 Hashtable response = new Hashtable();
174
175 response["int_response_code"] = 500;
176 response["str_response_string"] = "Script timeout";
177 response["content_type"] = "text/plain";
178 response["keepalive"] = false;
179 response["reusecontext"] = false;
180
181 lock (m_lock)
182 m_busy = false;
183 263
184 return response; 264 args.Process();
185 }
186
187 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
188 {
189 lock (m_lock)
190 m_busy = true;
191
192 Hashtable response = new Hashtable();
193
194 response["int_response_code"] = 500;
195 response["str_response_string"] = "Internal error";
196 response["content_type"] = "text/plain";
197 response["keepalive"] = false;
198 response["reusecontext"] = false;
199
200 try
201 {
202
203 Hashtable requestHash;
204 lock (m_lock)
205 {
206 if (!m_requests.TryGetValue(requestID, out requestHash))
207 {
208 m_busy = false;
209 response["str_response_string"] = "Invalid request";
210 return response;
211 }
212 m_requests.Remove(requestID);
213 }
214
215// m_log.DebugFormat("[FETCH2]: Processed request {0}", requestID);
216
217 string reply = m_webFetchHandler.FetchInventoryDescendentsRequest(requestHash["body"].ToString(), String.Empty, String.Empty, null, null);
218
219
220 response["int_response_code"] = 200;
221 response["str_response_string"] = reply;
222 }
223 finally
224 {
225 lock (m_lock)
226 m_busy = false;
227 } 265 }
228
229 return response;
230 } 266 }
231 } 267 }
232} 268}