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