opensim – Blame information for rev 1

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