29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using System.Threading;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Servers;
39 using OpenSim.Framework.Servers.HttpServer;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Framework.Scenes;
42 using OpenSim.Framework.Capabilities;
43 using OpenSim.Services.Interfaces;
45 using OpenSim.Capabilities.Handlers;
46 using OpenSim.Framework.Monitoring;
48 using OpenMetaverse.StructuredData;
50 namespace OpenSim.
Region.ClientStack.Linden
55 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"WebFetchInvDescModule")]
60 public PollServiceInventoryEventArgs thepoll;
62 public Hashtable request;
64 public List<UUID> folders;
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
75 public bool ProcessQueuedRequestsAsync {
get;
private set; }
83 public static int ProcessedRequestsCount {
get; set; }
85 private static Stat s_queuedRequestsStat;
86 private static Stat s_processedRequestsStat;
93 private bool m_Enabled;
95 private string m_fetchInventoryDescendents2Url;
100 private static Thread[] m_workerThreads = null;
102 private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue =
103 new OpenSim.Framework.BlockingQueue<aPollRequest>();
105 private static int m_NumberScenes = 0;
107 #region ISharedRegionModule Members
113 ProcessQueuedRequestsAsync = processQueuedResultsAsync;
118 IConfig config = source.Configs[
"ClientStack.LindenCaps"];
122 m_fetchInventoryDescendents2Url = config.GetString(
"Cap_FetchInventoryDescendents2", string.Empty);
126 if (m_fetchInventoryDescendents2Url !=
string.Empty)
145 Scene.EventManager.OnRegisterCaps -= RegisterCaps;
147 StatsManager.DeregisterStat(s_processedRequestsStat);
148 StatsManager.DeregisterStat(s_queuedRequestsStat);
159 if (s_processedRequestsStat == null)
160 s_processedRequestsStat =
162 "ProcessedFetchInventoryRequests",
163 "Number of processed fetch inventory requests",
164 "These have not necessarily yet been dispatched back to the requester.",
170 stat => { stat.Value = ProcessedRequestsCount; },
171 StatVerbosity.Debug);
173 if (s_queuedRequestsStat == null)
174 s_queuedRequestsStat =
176 "QueuedFetchInventoryRequests",
177 "Number of fetch inventory requests queued for processing",
184 stat => { stat.Value = m_queue.Count(); },
185 StatVerbosity.Debug);
187 StatsManager.RegisterStat(s_processedRequestsStat);
188 StatsManager.RegisterStat(s_queuedRequestsStat);
190 m_InventoryService = Scene.InventoryService;
191 m_LibraryService = Scene.LibraryService;
196 Scene.EventManager.OnRegisterCaps += RegisterCaps;
201 if (ProcessQueuedRequestsAsync && m_workerThreads == null)
203 m_workerThreads =
new Thread[nworkers];
205 for (uint i = 0; i < nworkers; i++)
207 m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests,
208 String.Format(
"InventoryWorkerThread{0}", i),
209 ThreadPriority.Normal,
227 if (ProcessQueuedRequestsAsync)
229 if (m_NumberScenes <= 0 && m_workerThreads != null)
231 m_log.DebugFormat(
"[WebFetchInvDescModule] Closing");
232 foreach (
Thread t
in m_workerThreads)
233 Watchdog.AbortThread(t.ManagedThreadId);
235 m_workerThreads = null;
240 public string Name {
get {
return "WebFetchInvDescModule"; } }
242 public Type ReplaceableInterface
251 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
253 private Dictionary<UUID, Hashtable> responses =
254 new Dictionary<UUID, Hashtable>();
259 base(null, url, null, null, null, pId, int.MaxValue)
263 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
264 GetEvents = (x, y) =>
283 aPollRequest reqinfo =
new aPollRequest();
284 reqinfo.thepoll =
this;
287 reqinfo.presence = sp;
288 reqinfo.folders =
new List<UUID>();
291 string request = y[
"body"].ToString();
293 request = request.Replace(
"<string>00000000-0000-0000-0000-000000000000</string>",
"<uuid>00000000-0000-0000-0000-000000000000</uuid>");
295 request = request.Replace(
"<key>fetch_folders</key><integer>0</integer>",
"<key>fetch_folders</key><boolean>0</boolean>");
296 request = request.Replace(
"<key>fetch_folders</key><integer>1</integer>",
"<key>fetch_folders</key><boolean>1</boolean>");
298 Hashtable hash =
new Hashtable();
301 hash = (Hashtable)LLSD.LLSDDeserialize(
Utils.StringToBytes(request));
303 catch (LLSD.LLSDParseException e)
305 m_log.ErrorFormat(
"[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
306 m_log.Error(
"Request: " + request);
309 catch (System.Xml.XmlException)
311 m_log.ErrorFormat(
"[INVENTORY]: XML Format error");
314 ArrayList foldersrequested = (ArrayList)hash[
"folders"];
316 bool highPriority =
false;
318 for (
int i = 0; i < foldersrequested.Count; i++)
320 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
321 string folder = inventoryhash[
"folder_id"].ToString();
323 if (
UUID.TryParse(folder, out folderID))
325 if (!reqinfo.folders.Contains(folderID))
327 if (sp.
COF !=
UUID.Zero && sp.
COF == folderID)
329 reqinfo.folders.Add(folderID);
335 m_queue.PriorityEnqueue(reqinfo);
337 m_queue.Enqueue(reqinfo);
349 Hashtable response =
new Hashtable();
351 response[
"int_response_code"] = 500;
352 response[
"str_response_string"] =
"Script timeout";
353 response[
"content_type"] =
"text/plain";
354 response[
"keepalive"] =
false;
355 response[
"reusecontext"] =
false;
361 public void Process(aPollRequest requestinfo)
363 if(m_module == null || m_module.Scene == null || m_module.Scene.ShuttingDown)
366 UUID requestID = requestinfo.reqID;
368 Hashtable response =
new Hashtable();
370 response[
"int_response_code"] = 200;
371 response[
"content_type"] =
"text/plain";
372 response[
"keepalive"] =
false;
373 response[
"reusecontext"] =
false;
375 response[
"str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
376 requestinfo.request[
"body"].ToString(),
String.Empty,
String.Empty, null, null);
380 if (responses.ContainsKey(requestID))
381 m_log.WarnFormat(
"[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054");
382 responses[requestID] = response;
384 requestinfo.folders.Clear();
385 requestinfo.request.Clear();
386 WebFetchInvDescModule.ProcessedRequestsCount++;
390 private void RegisterCaps(UUID agentID,
Caps caps)
392 RegisterFetchDescendentsCap(agentID, caps,
"FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
395 private void RegisterFetchDescendentsCap(UUID agentID,
Caps caps,
string capName,
string url)
405 else if (url ==
"localhost")
407 capUrl =
"/CAPS/" + UUID.Random() +
"/";
410 PollServiceInventoryEventArgs args =
new PollServiceInventoryEventArgs(
this, capUrl, agentID);
411 args.Type = PollServiceEventArgs.EventType.Inventory;
413 caps.RegisterPollHandler(capName, args);
421 handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
423 caps.RegisterHandler(capName, capUrl);
442 private static void DoInventoryRequests()
446 Watchdog.UpdateThread();
448 aPollRequest poolreq = m_queue.Dequeue(5000);
450 if (poolreq != null && poolreq.thepoll != null)
454 poolreq.thepoll.Process(poolreq);
459 "[INVENTORY]: Failed to process queued inventory request {0} for {1}. Exception {3}",
460 poolreq.reqID, poolreq.presence != null ? poolreq.presence.Name :
"unknown", e);
OpenSim.Server.Handlers.Simulation.Utils Utils
WebFetchInvDescModule(bool processQueuedResultsAsync)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Holds individual statistic details
This module implements both WebFetchInventoryDescendents and FetchInventoryDescendents2 capabilities...
OpenSim.Framework.Capabilities.Caps Caps
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
void RemoveRegion(Scene s)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void AddRegion(Scene s)
This is called whenever a Scene is added. For shared modules, this can happen several times...
MeasuresOfInterest
Measures of interest for this stat.
void RegionLoaded(Scene s)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...