29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.Reflection;
34 using System.Threading;
37 using OpenSim.Framework.Monitoring;
41 using OpenMetaverse.StructuredData;
42 using OpenSim.Capabilities.Handlers;
43 using OpenSim.Framework;
44 using OpenSim.Framework.Servers;
45 using OpenSim.Framework.Servers.HttpServer;
46 using OpenSim.Region.Framework.Interfaces;
47 using OpenSim.Region.Framework.Scenes;
48 using OpenSim.Services.Interfaces;
51 namespace OpenSim.
Region.ClientStack.Linden
53 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"GetMeshModule")]
59 private Scene m_scene;
61 private bool m_Enabled =
true;
64 private string m_URL2;
65 private string m_RedirectURL = null;
66 private string m_RedirectURL2 = null;
70 public PollServiceMeshEventArgs thepoll;
72 public Hashtable request;
83 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
89 private Dictionary<UUID, string> m_capsDict =
new Dictionary<UUID, string>();
90 private static Thread[] m_workerThreads = null;
91 private static int m_NumberScenes = 0;
92 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
93 new OpenMetaverse.BlockingQueue<aPollRequest>();
95 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices =
new Dictionary<UUID, PollServiceMeshEventArgs>();
98 #region Region Module interfaceBase Members
100 public Type ReplaceableInterface
107 IConfig config = source.Configs[
"ClientStack.LindenCaps"];
111 m_URL = config.GetString(
"Cap_GetMesh", string.Empty);
113 if (m_URL !=
string.Empty)
116 m_RedirectURL = config.GetString(
"GetMeshRedirectURL");
119 m_URL2 = config.GetString(
"Cap_GetMesh2", string.Empty);
121 if (m_URL2 !=
string.Empty)
125 m_RedirectURL2 = config.GetString(
"GetMesh2RedirectURL");
136 m_assetService = pScene.AssetService;
144 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
145 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
146 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
156 m_AssetService = m_scene.RequestModuleInterface<
IAssetService>();
157 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
160 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
161 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
165 if (m_workerThreads == null)
167 m_workerThreads =
new Thread[2];
169 for (uint i = 0; i < 2; i++)
171 m_workerThreads[i] = WorkManager.StartThread(DoMeshRequests,
172 String.Format(
"GetMeshWorker{0}", i),
173 ThreadPriority.Normal,
184 if(m_NumberScenes <= 0 && m_workerThreads != null)
186 m_log.DebugFormat(
"[GetMeshModule] Closing");
187 foreach (
Thread t
in m_workerThreads)
188 Watchdog.AbortThread(t.ManagedThreadId);
193 public string Name {
get {
return "GetMeshModule"; } }
197 private static void DoMeshRequests()
201 aPollRequest poolreq = m_queue.Dequeue();
202 Watchdog.UpdateThread();
203 poolreq.thepoll.Process(poolreq);
212 PollServiceMeshEventArgs args;
213 if (m_pollservices.TryGetValue(user, out args))
215 args.UpdateThrottle(imagethrottle, p);
221 private List<Hashtable> requests =
222 new List<Hashtable>();
223 private Dictionary<UUID, aPollResponse> responses =
224 new Dictionary<UUID, aPollResponse>();
226 private Scene m_scene;
227 private MeshCapsDataThrottler m_throttler;
228 public PollServiceMeshEventArgs(
string uri, UUID pId,
Scene scene) :
229 base(null, uri, null, null, null, pId, int.MaxValue)
232 m_throttler =
new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
234 HasEvents = (x, y) =>
238 bool ret = m_throttler.hasEvents(x, responses);
239 m_throttler.ProcessTime();
244 GetEvents = (x, y) =>
250 return responses[x].response;
254 m_throttler.ProcessTime();
262 aPollRequest reqinfo =
new aPollRequest();
263 reqinfo.thepoll =
this;
267 m_queue.Enqueue(reqinfo);
280 Hashtable response =
new Hashtable();
282 response[
"int_response_code"] = 500;
283 response[
"str_response_string"] =
"Script timeout";
284 response[
"content_type"] =
"text/plain";
285 response[
"keepalive"] =
false;
286 response[
"reusecontext"] =
false;
292 public void Process(aPollRequest requestinfo)
296 UUID requestID = requestinfo.reqID;
298 if(m_scene.ShuttingDown)
302 if (m_scene.GetScenePresence(Id) == null)
304 response =
new Hashtable();
306 response[
"int_response_code"] = 500;
307 response[
"str_response_string"] =
"Script timeout";
308 response[
"content_type"] =
"text/plain";
309 response[
"keepalive"] =
false;
310 response[
"reusecontext"] =
false;
313 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
318 response = m_getMeshHandler.Handle(requestinfo.request);
321 responses[requestID] =
new aPollResponse()
323 bytes = (int)response[
"int_bytes"],
324 lod = (
int)response[
"int_lod"],
329 m_throttler.ProcessTime();
332 internal void UpdateThrottle(
int pimagethrottle,
ScenePresence p)
334 m_throttler.UpdateThrottle(pimagethrottle, p);
341 if (m_URL ==
"localhost")
343 string capUrl =
"/CAPS/" + UUID.Random() +
"/";
346 PollServiceMeshEventArgs args =
new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
348 args.Type = PollServiceEventArgs.EventType.Mesh;
349 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
351 string hostName = m_scene.RegionInfo.ExternalHostName;
353 string protocol =
"http";
357 hostName = MainServer.Instance.SSLCommonName;
358 port = MainServer.Instance.SSLPort;
361 caps.RegisterHandler(
"GetMesh", String.Format(
"{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
362 m_pollservices[agentID] = args;
363 m_capsDict[agentID] = capUrl;
367 caps.RegisterHandler(
"GetMesh", m_URL);
371 private void DeregisterCaps(UUID agentID,
Caps caps)
374 PollServiceMeshEventArgs args;
375 if (m_capsDict.TryGetValue(agentID, out capUrl))
377 MainServer.Instance.RemoveHTTPHandler(
"", capUrl);
378 m_capsDict.Remove(agentID);
380 if (m_pollservices.TryGetValue(agentID, out args))
382 m_pollservices.Remove(agentID);
386 internal sealed
class MeshCapsDataThrottler
389 private volatile int currenttime = 0;
390 private volatile int lastTimeElapsed = 0;
391 private volatile int BytesSent = 0;
392 private int Lod3 = 0;
393 private int Lod2 = 0;
395 private int UserSetThrottle = 0;
396 private int UDPSetThrottle = 0;
397 private int CapSetThrottle = 0;
398 private float CapThrottleDistributon = 0.30f;
399 private readonly
Scene m_scene;
403 public MeshCapsDataThrottler(
int pBytes,
int max,
int min,
Scene pScene, UUID puser)
405 ThrottleBytes = pBytes;
406 lastTimeElapsed = Util.EnvironmentTickCount();
407 Throttle = ThrottleOutPacketType.Asset;
412 public bool hasEvents(UUID
key, Dictionary<UUID, aPollResponse> responses)
414 const float ThirtyPercent = 0.30f;
415 const float FivePercent = 0.05f;
418 bool haskey = responses.ContainsKey(
key);
420 if (responses.Count > 2)
422 SplitThrottle(ThirtyPercent);
426 SplitThrottle(FivePercent);
433 aPollResponse response;
434 if (responses.TryGetValue(key, out response))
436 float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
437 float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
439 if (BytesSent + response.bytes <= ThrottleBytes)
441 BytesSent += response.bytes;
446 else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
448 Interlocked.Increment(ref Lod3);
449 BytesSent += response.bytes;
454 else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
456 Interlocked.Increment(ref Lod2);
457 BytesSent += response.bytes;
469 public void SubtractBytes(
int bytes,
int lod)
473 private void SplitThrottle(
float percentMultiplier)
476 if (CapThrottleDistributon != percentMultiplier)
478 CapThrottleDistributon = percentMultiplier;
480 if (m_scene.TryGetScenePresence(User, out p))
483 UpdateThrottle(UserSetThrottle, p);
488 public void ProcessTime()
493 private void PassTime()
495 currenttime = Util.EnvironmentTickCount();
496 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
498 if (currenttime - timeElapsed >= 1000)
500 lastTimeElapsed = Util.EnvironmentTickCount();
501 BytesSent -= ThrottleBytes;
502 if (BytesSent < 0) BytesSent = 0;
503 if (BytesSent < ThrottleBytes)
514 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
517 public int ThrottleBytes
519 get {
return CapSetThrottle; }
520 set { CapSetThrottle = value; }
523 internal void UpdateThrottle(
int pimagethrottle,
ScenePresence p)
526 UserSetThrottle = pimagethrottle;
527 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
530 float udp = 1.0f - CapThrottleDistributon;
533 UDPSetThrottle = (int) ((
float)pimagethrottle * udp);
534 if (CapSetThrottle < 4068)
535 CapSetThrottle = 4068;
536 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
OpenSim.Framework.Capabilities.Caps Caps
OpenSim.Framework.Capabilities.Caps Caps
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
static BaseHttpServer Instance
Set the main HTTP server instance.
void RegisterCaps(UUID agentID, Caps caps)
void AddRegion(Scene pScene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void ThrottleUpdate(ScenePresence p)