diff options
author | Robert Adams | 2015-09-08 04:54:16 -0700 |
---|---|---|
committer | Robert Adams | 2015-09-08 04:54:16 -0700 |
commit | e5367d822be9b05e74c859afe2d2956a3e95aa33 (patch) | |
tree | e904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs | |
parent | add lost admin_reset_land method (diff) | |
parent | Deleted access control spec from [LoginService] section of standalone config.... (diff) | |
download | opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2 opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz |
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules.
AVN physics hasn't been moved to new location.
Does not compile yet.
Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs')
-rw-r--r-- | OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs | 1203 |
1 files changed, 1203 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs new file mode 100644 index 0000000..bd5289f --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs | |||
@@ -0,0 +1,1203 @@ | |||
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.IO; | ||
32 | using System.Net; // to be used for REST-->Grid shortly | ||
33 | using System.Reflection; | ||
34 | using System.Text; | ||
35 | using System.Threading; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.StructuredData; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using Mono.Data.SqliteClient; | ||
46 | using Mono.Addins; | ||
47 | |||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | |||
50 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
51 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
52 | |||
53 | namespace OpenSim.Region.UserStatistics | ||
54 | { | ||
55 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")] | ||
56 | public class WebStatsModule : ISharedRegionModule | ||
57 | { | ||
58 | private static readonly ILog m_log = | ||
59 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
60 | |||
61 | private static SqliteConnection dbConn; | ||
62 | |||
63 | /// <summary> | ||
64 | /// User statistics sessions keyed by agent ID | ||
65 | /// </summary> | ||
66 | private Dictionary<UUID, UserSession> m_sessions = new Dictionary<UUID, UserSession>(); | ||
67 | |||
68 | private List<Scene> m_scenes = new List<Scene>(); | ||
69 | private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>(); | ||
70 | private Dictionary<UUID, USimStatsData> m_simstatsCounters = new Dictionary<UUID, USimStatsData>(); | ||
71 | private const int updateStatsMod = 6; | ||
72 | private int updateLogMod = 1; | ||
73 | private volatile int updateLogCounter = 0; | ||
74 | private volatile int concurrencyCounter = 0; | ||
75 | private bool enabled = false; | ||
76 | private string m_loglines = String.Empty; | ||
77 | private volatile int lastHit = 12000; | ||
78 | |||
79 | #region ISharedRegionModule | ||
80 | |||
81 | public virtual void Initialise(IConfigSource config) | ||
82 | { | ||
83 | IConfig cnfg = config.Configs["WebStats"]; | ||
84 | |||
85 | if (cnfg != null) | ||
86 | enabled = cnfg.GetBoolean("enabled", false); | ||
87 | } | ||
88 | |||
89 | public virtual void PostInitialise() | ||
90 | { | ||
91 | if (!enabled) | ||
92 | return; | ||
93 | |||
94 | if (Util.IsWindows()) | ||
95 | Util.LoadArchSpecificWindowsDll("sqlite3.dll"); | ||
96 | |||
97 | //IConfig startupConfig = config.Configs["Startup"]; | ||
98 | |||
99 | dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3"); | ||
100 | dbConn.Open(); | ||
101 | CreateTables(dbConn); | ||
102 | |||
103 | Prototype_distributor protodep = new Prototype_distributor(); | ||
104 | Updater_distributor updatedep = new Updater_distributor(); | ||
105 | ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX(); | ||
106 | SimStatsAJAX ajSimStats = new SimStatsAJAX(); | ||
107 | LogLinesAJAX ajLogLines = new LogLinesAJAX(); | ||
108 | Default_Report defaultReport = new Default_Report(); | ||
109 | Clients_report clientReport = new Clients_report(); | ||
110 | Sessions_Report sessionsReport = new Sessions_Report(); | ||
111 | |||
112 | reports.Add("prototype.js", protodep); | ||
113 | reports.Add("updater.js", updatedep); | ||
114 | reports.Add("activeconnectionsajax.html", ajConnections); | ||
115 | reports.Add("simstatsajax.html", ajSimStats); | ||
116 | reports.Add("activelogajax.html", ajLogLines); | ||
117 | reports.Add("default.report", defaultReport); | ||
118 | reports.Add("clients.report", clientReport); | ||
119 | reports.Add("sessions.report", sessionsReport); | ||
120 | |||
121 | reports.Add("sim.css", new Prototype_distributor("sim.css")); | ||
122 | reports.Add("sim.html", new Prototype_distributor("sim.html")); | ||
123 | reports.Add("jquery.js", new Prototype_distributor("jquery.js")); | ||
124 | |||
125 | //// | ||
126 | // Add Your own Reports here (Do Not Modify Lines here Devs!) | ||
127 | //// | ||
128 | |||
129 | //// | ||
130 | // End Own reports section | ||
131 | //// | ||
132 | |||
133 | MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest); | ||
134 | MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest); | ||
135 | } | ||
136 | |||
137 | public virtual void AddRegion(Scene scene) | ||
138 | { | ||
139 | if (!enabled) | ||
140 | return; | ||
141 | |||
142 | lock (m_scenes) | ||
143 | { | ||
144 | m_scenes.Add(scene); | ||
145 | updateLogMod = m_scenes.Count * 2; | ||
146 | |||
147 | m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID)); | ||
148 | |||
149 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
150 | scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; | ||
151 | scene.EventManager.OnClientClosed += OnClientClosed; | ||
152 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
153 | scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | public void RegionLoaded(Scene scene) | ||
158 | { | ||
159 | } | ||
160 | |||
161 | public void RemoveRegion(Scene scene) | ||
162 | { | ||
163 | if (!enabled) | ||
164 | return; | ||
165 | |||
166 | lock (m_scenes) | ||
167 | { | ||
168 | m_scenes.Remove(scene); | ||
169 | updateLogMod = m_scenes.Count * 2; | ||
170 | m_simstatsCounters.Remove(scene.RegionInfo.RegionID); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | public virtual void Close() | ||
175 | { | ||
176 | if (!enabled) | ||
177 | return; | ||
178 | |||
179 | dbConn.Close(); | ||
180 | dbConn.Dispose(); | ||
181 | m_sessions.Clear(); | ||
182 | m_scenes.Clear(); | ||
183 | reports.Clear(); | ||
184 | m_simstatsCounters.Clear(); | ||
185 | } | ||
186 | |||
187 | public virtual string Name | ||
188 | { | ||
189 | get { return "ViewerStatsModule"; } | ||
190 | } | ||
191 | |||
192 | public Type ReplaceableInterface | ||
193 | { | ||
194 | get { return null; } | ||
195 | } | ||
196 | |||
197 | #endregion | ||
198 | |||
199 | private void ReceiveClassicSimStatsPacket(SimStats stats) | ||
200 | { | ||
201 | if (!enabled) | ||
202 | return; | ||
203 | |||
204 | try | ||
205 | { | ||
206 | // Ignore the update if there's a report running right now | ||
207 | // ignore the update if there hasn't been a hit in 30 seconds. | ||
208 | if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000) | ||
209 | return; | ||
210 | |||
211 | // We will conduct this under lock so that fields such as updateLogCounter do not potentially get | ||
212 | // confused if a scene is removed. | ||
213 | // XXX: Possibly the scope of this lock could be reduced though it's not critical. | ||
214 | lock (m_scenes) | ||
215 | { | ||
216 | if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0) | ||
217 | { | ||
218 | m_loglines = readLogLines(10); | ||
219 | |||
220 | if (updateLogCounter > 10000) | ||
221 | updateLogCounter = 1; | ||
222 | } | ||
223 | |||
224 | USimStatsData ss = m_simstatsCounters[stats.RegionUUID]; | ||
225 | |||
226 | if ((++ss.StatsCounter % updateStatsMod) == 0) | ||
227 | { | ||
228 | ss.ConsumeSimStats(stats); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | catch (KeyNotFoundException) | ||
233 | { | ||
234 | } | ||
235 | } | ||
236 | |||
237 | private Hashtable HandleUnknownCAPSRequest(Hashtable request) | ||
238 | { | ||
239 | //string regpath = request["uri"].ToString(); | ||
240 | int response_code = 200; | ||
241 | string contenttype = "text/html"; | ||
242 | UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn); | ||
243 | Hashtable responsedata = new Hashtable(); | ||
244 | |||
245 | responsedata["int_response_code"] = response_code; | ||
246 | responsedata["content_type"] = contenttype; | ||
247 | responsedata["keepalive"] = false; | ||
248 | responsedata["str_response_string"] = string.Empty; | ||
249 | return responsedata; | ||
250 | } | ||
251 | |||
252 | private Hashtable HandleStatsRequest(Hashtable request) | ||
253 | { | ||
254 | lastHit = System.Environment.TickCount; | ||
255 | Hashtable responsedata = new Hashtable(); | ||
256 | string regpath = request["uri"].ToString(); | ||
257 | int response_code = 404; | ||
258 | string contenttype = "text/html"; | ||
259 | bool jsonFormatOutput = false; | ||
260 | |||
261 | string strOut = string.Empty; | ||
262 | |||
263 | // The request patch should be "/SStats/reportName" where 'reportName' | ||
264 | // is one of the names added to the 'reports' hashmap. | ||
265 | regpath = regpath.Remove(0, 8); | ||
266 | if (regpath.Length == 0) regpath = "default.report"; | ||
267 | if (reports.ContainsKey(regpath)) | ||
268 | { | ||
269 | IStatsController rep = reports[regpath]; | ||
270 | Hashtable repParams = new Hashtable(); | ||
271 | |||
272 | if (request.ContainsKey("json")) | ||
273 | jsonFormatOutput = true; | ||
274 | |||
275 | if (request.ContainsKey("requestvars")) | ||
276 | repParams["RequestVars"] = request["requestvars"]; | ||
277 | else | ||
278 | repParams["RequestVars"] = new Hashtable(); | ||
279 | |||
280 | if (request.ContainsKey("querystringkeys")) | ||
281 | repParams["QueryStringKeys"] = request["querystringkeys"]; | ||
282 | else | ||
283 | repParams["QueryStringKeys"] = new string[0]; | ||
284 | |||
285 | |||
286 | repParams["DatabaseConnection"] = dbConn; | ||
287 | repParams["Scenes"] = m_scenes; | ||
288 | repParams["SimStats"] = m_simstatsCounters; | ||
289 | repParams["LogLines"] = m_loglines; | ||
290 | repParams["Reports"] = reports; | ||
291 | |||
292 | concurrencyCounter++; | ||
293 | |||
294 | if (jsonFormatOutput) | ||
295 | { | ||
296 | strOut = rep.RenderJson(rep.ProcessModel(repParams)); | ||
297 | contenttype = "text/json"; | ||
298 | } | ||
299 | else | ||
300 | { | ||
301 | strOut = rep.RenderView(rep.ProcessModel(repParams)); | ||
302 | } | ||
303 | |||
304 | if (regpath.EndsWith("js")) | ||
305 | { | ||
306 | contenttype = "text/javascript"; | ||
307 | } | ||
308 | |||
309 | if (regpath.EndsWith("css")) | ||
310 | { | ||
311 | contenttype = "text/css"; | ||
312 | } | ||
313 | |||
314 | concurrencyCounter--; | ||
315 | |||
316 | response_code = 200; | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | strOut = MainServer.Instance.GetHTTP404(""); | ||
321 | } | ||
322 | |||
323 | responsedata["int_response_code"] = response_code; | ||
324 | responsedata["content_type"] = contenttype; | ||
325 | responsedata["keepalive"] = false; | ||
326 | responsedata["str_response_string"] = strOut; | ||
327 | |||
328 | return responsedata; | ||
329 | } | ||
330 | |||
331 | private void CreateTables(SqliteConnection db) | ||
332 | { | ||
333 | using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db)) | ||
334 | { | ||
335 | createcmd.ExecuteNonQuery(); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | private void OnRegisterCaps(UUID agentID, Caps caps) | ||
340 | { | ||
341 | // m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); | ||
342 | |||
343 | string capsPath = "/CAPS/VS/" + UUID.Random(); | ||
344 | caps.RegisterHandler( | ||
345 | "ViewerStats", | ||
346 | new RestStreamHandler( | ||
347 | "POST", | ||
348 | capsPath, | ||
349 | (request, path, param, httpRequest, httpResponse) | ||
350 | => ViewerStatsReport(request, path, param, agentID, caps), | ||
351 | "ViewerStats", | ||
352 | agentID.ToString())); | ||
353 | } | ||
354 | |||
355 | private void OnDeRegisterCaps(UUID agentID, Caps caps) | ||
356 | { | ||
357 | } | ||
358 | |||
359 | protected virtual void AddEventHandlers() | ||
360 | { | ||
361 | lock (m_scenes) | ||
362 | { | ||
363 | updateLogMod = m_scenes.Count * 2; | ||
364 | foreach (Scene scene in m_scenes) | ||
365 | { | ||
366 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | ||
367 | scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps; | ||
368 | scene.EventManager.OnClientClosed += OnClientClosed; | ||
369 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | private void OnMakeRootAgent(ScenePresence agent) | ||
375 | { | ||
376 | // m_log.DebugFormat( | ||
377 | // "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}", | ||
378 | // agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name); | ||
379 | |||
380 | lock (m_sessions) | ||
381 | { | ||
382 | UserSession uid; | ||
383 | |||
384 | if (!m_sessions.ContainsKey(agent.UUID)) | ||
385 | { | ||
386 | UserSessionData usd = UserSessionUtil.newUserSessionData(); | ||
387 | uid = new UserSession(); | ||
388 | uid.name_f = agent.Firstname; | ||
389 | uid.name_l = agent.Lastname; | ||
390 | uid.session_data = usd; | ||
391 | |||
392 | m_sessions.Add(agent.UUID, uid); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | uid = m_sessions[agent.UUID]; | ||
397 | } | ||
398 | |||
399 | uid.region_id = agent.Scene.RegionInfo.RegionID; | ||
400 | uid.session_id = agent.ControllingClient.SessionId; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | private void OnClientClosed(UUID agentID, Scene scene) | ||
405 | { | ||
406 | lock (m_sessions) | ||
407 | { | ||
408 | if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID) | ||
409 | { | ||
410 | m_sessions.Remove(agentID); | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | |||
415 | private string readLogLines(int amount) | ||
416 | { | ||
417 | Encoding encoding = Encoding.ASCII; | ||
418 | int sizeOfChar = encoding.GetByteCount("\n"); | ||
419 | byte[] buffer = encoding.GetBytes("\n"); | ||
420 | string logfile = Util.logFile(); | ||
421 | FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); | ||
422 | Int64 tokenCount = 0; | ||
423 | Int64 endPosition = fs.Length / sizeOfChar; | ||
424 | |||
425 | for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar) | ||
426 | { | ||
427 | fs.Seek(-position, SeekOrigin.End); | ||
428 | fs.Read(buffer, 0, buffer.Length); | ||
429 | |||
430 | if (encoding.GetString(buffer) == "\n") | ||
431 | { | ||
432 | tokenCount++; | ||
433 | if (tokenCount == amount) | ||
434 | { | ||
435 | byte[] returnBuffer = new byte[fs.Length - fs.Position]; | ||
436 | fs.Read(returnBuffer, 0, returnBuffer.Length); | ||
437 | fs.Close(); | ||
438 | fs.Dispose(); | ||
439 | return encoding.GetString(returnBuffer); | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | |||
444 | // handle case where number of tokens in file is less than numberOfTokens | ||
445 | fs.Seek(0, SeekOrigin.Begin); | ||
446 | buffer = new byte[fs.Length]; | ||
447 | fs.Read(buffer, 0, buffer.Length); | ||
448 | fs.Close(); | ||
449 | fs.Dispose(); | ||
450 | return encoding.GetString(buffer); | ||
451 | } | ||
452 | |||
453 | /// <summary> | ||
454 | /// Callback for a viewerstats cap | ||
455 | /// </summary> | ||
456 | /// <param name="request"></param> | ||
457 | /// <param name="path"></param> | ||
458 | /// <param name="param"></param> | ||
459 | /// <param name="agentID"></param> | ||
460 | /// <param name="caps"></param> | ||
461 | /// <returns></returns> | ||
462 | private string ViewerStatsReport(string request, string path, string param, | ||
463 | UUID agentID, Caps caps) | ||
464 | { | ||
465 | // m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID); | ||
466 | |||
467 | UpdateUserStats(ParseViewerStats(request, agentID), dbConn); | ||
468 | |||
469 | return String.Empty; | ||
470 | } | ||
471 | |||
472 | private UserSession ParseViewerStats(string request, UUID agentID) | ||
473 | { | ||
474 | UserSession uid = new UserSession(); | ||
475 | UserSessionData usd; | ||
476 | OSD message = OSDParser.DeserializeLLSDXml(request); | ||
477 | OSDMap mmap; | ||
478 | |||
479 | lock (m_sessions) | ||
480 | { | ||
481 | if (agentID != UUID.Zero) | ||
482 | { | ||
483 | if (!m_sessions.ContainsKey(agentID)) | ||
484 | { | ||
485 | m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID); | ||
486 | return new UserSession(); | ||
487 | } | ||
488 | |||
489 | uid = m_sessions[agentID]; | ||
490 | |||
491 | // m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID); | ||
492 | } | ||
493 | else | ||
494 | { | ||
495 | // parse through the beginning to locate the session | ||
496 | if (message.Type != OSDType.Map) | ||
497 | return new UserSession(); | ||
498 | |||
499 | mmap = (OSDMap)message; | ||
500 | { | ||
501 | UUID sessionID = mmap["session_id"].AsUUID(); | ||
502 | |||
503 | if (sessionID == UUID.Zero) | ||
504 | return new UserSession(); | ||
505 | |||
506 | |||
507 | // search through each session looking for the owner | ||
508 | foreach (UUID usersessionid in m_sessions.Keys) | ||
509 | { | ||
510 | // got it! | ||
511 | if (m_sessions[usersessionid].session_id == sessionID) | ||
512 | { | ||
513 | agentID = usersessionid; | ||
514 | uid = m_sessions[usersessionid]; | ||
515 | break; | ||
516 | } | ||
517 | |||
518 | } | ||
519 | |||
520 | // can't find a session | ||
521 | if (agentID == UUID.Zero) | ||
522 | { | ||
523 | return new UserSession(); | ||
524 | } | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | |||
529 | usd = uid.session_data; | ||
530 | |||
531 | if (message.Type != OSDType.Map) | ||
532 | return new UserSession(); | ||
533 | |||
534 | mmap = (OSDMap)message; | ||
535 | { | ||
536 | if (mmap["agent"].Type != OSDType.Map) | ||
537 | return new UserSession(); | ||
538 | OSDMap agent_map = (OSDMap)mmap["agent"]; | ||
539 | usd.agent_id = agentID; | ||
540 | usd.name_f = uid.name_f; | ||
541 | usd.name_l = uid.name_l; | ||
542 | usd.region_id = uid.region_id; | ||
543 | usd.a_language = agent_map["language"].AsString(); | ||
544 | usd.mem_use = (float)agent_map["mem_use"].AsReal(); | ||
545 | usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal(); | ||
546 | usd.regions_visited = agent_map["regions_visited"].AsInteger(); | ||
547 | usd.run_time = (float)agent_map["run_time"].AsReal(); | ||
548 | usd.start_time = (float)agent_map["start_time"].AsReal(); | ||
549 | usd.client_version = agent_map["version"].AsString(); | ||
550 | |||
551 | UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(), | ||
552 | (float)agent_map["ping"].AsReal(), | ||
553 | (float)agent_map["sim_fps"].AsReal(), | ||
554 | (float)agent_map["fps"].AsReal()); | ||
555 | |||
556 | if (mmap["downloads"].Type != OSDType.Map) | ||
557 | return new UserSession(); | ||
558 | OSDMap downloads_map = (OSDMap)mmap["downloads"]; | ||
559 | usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal(); | ||
560 | usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal(); | ||
561 | usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal(); | ||
562 | |||
563 | // m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID()); | ||
564 | |||
565 | usd.session_id = mmap["session_id"].AsUUID(); | ||
566 | |||
567 | if (mmap["system"].Type != OSDType.Map) | ||
568 | return new UserSession(); | ||
569 | OSDMap system_map = (OSDMap)mmap["system"]; | ||
570 | |||
571 | usd.s_cpu = system_map["cpu"].AsString(); | ||
572 | usd.s_gpu = system_map["gpu"].AsString(); | ||
573 | usd.s_os = system_map["os"].AsString(); | ||
574 | usd.s_ram = system_map["ram"].AsInteger(); | ||
575 | |||
576 | if (mmap["stats"].Type != OSDType.Map) | ||
577 | return new UserSession(); | ||
578 | |||
579 | OSDMap stats_map = (OSDMap)mmap["stats"]; | ||
580 | { | ||
581 | |||
582 | if (stats_map["failures"].Type != OSDType.Map) | ||
583 | return new UserSession(); | ||
584 | OSDMap stats_failures = (OSDMap)stats_map["failures"]; | ||
585 | usd.f_dropped = stats_failures["dropped"].AsInteger(); | ||
586 | usd.f_failed_resends = stats_failures["failed_resends"].AsInteger(); | ||
587 | usd.f_invalid = stats_failures["invalid"].AsInteger(); | ||
588 | usd.f_resent = stats_failures["resent"].AsInteger(); | ||
589 | usd.f_send_packet = stats_failures["send_packet"].AsInteger(); | ||
590 | |||
591 | if (stats_map["net"].Type != OSDType.Map) | ||
592 | return new UserSession(); | ||
593 | OSDMap stats_net = (OSDMap)stats_map["net"]; | ||
594 | { | ||
595 | if (stats_net["in"].Type != OSDType.Map) | ||
596 | return new UserSession(); | ||
597 | |||
598 | OSDMap net_in = (OSDMap)stats_net["in"]; | ||
599 | usd.n_in_kb = (float)net_in["kbytes"].AsReal(); | ||
600 | usd.n_in_pk = net_in["packets"].AsInteger(); | ||
601 | |||
602 | if (stats_net["out"].Type != OSDType.Map) | ||
603 | return new UserSession(); | ||
604 | OSDMap net_out = (OSDMap)stats_net["out"]; | ||
605 | |||
606 | usd.n_out_kb = (float)net_out["kbytes"].AsReal(); | ||
607 | usd.n_out_pk = net_out["packets"].AsInteger(); | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | uid.session_data = usd; | ||
613 | m_sessions[agentID] = uid; | ||
614 | |||
615 | // m_log.DebugFormat( | ||
616 | // "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); | ||
617 | |||
618 | return uid; | ||
619 | } | ||
620 | |||
621 | private void UpdateUserStats(UserSession uid, SqliteConnection db) | ||
622 | { | ||
623 | // m_log.DebugFormat( | ||
624 | // "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id); | ||
625 | |||
626 | if (uid.session_id == UUID.Zero) | ||
627 | return; | ||
628 | |||
629 | lock (db) | ||
630 | { | ||
631 | using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db)) | ||
632 | { | ||
633 | updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString())); | ||
634 | updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString())); | ||
635 | updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString())); | ||
636 | updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated)); | ||
637 | updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip)); | ||
638 | updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f)); | ||
639 | updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l)); | ||
640 | updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view)); | ||
641 | updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view", | ||
642 | (int) uid.session_data.min_agents_in_view)); | ||
643 | updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view", | ||
644 | (int) uid.session_data.max_agents_in_view)); | ||
645 | updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view", | ||
646 | (int) uid.session_data.mode_agents_in_view)); | ||
647 | updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps)); | ||
648 | updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps)); | ||
649 | updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps)); | ||
650 | updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps)); | ||
651 | updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language)); | ||
652 | updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use)); | ||
653 | updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled)); | ||
654 | updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping)); | ||
655 | updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping)); | ||
656 | updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping)); | ||
657 | updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping)); | ||
658 | updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited)); | ||
659 | updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time)); | ||
660 | updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps)); | ||
661 | updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps)); | ||
662 | updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps)); | ||
663 | updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps)); | ||
664 | updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time)); | ||
665 | updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version)); | ||
666 | updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu)); | ||
667 | updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu)); | ||
668 | updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os)); | ||
669 | updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram)); | ||
670 | updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb)); | ||
671 | updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb)); | ||
672 | updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb)); | ||
673 | updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb)); | ||
674 | updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk)); | ||
675 | updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb)); | ||
676 | updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk)); | ||
677 | updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped)); | ||
678 | updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends)); | ||
679 | updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid)); | ||
680 | updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit)); | ||
681 | updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent)); | ||
682 | updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet)); | ||
683 | |||
684 | // StringBuilder parameters = new StringBuilder(); | ||
685 | // SqliteParameterCollection spc = updatecmd.Parameters; | ||
686 | // foreach (SqliteParameter sp in spc) | ||
687 | // parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value); | ||
688 | // | ||
689 | // m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters); | ||
690 | |||
691 | // m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id); | ||
692 | |||
693 | updatecmd.ExecuteNonQuery(); | ||
694 | } | ||
695 | } | ||
696 | } | ||
697 | |||
698 | #region SQL | ||
699 | private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data ( | ||
700 | session_id VARCHAR(36) NOT NULL PRIMARY KEY, | ||
701 | agent_id VARCHAR(36) NOT NULL DEFAULT '', | ||
702 | region_id VARCHAR(36) NOT NULL DEFAULT '', | ||
703 | last_updated INT NOT NULL DEFAULT '0', | ||
704 | remote_ip VARCHAR(16) NOT NULL DEFAULT '', | ||
705 | name_f VARCHAR(50) NOT NULL DEFAULT '', | ||
706 | name_l VARCHAR(50) NOT NULL DEFAULT '', | ||
707 | avg_agents_in_view FLOAT NOT NULL DEFAULT '0', | ||
708 | min_agents_in_view INT NOT NULL DEFAULT '0', | ||
709 | max_agents_in_view INT NOT NULL DEFAULT '0', | ||
710 | mode_agents_in_view INT NOT NULL DEFAULT '0', | ||
711 | avg_fps FLOAT NOT NULL DEFAULT '0', | ||
712 | min_fps FLOAT NOT NULL DEFAULT '0', | ||
713 | max_fps FLOAT NOT NULL DEFAULT '0', | ||
714 | mode_fps FLOAT NOT NULL DEFAULT '0', | ||
715 | a_language VARCHAR(25) NOT NULL DEFAULT '', | ||
716 | mem_use FLOAT NOT NULL DEFAULT '0', | ||
717 | meters_traveled FLOAT NOT NULL DEFAULT '0', | ||
718 | avg_ping FLOAT NOT NULL DEFAULT '0', | ||
719 | min_ping FLOAT NOT NULL DEFAULT '0', | ||
720 | max_ping FLOAT NOT NULL DEFAULT '0', | ||
721 | mode_ping FLOAT NOT NULL DEFAULT '0', | ||
722 | regions_visited INT NOT NULL DEFAULT '0', | ||
723 | run_time FLOAT NOT NULL DEFAULT '0', | ||
724 | avg_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
725 | min_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
726 | max_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
727 | mode_sim_fps FLOAT NOT NULL DEFAULT '0', | ||
728 | start_time FLOAT NOT NULL DEFAULT '0', | ||
729 | client_version VARCHAR(255) NOT NULL DEFAULT '', | ||
730 | s_cpu VARCHAR(255) NOT NULL DEFAULT '', | ||
731 | s_gpu VARCHAR(255) NOT NULL DEFAULT '', | ||
732 | s_os VARCHAR(2255) NOT NULL DEFAULT '', | ||
733 | s_ram INT NOT NULL DEFAULT '0', | ||
734 | d_object_kb FLOAT NOT NULL DEFAULT '0', | ||
735 | d_texture_kb FLOAT NOT NULL DEFAULT '0', | ||
736 | d_world_kb FLOAT NOT NULL DEFAULT '0', | ||
737 | n_in_kb FLOAT NOT NULL DEFAULT '0', | ||
738 | n_in_pk INT NOT NULL DEFAULT '0', | ||
739 | n_out_kb FLOAT NOT NULL DEFAULT '0', | ||
740 | n_out_pk INT NOT NULL DEFAULT '0', | ||
741 | f_dropped INT NOT NULL DEFAULT '0', | ||
742 | f_failed_resends INT NOT NULL DEFAULT '0', | ||
743 | f_invalid INT NOT NULL DEFAULT '0', | ||
744 | f_off_circuit INT NOT NULL DEFAULT '0', | ||
745 | f_resent INT NOT NULL DEFAULT '0', | ||
746 | f_send_packet INT NOT NULL DEFAULT '0' | ||
747 | );"; | ||
748 | |||
749 | private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data ( | ||
750 | session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view, | ||
751 | mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping, | ||
752 | regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram, | ||
753 | d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit, | ||
754 | f_resent, f_send_packet | ||
755 | ) | ||
756 | VALUES | ||
757 | ( | ||
758 | :session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view, | ||
759 | :mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping, | ||
760 | :regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram, | ||
761 | :d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit, | ||
762 | :f_resent, :f_send_packet | ||
763 | ) | ||
764 | "; | ||
765 | |||
766 | #endregion | ||
767 | |||
768 | } | ||
769 | |||
770 | public static class UserSessionUtil | ||
771 | { | ||
772 | public static UserSessionData newUserSessionData() | ||
773 | { | ||
774 | UserSessionData obj = ZeroSession(new UserSessionData()); | ||
775 | return obj; | ||
776 | } | ||
777 | |||
778 | public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps) | ||
779 | { | ||
780 | // don't insert zero values here or it'll skew the statistics. | ||
781 | if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0) | ||
782 | return; | ||
783 | s._agents_in_view.Add(agents_in_view); | ||
784 | s._fps.Add(fps); | ||
785 | s._sim_fps.Add(sim_fps); | ||
786 | s._ping.Add(ping); | ||
787 | |||
788 | int[] __agents_in_view = s._agents_in_view.ToArray(); | ||
789 | |||
790 | s.avg_agents_in_view = ArrayAvg_i(__agents_in_view); | ||
791 | s.min_agents_in_view = ArrayMin_i(__agents_in_view); | ||
792 | s.max_agents_in_view = ArrayMax_i(__agents_in_view); | ||
793 | s.mode_agents_in_view = ArrayMode_i(__agents_in_view); | ||
794 | |||
795 | float[] __fps = s._fps.ToArray(); | ||
796 | s.avg_fps = ArrayAvg_f(__fps); | ||
797 | s.min_fps = ArrayMin_f(__fps); | ||
798 | s.max_fps = ArrayMax_f(__fps); | ||
799 | s.mode_fps = ArrayMode_f(__fps); | ||
800 | |||
801 | float[] __sim_fps = s._sim_fps.ToArray(); | ||
802 | s.avg_sim_fps = ArrayAvg_f(__sim_fps); | ||
803 | s.min_sim_fps = ArrayMin_f(__sim_fps); | ||
804 | s.max_sim_fps = ArrayMax_f(__sim_fps); | ||
805 | s.mode_sim_fps = ArrayMode_f(__sim_fps); | ||
806 | |||
807 | float[] __ping = s._ping.ToArray(); | ||
808 | s.avg_ping = ArrayAvg_f(__ping); | ||
809 | s.min_ping = ArrayMin_f(__ping); | ||
810 | s.max_ping = ArrayMax_f(__ping); | ||
811 | s.mode_ping = ArrayMode_f(__ping); | ||
812 | } | ||
813 | |||
814 | #region Statistics | ||
815 | |||
816 | public static int ArrayMin_i(int[] arr) | ||
817 | { | ||
818 | int cnt = arr.Length; | ||
819 | if (cnt == 0) | ||
820 | return 0; | ||
821 | |||
822 | Array.Sort(arr); | ||
823 | return arr[0]; | ||
824 | } | ||
825 | |||
826 | public static int ArrayMax_i(int[] arr) | ||
827 | { | ||
828 | int cnt = arr.Length; | ||
829 | if (cnt == 0) | ||
830 | return 0; | ||
831 | |||
832 | Array.Sort(arr); | ||
833 | return arr[cnt-1]; | ||
834 | } | ||
835 | |||
836 | public static float ArrayMin_f(float[] arr) | ||
837 | { | ||
838 | int cnt = arr.Length; | ||
839 | if (cnt == 0) | ||
840 | return 0; | ||
841 | |||
842 | Array.Sort(arr); | ||
843 | return arr[0]; | ||
844 | } | ||
845 | |||
846 | public static float ArrayMax_f(float[] arr) | ||
847 | { | ||
848 | int cnt = arr.Length; | ||
849 | if (cnt == 0) | ||
850 | return 0; | ||
851 | |||
852 | Array.Sort(arr); | ||
853 | return arr[cnt - 1]; | ||
854 | } | ||
855 | |||
856 | public static float ArrayAvg_i(int[] arr) | ||
857 | { | ||
858 | int cnt = arr.Length; | ||
859 | |||
860 | if (cnt == 0) | ||
861 | return 0; | ||
862 | |||
863 | float result = arr[0]; | ||
864 | |||
865 | for (int i = 1; i < cnt; i++) | ||
866 | result += arr[i]; | ||
867 | |||
868 | return result / cnt; | ||
869 | } | ||
870 | |||
871 | public static float ArrayAvg_f(float[] arr) | ||
872 | { | ||
873 | int cnt = arr.Length; | ||
874 | |||
875 | if (cnt == 0) | ||
876 | return 0; | ||
877 | |||
878 | float result = arr[0]; | ||
879 | |||
880 | for (int i = 1; i < cnt; i++) | ||
881 | result += arr[i]; | ||
882 | |||
883 | return result / cnt; | ||
884 | } | ||
885 | |||
886 | public static float ArrayMode_f(float[] arr) | ||
887 | { | ||
888 | List<float> mode = new List<float>(); | ||
889 | |||
890 | float[] srtArr = new float[arr.Length]; | ||
891 | float[,] freq = new float[arr.Length, 2]; | ||
892 | Array.Copy(arr, srtArr, arr.Length); | ||
893 | Array.Sort(srtArr); | ||
894 | |||
895 | float tmp = srtArr[0]; | ||
896 | int index = 0; | ||
897 | int i = 0; | ||
898 | while (i < srtArr.Length) | ||
899 | { | ||
900 | freq[index, 0] = tmp; | ||
901 | |||
902 | while (tmp == srtArr[i]) | ||
903 | { | ||
904 | freq[index, 1]++; | ||
905 | i++; | ||
906 | |||
907 | if (i > srtArr.Length - 1) | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | if (i < srtArr.Length) | ||
912 | { | ||
913 | tmp = srtArr[i]; | ||
914 | index++; | ||
915 | } | ||
916 | |||
917 | } | ||
918 | |||
919 | Array.Clear(srtArr, 0, srtArr.Length); | ||
920 | |||
921 | for (i = 0; i < srtArr.Length; i++) | ||
922 | srtArr[i] = freq[i, 1]; | ||
923 | |||
924 | Array.Sort(srtArr); | ||
925 | |||
926 | if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) | ||
927 | return 0; | ||
928 | |||
929 | float freqtest = (float)freq.Length / freq.Rank; | ||
930 | |||
931 | for (i = 0; i < freqtest; i++) | ||
932 | { | ||
933 | if (freq[i, 1] == srtArr[index]) | ||
934 | mode.Add(freq[i, 0]); | ||
935 | |||
936 | } | ||
937 | |||
938 | return mode.ToArray()[0]; | ||
939 | } | ||
940 | |||
941 | public static int ArrayMode_i(int[] arr) | ||
942 | { | ||
943 | List<int> mode = new List<int>(); | ||
944 | |||
945 | int[] srtArr = new int[arr.Length]; | ||
946 | int[,] freq = new int[arr.Length, 2]; | ||
947 | Array.Copy(arr, srtArr, arr.Length); | ||
948 | Array.Sort(srtArr); | ||
949 | |||
950 | int tmp = srtArr[0]; | ||
951 | int index = 0; | ||
952 | int i = 0; | ||
953 | while (i < srtArr.Length) | ||
954 | { | ||
955 | freq[index, 0] = tmp; | ||
956 | |||
957 | while (tmp == srtArr[i]) | ||
958 | { | ||
959 | freq[index, 1]++; | ||
960 | i++; | ||
961 | |||
962 | if (i > srtArr.Length - 1) | ||
963 | break; | ||
964 | } | ||
965 | |||
966 | if (i < srtArr.Length) | ||
967 | { | ||
968 | tmp = srtArr[i]; | ||
969 | index++; | ||
970 | } | ||
971 | |||
972 | } | ||
973 | |||
974 | Array.Clear(srtArr, 0, srtArr.Length); | ||
975 | |||
976 | for (i = 0; i < srtArr.Length; i++) | ||
977 | srtArr[i] = freq[i, 1]; | ||
978 | |||
979 | Array.Sort(srtArr); | ||
980 | |||
981 | if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1) | ||
982 | return 0; | ||
983 | |||
984 | float freqtest = (float)freq.Length / freq.Rank; | ||
985 | |||
986 | for (i = 0; i < freqtest; i++) | ||
987 | { | ||
988 | if (freq[i, 1] == srtArr[index]) | ||
989 | mode.Add(freq[i, 0]); | ||
990 | |||
991 | } | ||
992 | |||
993 | return mode.ToArray()[0]; | ||
994 | } | ||
995 | |||
996 | #endregion | ||
997 | |||
998 | private static UserSessionData ZeroSession(UserSessionData s) | ||
999 | { | ||
1000 | s.session_id = UUID.Zero; | ||
1001 | s.agent_id = UUID.Zero; | ||
1002 | s.region_id = UUID.Zero; | ||
1003 | s.last_updated = Util.UnixTimeSinceEpoch(); | ||
1004 | s.remote_ip = ""; | ||
1005 | s.name_f = ""; | ||
1006 | s.name_l = ""; | ||
1007 | s.avg_agents_in_view = 0; | ||
1008 | s.min_agents_in_view = 0; | ||
1009 | s.max_agents_in_view = 0; | ||
1010 | s.mode_agents_in_view = 0; | ||
1011 | s.avg_fps = 0; | ||
1012 | s.min_fps = 0; | ||
1013 | s.max_fps = 0; | ||
1014 | s.mode_fps = 0; | ||
1015 | s.a_language = ""; | ||
1016 | s.mem_use = 0; | ||
1017 | s.meters_traveled = 0; | ||
1018 | s.avg_ping = 0; | ||
1019 | s.min_ping = 0; | ||
1020 | s.max_ping = 0; | ||
1021 | s.mode_ping = 0; | ||
1022 | s.regions_visited = 0; | ||
1023 | s.run_time = 0; | ||
1024 | s.avg_sim_fps = 0; | ||
1025 | s.min_sim_fps = 0; | ||
1026 | s.max_sim_fps = 0; | ||
1027 | s.mode_sim_fps = 0; | ||
1028 | s.start_time = 0; | ||
1029 | s.client_version = ""; | ||
1030 | s.s_cpu = ""; | ||
1031 | s.s_gpu = ""; | ||
1032 | s.s_os = ""; | ||
1033 | s.s_ram = 0; | ||
1034 | s.d_object_kb = 0; | ||
1035 | s.d_texture_kb = 0; | ||
1036 | s.d_world_kb = 0; | ||
1037 | s.n_in_kb = 0; | ||
1038 | s.n_in_pk = 0; | ||
1039 | s.n_out_kb = 0; | ||
1040 | s.n_out_pk = 0; | ||
1041 | s.f_dropped = 0; | ||
1042 | s.f_failed_resends = 0; | ||
1043 | s.f_invalid = 0; | ||
1044 | s.f_off_circuit = 0; | ||
1045 | s.f_resent = 0; | ||
1046 | s.f_send_packet = 0; | ||
1047 | s._ping = new List<float>(); | ||
1048 | s._fps = new List<float>(); | ||
1049 | s._sim_fps = new List<float>(); | ||
1050 | s._agents_in_view = new List<int>(); | ||
1051 | return s; | ||
1052 | } | ||
1053 | } | ||
1054 | #region structs | ||
1055 | |||
1056 | public class UserSession | ||
1057 | { | ||
1058 | public UUID session_id; | ||
1059 | public UUID region_id; | ||
1060 | public string name_f; | ||
1061 | public string name_l; | ||
1062 | public UserSessionData session_data; | ||
1063 | } | ||
1064 | |||
1065 | public struct UserSessionData | ||
1066 | { | ||
1067 | public UUID session_id; | ||
1068 | public UUID agent_id; | ||
1069 | public UUID region_id; | ||
1070 | public float last_updated; | ||
1071 | public string remote_ip; | ||
1072 | public string name_f; | ||
1073 | public string name_l; | ||
1074 | public float avg_agents_in_view; | ||
1075 | public float min_agents_in_view; | ||
1076 | public float max_agents_in_view; | ||
1077 | public float mode_agents_in_view; | ||
1078 | public float avg_fps; | ||
1079 | public float min_fps; | ||
1080 | public float max_fps; | ||
1081 | public float mode_fps; | ||
1082 | public string a_language; | ||
1083 | public float mem_use; | ||
1084 | public float meters_traveled; | ||
1085 | public float avg_ping; | ||
1086 | public float min_ping; | ||
1087 | public float max_ping; | ||
1088 | public float mode_ping; | ||
1089 | public int regions_visited; | ||
1090 | public float run_time; | ||
1091 | public float avg_sim_fps; | ||
1092 | public float min_sim_fps; | ||
1093 | public float max_sim_fps; | ||
1094 | public float mode_sim_fps; | ||
1095 | public float start_time; | ||
1096 | public string client_version; | ||
1097 | public string s_cpu; | ||
1098 | public string s_gpu; | ||
1099 | public string s_os; | ||
1100 | public int s_ram; | ||
1101 | public float d_object_kb; | ||
1102 | public float d_texture_kb; | ||
1103 | public float d_world_kb; | ||
1104 | public float n_in_kb; | ||
1105 | public int n_in_pk; | ||
1106 | public float n_out_kb; | ||
1107 | public int n_out_pk; | ||
1108 | public int f_dropped; | ||
1109 | public int f_failed_resends; | ||
1110 | public int f_invalid; | ||
1111 | public int f_off_circuit; | ||
1112 | public int f_resent; | ||
1113 | public int f_send_packet; | ||
1114 | public List<float> _ping; | ||
1115 | public List<float> _fps; | ||
1116 | public List<float> _sim_fps; | ||
1117 | public List<int> _agents_in_view; | ||
1118 | } | ||
1119 | |||
1120 | #endregion | ||
1121 | |||
1122 | public class USimStatsData | ||
1123 | { | ||
1124 | private UUID m_regionID = UUID.Zero; | ||
1125 | private volatile int m_statcounter = 0; | ||
1126 | private volatile float m_timeDilation; | ||
1127 | private volatile float m_simFps; | ||
1128 | private volatile float m_physicsFps; | ||
1129 | private volatile float m_agentUpdates; | ||
1130 | private volatile float m_rootAgents; | ||
1131 | private volatile float m_childAgents; | ||
1132 | private volatile float m_totalPrims; | ||
1133 | private volatile float m_activePrims; | ||
1134 | private volatile float m_totalFrameTime; | ||
1135 | private volatile float m_netFrameTime; | ||
1136 | private volatile float m_physicsFrameTime; | ||
1137 | private volatile float m_otherFrameTime; | ||
1138 | private volatile float m_imageFrameTime; | ||
1139 | private volatile float m_inPacketsPerSecond; | ||
1140 | private volatile float m_outPacketsPerSecond; | ||
1141 | private volatile float m_unackedBytes; | ||
1142 | private volatile float m_agentFrameTime; | ||
1143 | private volatile float m_pendingDownloads; | ||
1144 | private volatile float m_pendingUploads; | ||
1145 | private volatile float m_activeScripts; | ||
1146 | private volatile float m_scriptLinesPerSecond; | ||
1147 | |||
1148 | public UUID RegionId { get { return m_regionID; } } | ||
1149 | public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}} | ||
1150 | public float TimeDilation { get { return m_timeDilation; } } | ||
1151 | public float SimFps { get { return m_simFps; } } | ||
1152 | public float PhysicsFps { get { return m_physicsFps; } } | ||
1153 | public float AgentUpdates { get { return m_agentUpdates; } } | ||
1154 | public float RootAgents { get { return m_rootAgents; } } | ||
1155 | public float ChildAgents { get { return m_childAgents; } } | ||
1156 | public float TotalPrims { get { return m_totalPrims; } } | ||
1157 | public float ActivePrims { get { return m_activePrims; } } | ||
1158 | public float TotalFrameTime { get { return m_totalFrameTime; } } | ||
1159 | public float NetFrameTime { get { return m_netFrameTime; } } | ||
1160 | public float PhysicsFrameTime { get { return m_physicsFrameTime; } } | ||
1161 | public float OtherFrameTime { get { return m_otherFrameTime; } } | ||
1162 | public float ImageFrameTime { get { return m_imageFrameTime; } } | ||
1163 | public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } } | ||
1164 | public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } } | ||
1165 | public float UnackedBytes { get { return m_unackedBytes; } } | ||
1166 | public float AgentFrameTime { get { return m_agentFrameTime; } } | ||
1167 | public float PendingDownloads { get { return m_pendingDownloads; } } | ||
1168 | public float PendingUploads { get { return m_pendingUploads; } } | ||
1169 | public float ActiveScripts { get { return m_activeScripts; } } | ||
1170 | public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } } | ||
1171 | |||
1172 | public USimStatsData(UUID pRegionID) | ||
1173 | { | ||
1174 | m_regionID = pRegionID; | ||
1175 | } | ||
1176 | |||
1177 | public void ConsumeSimStats(SimStats stats) | ||
1178 | { | ||
1179 | m_regionID = stats.RegionUUID; | ||
1180 | m_timeDilation = stats.StatsBlock[0].StatValue; | ||
1181 | m_simFps = stats.StatsBlock[1].StatValue; | ||
1182 | m_physicsFps = stats.StatsBlock[2].StatValue; | ||
1183 | m_agentUpdates = stats.StatsBlock[3].StatValue; | ||
1184 | m_rootAgents = stats.StatsBlock[4].StatValue; | ||
1185 | m_childAgents = stats.StatsBlock[5].StatValue; | ||
1186 | m_totalPrims = stats.StatsBlock[6].StatValue; | ||
1187 | m_activePrims = stats.StatsBlock[7].StatValue; | ||
1188 | m_totalFrameTime = stats.StatsBlock[8].StatValue; | ||
1189 | m_netFrameTime = stats.StatsBlock[9].StatValue; | ||
1190 | m_physicsFrameTime = stats.StatsBlock[10].StatValue; | ||
1191 | m_otherFrameTime = stats.StatsBlock[11].StatValue; | ||
1192 | m_imageFrameTime = stats.StatsBlock[12].StatValue; | ||
1193 | m_inPacketsPerSecond = stats.StatsBlock[13].StatValue; | ||
1194 | m_outPacketsPerSecond = stats.StatsBlock[14].StatValue; | ||
1195 | m_unackedBytes = stats.StatsBlock[15].StatValue; | ||
1196 | m_agentFrameTime = stats.StatsBlock[16].StatValue; | ||
1197 | m_pendingDownloads = stats.StatsBlock[17].StatValue; | ||
1198 | m_pendingUploads = stats.StatsBlock[18].StatValue; | ||
1199 | m_activeScripts = stats.StatsBlock[19].StatValue; | ||
1200 | m_scriptLinesPerSecond = stats.ExtraStatsBlock[0].StatValue; | ||
1201 | } | ||
1202 | } | ||
1203 | } \ No newline at end of file | ||