diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 267 |
1 files changed, 215 insertions, 52 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 6890f4a..707cc93 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -27,18 +27,25 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
31 | using log4net; | 33 | using log4net; |
32 | using Nini.Config; | 34 | using Nini.Config; |
33 | using Mono.Addins; | 35 | using Mono.Addins; |
34 | using OpenMetaverse; | 36 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | 39 | using OpenSim.Framework.Servers.HttpServer; |
37 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
42 | using OpenSim.Framework.Capabilities; | ||
39 | using OpenSim.Services.Interfaces; | 43 | using OpenSim.Services.Interfaces; |
40 | using Caps = OpenSim.Framework.Capabilities.Caps; | 44 | using Caps = OpenSim.Framework.Capabilities.Caps; |
41 | using OpenSim.Capabilities.Handlers; | 45 | using OpenSim.Capabilities.Handlers; |
46 | using OpenSim.Framework.Monitoring; | ||
47 | using OpenMetaverse; | ||
48 | using OpenMetaverse.StructuredData; | ||
42 | 49 | ||
43 | namespace OpenSim.Region.ClientStack.Linden | 50 | namespace OpenSim.Region.ClientStack.Linden |
44 | { | 51 | { |
@@ -48,67 +55,74 @@ namespace OpenSim.Region.ClientStack.Linden | |||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] | 55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] |
49 | public class WebFetchInvDescModule : INonSharedRegionModule | 56 | public class WebFetchInvDescModule : INonSharedRegionModule |
50 | { | 57 | { |
51 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 58 | class aPollRequest |
59 | { | ||
60 | public PollServiceInventoryEventArgs thepoll; | ||
61 | public UUID reqID; | ||
62 | public Hashtable request; | ||
63 | public ScenePresence presence; | ||
64 | public List<UUID> folders; | ||
65 | } | ||
66 | |||
67 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | 68 | ||
53 | private Scene m_scene; | 69 | private Scene m_scene; |
54 | 70 | ||
55 | private IInventoryService m_InventoryService; | 71 | private IInventoryService m_InventoryService; |
56 | private ILibraryService m_LibraryService; | 72 | private ILibraryService m_LibraryService; |
57 | 73 | ||
58 | private bool m_Enabled; | 74 | private static WebFetchInvDescHandler m_webFetchHandler; |
59 | 75 | ||
60 | private string m_fetchInventoryDescendents2Url; | 76 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); |
61 | private string m_webFetchInventoryDescendentsUrl; | 77 | private static Thread[] m_workerThreads = null; |
62 | 78 | ||
63 | private WebFetchInvDescHandler m_webFetchHandler; | 79 | private static DoubleQueue<aPollRequest> m_queue = |
80 | new DoubleQueue<aPollRequest>(); | ||
64 | 81 | ||
65 | #region ISharedRegionModule Members | 82 | #region ISharedRegionModule Members |
66 | 83 | ||
67 | public void Initialise(IConfigSource source) | 84 | public void Initialise(IConfigSource source) |
68 | { | 85 | { |
69 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
70 | if (config == null) | ||
71 | return; | ||
72 | |||
73 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); | ||
74 | m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | ||
75 | |||
76 | if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) | ||
77 | { | ||
78 | m_Enabled = true; | ||
79 | } | ||
80 | } | 86 | } |
81 | 87 | ||
82 | public void AddRegion(Scene s) | 88 | public void AddRegion(Scene s) |
83 | { | 89 | { |
84 | if (!m_Enabled) | ||
85 | return; | ||
86 | |||
87 | m_scene = s; | 90 | m_scene = s; |
88 | } | 91 | } |
89 | 92 | ||
90 | public void RemoveRegion(Scene s) | 93 | public void RemoveRegion(Scene s) |
91 | { | 94 | { |
92 | if (!m_Enabled) | ||
93 | return; | ||
94 | |||
95 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 95 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
96 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | ||
96 | m_scene = null; | 97 | m_scene = null; |
97 | } | 98 | } |
98 | 99 | ||
99 | public void RegionLoaded(Scene s) | 100 | public void RegionLoaded(Scene s) |
100 | { | 101 | { |
101 | if (!m_Enabled) | ||
102 | return; | ||
103 | |||
104 | m_InventoryService = m_scene.InventoryService; | 102 | m_InventoryService = m_scene.InventoryService; |
105 | m_LibraryService = m_scene.LibraryService; | 103 | m_LibraryService = m_scene.LibraryService; |
106 | 104 | ||
107 | // We'll reuse the same handler for all requests. | 105 | // We'll reuse the same handler for all requests. |
108 | if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") | 106 | m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); |
109 | m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); | ||
110 | 107 | ||
111 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 108 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
109 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | ||
110 | |||
111 | if (m_workerThreads == null) | ||
112 | { | ||
113 | m_workerThreads = new Thread[2]; | ||
114 | |||
115 | for (uint i = 0; i < 2; i++) | ||
116 | { | ||
117 | m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests, | ||
118 | String.Format("InventoryWorkerThread{0}", i), | ||
119 | ThreadPriority.Normal, | ||
120 | false, | ||
121 | true, | ||
122 | null, | ||
123 | int.MaxValue); | ||
124 | } | ||
125 | } | ||
112 | } | 126 | } |
113 | 127 | ||
114 | public void PostInitialise() | 128 | public void PostInitialise() |
@@ -126,43 +140,192 @@ namespace OpenSim.Region.ClientStack.Linden | |||
126 | 140 | ||
127 | #endregion | 141 | #endregion |
128 | 142 | ||
129 | private void RegisterCaps(UUID agentID, Caps caps) | 143 | ~WebFetchInvDescModule() |
130 | { | 144 | { |
131 | if (m_webFetchInventoryDescendentsUrl != "") | 145 | foreach (Thread t in m_workerThreads) |
132 | RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); | 146 | Watchdog.AbortThread(t.ManagedThreadId); |
133 | |||
134 | if (m_fetchInventoryDescendents2Url != "") | ||
135 | RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url); | ||
136 | } | 147 | } |
137 | 148 | ||
138 | private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) | 149 | private class PollServiceInventoryEventArgs : PollServiceEventArgs |
139 | { | 150 | { |
140 | string capUrl; | 151 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
152 | |||
153 | private Dictionary<UUID, Hashtable> responses = | ||
154 | new Dictionary<UUID, Hashtable>(); | ||
155 | |||
156 | private Scene m_scene; | ||
141 | 157 | ||
142 | if (url == "localhost") | 158 | public PollServiceInventoryEventArgs(Scene scene, UUID pId) : |
159 | base(null, null, null, null, pId, int.MaxValue) | ||
143 | { | 160 | { |
144 | capUrl = "/CAPS/" + UUID.Random(); | 161 | m_scene = scene; |
162 | |||
163 | HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; | ||
164 | GetEvents = (x, y) => | ||
165 | { | ||
166 | lock (responses) | ||
167 | { | ||
168 | try | ||
169 | { | ||
170 | return responses[x]; | ||
171 | } | ||
172 | finally | ||
173 | { | ||
174 | responses.Remove(x); | ||
175 | } | ||
176 | } | ||
177 | }; | ||
178 | |||
179 | Request = (x, y) => | ||
180 | { | ||
181 | ScenePresence sp = m_scene.GetScenePresence(Id); | ||
182 | if (sp == null) | ||
183 | { | ||
184 | m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | aPollRequest reqinfo = new aPollRequest(); | ||
189 | reqinfo.thepoll = this; | ||
190 | reqinfo.reqID = x; | ||
191 | reqinfo.request = y; | ||
192 | reqinfo.presence = sp; | ||
193 | reqinfo.folders = new List<UUID>(); | ||
194 | |||
195 | // Decode the request here | ||
196 | string request = y["body"].ToString(); | ||
197 | |||
198 | request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); | ||
199 | |||
200 | request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); | ||
201 | request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); | ||
202 | |||
203 | Hashtable hash = new Hashtable(); | ||
204 | try | ||
205 | { | ||
206 | hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); | ||
207 | } | ||
208 | catch (LLSD.LLSDParseException e) | ||
209 | { | ||
210 | m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace); | ||
211 | m_log.Error("Request: " + request); | ||
212 | return; | ||
213 | } | ||
214 | catch (System.Xml.XmlException) | ||
215 | { | ||
216 | m_log.ErrorFormat("[INVENTORY]: XML Format error"); | ||
217 | } | ||
218 | |||
219 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | ||
220 | |||
221 | bool highPriority = false; | ||
222 | |||
223 | for (int i = 0; i < foldersrequested.Count; i++) | ||
224 | { | ||
225 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
226 | string folder = inventoryhash["folder_id"].ToString(); | ||
227 | UUID folderID; | ||
228 | if (UUID.TryParse(folder, out folderID)) | ||
229 | { | ||
230 | if (!reqinfo.folders.Contains(folderID)) | ||
231 | { | ||
232 | if (sp.COF != UUID.Zero && sp.COF == folderID) | ||
233 | highPriority = true; | ||
234 | reqinfo.folders.Add(folderID); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | if (highPriority) | ||
240 | m_queue.EnqueueHigh(reqinfo); | ||
241 | else | ||
242 | m_queue.EnqueueLow(reqinfo); | ||
243 | }; | ||
244 | |||
245 | NoEvents = (x, y) => | ||
246 | { | ||
247 | /* | ||
248 | lock (requests) | ||
249 | { | ||
250 | Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); | ||
251 | requests.Remove(request); | ||
252 | } | ||
253 | */ | ||
254 | Hashtable response = new Hashtable(); | ||
255 | |||
256 | response["int_response_code"] = 500; | ||
257 | response["str_response_string"] = "Script timeout"; | ||
258 | response["content_type"] = "text/plain"; | ||
259 | response["keepalive"] = false; | ||
260 | response["reusecontext"] = false; | ||
261 | |||
262 | return response; | ||
263 | }; | ||
264 | } | ||
145 | 265 | ||
146 | IRequestHandler reqHandler | 266 | public void Process(aPollRequest requestinfo) |
147 | = new RestStreamHandler( | 267 | { |
148 | "POST", | 268 | UUID requestID = requestinfo.reqID; |
149 | capUrl, | 269 | |
150 | m_webFetchHandler.FetchInventoryDescendentsRequest, | 270 | Hashtable response = new Hashtable(); |
151 | "FetchInventoryDescendents2", | 271 | |
152 | agentID.ToString()); | 272 | response["int_response_code"] = 200; |
273 | response["content_type"] = "text/plain"; | ||
274 | response["keepalive"] = false; | ||
275 | response["reusecontext"] = false; | ||
153 | 276 | ||
154 | caps.RegisterHandler(capName, reqHandler); | 277 | response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( |
278 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); | ||
279 | |||
280 | lock (responses) | ||
281 | responses[requestID] = response; | ||
155 | } | 282 | } |
156 | else | 283 | } |
284 | |||
285 | private void RegisterCaps(UUID agentID, Caps caps) | ||
286 | { | ||
287 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | ||
288 | |||
289 | // Register this as a poll service | ||
290 | PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); | ||
291 | |||
292 | args.Type = PollServiceEventArgs.EventType.Inventory; | ||
293 | MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); | ||
294 | |||
295 | string hostName = m_scene.RegionInfo.ExternalHostName; | ||
296 | uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; | ||
297 | string protocol = "http"; | ||
298 | |||
299 | if (MainServer.Instance.UseSSL) | ||
157 | { | 300 | { |
158 | capUrl = url; | 301 | hostName = MainServer.Instance.SSLCommonName; |
302 | port = MainServer.Instance.SSLPort; | ||
303 | protocol = "https"; | ||
304 | } | ||
305 | caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | ||
306 | |||
307 | m_capsDict[agentID] = capUrl; | ||
308 | } | ||
159 | 309 | ||
160 | caps.RegisterHandler(capName, capUrl); | 310 | private void DeregisterCaps(UUID agentID, Caps caps) |
311 | { | ||
312 | string capUrl; | ||
313 | |||
314 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | ||
315 | { | ||
316 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | ||
317 | m_capsDict.Remove(agentID); | ||
161 | } | 318 | } |
319 | } | ||
162 | 320 | ||
163 | // m_log.DebugFormat( | 321 | private void DoInventoryRequests() |
164 | // "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", | 322 | { |
165 | // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); | 323 | while (true) |
324 | { | ||
325 | aPollRequest poolreq = m_queue.Dequeue(); | ||
326 | |||
327 | poolreq.thepoll.Process(poolreq); | ||
328 | } | ||
166 | } | 329 | } |
167 | } | 330 | } |
168 | } \ No newline at end of file | 331 | } |