aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs')
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs1203
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..bcb6361
--- /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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net; // to be used for REST-->Grid shortly
33using System.Reflection;
34using System.Text;
35using System.Threading;
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using Mono.Data.SqliteClient;
46using Mono.Addins;
47
48using Caps = OpenSim.Framework.Capabilities.Caps;
49
50using OSD = OpenMetaverse.StructuredData.OSD;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace 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 (
750session_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,
751mode_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,
752regions_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,
753d_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,
754f_resent, f_send_packet
755)
756VALUES
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.StatsBlock[20].StatValue;
1201 }
1202 }
1203} \ No newline at end of file