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 | |
parent | add lost admin_reset_land method (diff) | |
parent | Deleted access control spec from [LoginService] section of standalone config.... (diff) | |
download | opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2 opensim-SC_OLD-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')
11 files changed, 3292 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs new file mode 100644 index 0000000..6a1112c --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs | |||
@@ -0,0 +1,308 @@ | |||
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.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Monitoring; | ||
39 | |||
40 | namespace OpenSim.Region.UserStatistics | ||
41 | { | ||
42 | public class ActiveConnectionsAJAX : IStatsController | ||
43 | { | ||
44 | private Vector3 DefaultNeighborPosition = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 70); | ||
45 | |||
46 | #region IStatsController Members | ||
47 | |||
48 | public string ReportName | ||
49 | { | ||
50 | get { return ""; } | ||
51 | } | ||
52 | |||
53 | public Hashtable ProcessModel(Hashtable pParams) | ||
54 | { | ||
55 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
56 | |||
57 | Hashtable nh = new Hashtable(); | ||
58 | nh.Add("hdata", m_scene); | ||
59 | |||
60 | return nh; | ||
61 | } | ||
62 | |||
63 | public string RenderView(Hashtable pModelResult) | ||
64 | { | ||
65 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
66 | |||
67 | StringBuilder output = new StringBuilder(); | ||
68 | HTMLUtil.OL_O(ref output, ""); | ||
69 | foreach (Scene scene in all_scenes) | ||
70 | { | ||
71 | HTMLUtil.LI_O(ref output, String.Empty); | ||
72 | output.Append(scene.RegionInfo.RegionName); | ||
73 | HTMLUtil.OL_O(ref output, String.Empty); | ||
74 | scene.ForEachScenePresence(delegate(ScenePresence av) | ||
75 | { | ||
76 | Dictionary<string, string> queues = new Dictionary<string, string>(); | ||
77 | if (av.ControllingClient is IStatsCollector) | ||
78 | { | ||
79 | IStatsCollector isClient = (IStatsCollector)av.ControllingClient; | ||
80 | queues = decodeQueueReport(isClient.Report()); | ||
81 | } | ||
82 | HTMLUtil.LI_O(ref output, String.Empty); | ||
83 | output.Append(av.Name); | ||
84 | output.Append(" "); | ||
85 | output.Append((av.IsChildAgent ? "Child" : "Root")); | ||
86 | if (av.AbsolutePosition == DefaultNeighborPosition) | ||
87 | { | ||
88 | output.Append("<br />Position: ?"); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | output.Append(string.Format("<br /><NOBR>Position: <{0},{1},{2}></NOBR>", (int)av.AbsolutePosition.X, | ||
93 | (int)av.AbsolutePosition.Y, | ||
94 | (int)av.AbsolutePosition.Z)); | ||
95 | } | ||
96 | Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1)); | ||
97 | |||
98 | HTMLUtil.UL_O(ref output, String.Empty); | ||
99 | |||
100 | foreach (string throttlename in throttles.Keys) | ||
101 | { | ||
102 | HTMLUtil.LI_O(ref output, String.Empty); | ||
103 | output.Append(throttlename); | ||
104 | output.Append(":"); | ||
105 | output.Append(throttles[throttlename].ToString()); | ||
106 | if (queues.ContainsKey(throttlename)) | ||
107 | { | ||
108 | output.Append("/"); | ||
109 | output.Append(queues[throttlename]); | ||
110 | } | ||
111 | HTMLUtil.LI_C(ref output); | ||
112 | } | ||
113 | if (queues.ContainsKey("Incoming") && queues.ContainsKey("Outgoing")) | ||
114 | { | ||
115 | HTMLUtil.LI_O(ref output, "red"); | ||
116 | output.Append("SEND:"); | ||
117 | output.Append(queues["Outgoing"]); | ||
118 | output.Append("/"); | ||
119 | output.Append(queues["Incoming"]); | ||
120 | HTMLUtil.LI_C(ref output); | ||
121 | } | ||
122 | |||
123 | HTMLUtil.UL_C(ref output); | ||
124 | HTMLUtil.LI_C(ref output); | ||
125 | }); | ||
126 | HTMLUtil.OL_C(ref output); | ||
127 | } | ||
128 | HTMLUtil.OL_C(ref output); | ||
129 | return output.ToString(); | ||
130 | } | ||
131 | |||
132 | /// <summary> | ||
133 | /// Convert active connections information to JSON string. Returns a structure: | ||
134 | /// <pre> | ||
135 | /// {"regionName": { | ||
136 | /// "presenceName": { | ||
137 | /// "name": "presenceName", | ||
138 | /// "position": "<x,y,z>", | ||
139 | /// "isRoot": "false", | ||
140 | /// "throttle": { | ||
141 | /// }, | ||
142 | /// "queue": { | ||
143 | /// } | ||
144 | /// }, | ||
145 | /// ... // multiple presences in the scene | ||
146 | /// }, | ||
147 | /// ... // multiple regions in the sim | ||
148 | /// } | ||
149 | /// | ||
150 | /// </pre> | ||
151 | /// </summary> | ||
152 | /// <param name="pModelResult"></param> | ||
153 | /// <returns></returns> | ||
154 | public string RenderJson(Hashtable pModelResult) | ||
155 | { | ||
156 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
157 | |||
158 | OSDMap regionInfo = new OSDMap(); | ||
159 | foreach (Scene scene in all_scenes) | ||
160 | { | ||
161 | OSDMap sceneInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
162 | List<ScenePresence> avatarInScene = scene.GetScenePresences(); | ||
163 | foreach (ScenePresence av in avatarInScene) | ||
164 | { | ||
165 | OSDMap presenceInfo = new OSDMap(); | ||
166 | presenceInfo.Add("Name", new OSDString(av.Name)); | ||
167 | |||
168 | Dictionary<string,string> queues = new Dictionary<string, string>(); | ||
169 | if (av.ControllingClient is IStatsCollector) | ||
170 | { | ||
171 | IStatsCollector isClient = (IStatsCollector) av.ControllingClient; | ||
172 | queues = decodeQueueReport(isClient.Report()); | ||
173 | } | ||
174 | OSDMap queueInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
175 | foreach (KeyValuePair<string, string> kvp in queues) { | ||
176 | queueInfo.Add(kvp.Key, new OSDString(kvp.Value)); | ||
177 | } | ||
178 | sceneInfo.Add("queues", queueInfo); | ||
179 | |||
180 | if (av.IsChildAgent) | ||
181 | presenceInfo.Add("isRoot", new OSDString("false")); | ||
182 | else | ||
183 | presenceInfo.Add("isRoot", new OSDString("true")); | ||
184 | |||
185 | if (av.AbsolutePosition == DefaultNeighborPosition) | ||
186 | { | ||
187 | presenceInfo.Add("position", new OSDString("<0, 0, 0>")); | ||
188 | } | ||
189 | else | ||
190 | { | ||
191 | presenceInfo.Add("position", new OSDString(string.Format("<{0},{1},{2}>", | ||
192 | (int)av.AbsolutePosition.X, | ||
193 | (int) av.AbsolutePosition.Y, | ||
194 | (int) av.AbsolutePosition.Z)) ); | ||
195 | } | ||
196 | |||
197 | Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1)); | ||
198 | OSDMap throttleInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
199 | foreach (string throttlename in throttles.Keys) | ||
200 | { | ||
201 | throttleInfo.Add(throttlename, new OSDString(throttles[throttlename].ToString())); | ||
202 | } | ||
203 | presenceInfo.Add("throttle", throttleInfo); | ||
204 | |||
205 | sceneInfo.Add(av.Name, presenceInfo); | ||
206 | } | ||
207 | regionInfo.Add(scene.RegionInfo.RegionName, sceneInfo); | ||
208 | } | ||
209 | return regionInfo.ToString(); | ||
210 | } | ||
211 | |||
212 | public Dictionary<string, int> DecodeClientThrottles(byte[] throttle) | ||
213 | { | ||
214 | Dictionary<string, int> returndict = new Dictionary<string, int>(); | ||
215 | // From mantis http://opensimulator.org/mantis/view.php?id=1374 | ||
216 | // it appears that sometimes we are receiving empty throttle byte arrays. | ||
217 | // TODO: Investigate this behaviour | ||
218 | if (throttle.Length == 0) | ||
219 | { | ||
220 | return new Dictionary<string, int>(); | ||
221 | } | ||
222 | |||
223 | int tResend = -1; | ||
224 | int tLand = -1; | ||
225 | int tWind = -1; | ||
226 | int tCloud = -1; | ||
227 | int tTask = -1; | ||
228 | int tTexture = -1; | ||
229 | int tAsset = -1; | ||
230 | int tall = -1; | ||
231 | const int singlefloat = 4; | ||
232 | |||
233 | //Agent Throttle Block contains 7 single floatingpoint values. | ||
234 | int j = 0; | ||
235 | |||
236 | // Some Systems may be big endian... | ||
237 | // it might be smart to do this check more often... | ||
238 | if (!BitConverter.IsLittleEndian) | ||
239 | for (int i = 0; i < 7; i++) | ||
240 | Array.Reverse(throttle, j + i * singlefloat, singlefloat); | ||
241 | |||
242 | // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_ | ||
243 | // bytes | ||
244 | // Convert to integer, since.. the full fp space isn't used. | ||
245 | tResend = (int)BitConverter.ToSingle(throttle, j); | ||
246 | returndict.Add("Resend", tResend); | ||
247 | j += singlefloat; | ||
248 | tLand = (int)BitConverter.ToSingle(throttle, j); | ||
249 | returndict.Add("Land", tLand); | ||
250 | j += singlefloat; | ||
251 | tWind = (int)BitConverter.ToSingle(throttle, j); | ||
252 | returndict.Add("Wind", tWind); | ||
253 | j += singlefloat; | ||
254 | tCloud = (int)BitConverter.ToSingle(throttle, j); | ||
255 | returndict.Add("Cloud", tCloud); | ||
256 | j += singlefloat; | ||
257 | tTask = (int)BitConverter.ToSingle(throttle, j); | ||
258 | returndict.Add("Task", tTask); | ||
259 | j += singlefloat; | ||
260 | tTexture = (int)BitConverter.ToSingle(throttle, j); | ||
261 | returndict.Add("Texture", tTexture); | ||
262 | j += singlefloat; | ||
263 | tAsset = (int)BitConverter.ToSingle(throttle, j); | ||
264 | returndict.Add("Asset", tAsset); | ||
265 | |||
266 | tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; | ||
267 | returndict.Add("All", tall); | ||
268 | |||
269 | return returndict; | ||
270 | } | ||
271 | public Dictionary<string,string> decodeQueueReport(string rep) | ||
272 | { | ||
273 | Dictionary<string, string> returndic = new Dictionary<string, string>(); | ||
274 | if (rep.Length == 79) | ||
275 | { | ||
276 | int pos = 1; | ||
277 | returndic.Add("All", rep.Substring((6 * pos), 8)); pos++; | ||
278 | returndic.Add("Incoming", rep.Substring((7 * pos), 8)); pos++; | ||
279 | returndic.Add("Outgoing", rep.Substring((7 * pos) , 8)); pos++; | ||
280 | returndic.Add("Resend", rep.Substring((7 * pos) , 8)); pos++; | ||
281 | returndic.Add("Land", rep.Substring((7 * pos) , 8)); pos++; | ||
282 | returndic.Add("Wind", rep.Substring((7 * pos) , 8)); pos++; | ||
283 | returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++; | ||
284 | returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++; | ||
285 | returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++; | ||
286 | returndic.Add("Asset", rep.Substring((7 * pos), 8)); | ||
287 | /* | ||
288 | * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", | ||
289 | SendQueue.Count(), | ||
290 | IncomingPacketQueue.Count, | ||
291 | OutgoingPacketQueue.Count, | ||
292 | ResendOutgoingPacketQueue.Count, | ||
293 | LandOutgoingPacketQueue.Count, | ||
294 | WindOutgoingPacketQueue.Count, | ||
295 | CloudOutgoingPacketQueue.Count, | ||
296 | TaskOutgoingPacketQueue.Count, | ||
297 | TextureOutgoingPacketQueue.Count, | ||
298 | AssetOutgoingPacketQueue.Count); | ||
299 | */ | ||
300 | } | ||
301 | |||
302 | |||
303 | |||
304 | return returndic; | ||
305 | } | ||
306 | #endregion | ||
307 | } | ||
308 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs new file mode 100644 index 0000000..4a6f7be --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs | |||
@@ -0,0 +1,329 @@ | |||
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.Text; | ||
32 | using Mono.Data.SqliteClient; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | |||
37 | namespace OpenSim.Region.UserStatistics | ||
38 | { | ||
39 | public class Clients_report : IStatsController | ||
40 | { | ||
41 | #region IStatsController Members | ||
42 | |||
43 | public string ReportName | ||
44 | { | ||
45 | get { return "Client"; } | ||
46 | } | ||
47 | |||
48 | /// <summary> | ||
49 | /// Return summar information in the form: | ||
50 | /// <pre> | ||
51 | /// {"totalUsers": "34", | ||
52 | /// "totalSessions": "233", | ||
53 | /// ... | ||
54 | /// } | ||
55 | /// </pre> | ||
56 | /// </summary> | ||
57 | /// <param name="pModelResult"></param> | ||
58 | /// <returns></returns> | ||
59 | public string RenderJson(Hashtable pModelResult) { | ||
60 | stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"]; | ||
61 | |||
62 | OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
63 | summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString())); | ||
64 | summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString())); | ||
65 | summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString())); | ||
66 | summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString())); | ||
67 | summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString())); | ||
68 | summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString())); | ||
69 | summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString())); | ||
70 | summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString())); | ||
71 | return summaryInfo.ToString(); | ||
72 | } | ||
73 | |||
74 | public Hashtable ProcessModel(Hashtable pParams) | ||
75 | { | ||
76 | SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; | ||
77 | |||
78 | |||
79 | List<ClientVersionData> clidata = new List<ClientVersionData>(); | ||
80 | List<ClientVersionData> cliRegData = new List<ClientVersionData>(); | ||
81 | Hashtable regionTotals = new Hashtable(); | ||
82 | |||
83 | Hashtable modeldata = new Hashtable(); | ||
84 | modeldata.Add("Scenes", pParams["Scenes"]); | ||
85 | modeldata.Add("Reports", pParams["Reports"]); | ||
86 | int totalclients = 0; | ||
87 | int totalregions = 0; | ||
88 | |||
89 | lock (dbConn) | ||
90 | { | ||
91 | string sql = "select count(distinct region_id) as regcnt from stats_session_data"; | ||
92 | |||
93 | SqliteCommand cmd = new SqliteCommand(sql, dbConn); | ||
94 | SqliteDataReader sdr = cmd.ExecuteReader(); | ||
95 | if (sdr.HasRows) | ||
96 | { | ||
97 | sdr.Read(); | ||
98 | totalregions = Convert.ToInt32(sdr["regcnt"]); | ||
99 | } | ||
100 | |||
101 | sdr.Close(); | ||
102 | sdr.Dispose(); | ||
103 | |||
104 | sql = | ||
105 | "select client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by client_version order by count(*) desc LIMIT 10;"; | ||
106 | |||
107 | cmd = new SqliteCommand(sql, dbConn); | ||
108 | sdr = cmd.ExecuteReader(); | ||
109 | if (sdr.HasRows) | ||
110 | { | ||
111 | while (sdr.Read()) | ||
112 | { | ||
113 | ClientVersionData udata = new ClientVersionData(); | ||
114 | udata.version = sdr["client_version"].ToString(); | ||
115 | udata.count = Convert.ToInt32(sdr["cnt"]); | ||
116 | udata.fps = Convert.ToSingle(sdr["simfps"]); | ||
117 | clidata.Add(udata); | ||
118 | totalclients += udata.count; | ||
119 | |||
120 | } | ||
121 | } | ||
122 | sdr.Close(); | ||
123 | sdr.Dispose(); | ||
124 | |||
125 | if (totalregions > 1) | ||
126 | { | ||
127 | sql = | ||
128 | "select region_id, client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by region_id, client_version order by region_id, count(*) desc;"; | ||
129 | cmd = new SqliteCommand(sql, dbConn); | ||
130 | |||
131 | sdr = cmd.ExecuteReader(); | ||
132 | |||
133 | if (sdr.HasRows) | ||
134 | { | ||
135 | while (sdr.Read()) | ||
136 | { | ||
137 | ClientVersionData udata = new ClientVersionData(); | ||
138 | udata.version = sdr["client_version"].ToString(); | ||
139 | udata.count = Convert.ToInt32(sdr["cnt"]); | ||
140 | udata.fps = Convert.ToSingle(sdr["simfps"]); | ||
141 | udata.region_id = UUID.Parse(sdr["region_id"].ToString()); | ||
142 | cliRegData.Add(udata); | ||
143 | } | ||
144 | } | ||
145 | sdr.Close(); | ||
146 | sdr.Dispose(); | ||
147 | |||
148 | |||
149 | } | ||
150 | |||
151 | } | ||
152 | |||
153 | foreach (ClientVersionData cvd in cliRegData) | ||
154 | { | ||
155 | |||
156 | if (regionTotals.ContainsKey(cvd.region_id)) | ||
157 | { | ||
158 | int regiontotal = (int)regionTotals[cvd.region_id]; | ||
159 | regiontotal += cvd.count; | ||
160 | regionTotals[cvd.region_id] = regiontotal; | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | regionTotals.Add(cvd.region_id, cvd.count); | ||
165 | } | ||
166 | |||
167 | |||
168 | |||
169 | } | ||
170 | |||
171 | modeldata["ClientData"] = clidata; | ||
172 | modeldata["ClientRegionData"] = cliRegData; | ||
173 | modeldata["RegionTotals"] = regionTotals; | ||
174 | modeldata["Total"] = totalclients; | ||
175 | |||
176 | return modeldata; | ||
177 | } | ||
178 | |||
179 | public string RenderView(Hashtable pModelResult) | ||
180 | { | ||
181 | List<ClientVersionData> clidata = (List<ClientVersionData>) pModelResult["ClientData"]; | ||
182 | int totalclients = (int)pModelResult["Total"]; | ||
183 | Hashtable regionTotals = (Hashtable) pModelResult["RegionTotals"]; | ||
184 | List<ClientVersionData> cliRegData = (List<ClientVersionData>) pModelResult["ClientRegionData"]; | ||
185 | List<Scene> m_scenes = (List<Scene>)pModelResult["Scenes"]; | ||
186 | Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"]; | ||
187 | |||
188 | const string STYLESHEET = | ||
189 | @" | ||
190 | <STYLE> | ||
191 | body | ||
192 | { | ||
193 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
194 | } | ||
195 | TABLE.defaultr { } | ||
196 | TR.defaultr { padding: 5px; } | ||
197 | TD.header { font-weight:bold; padding:5px; } | ||
198 | TD.content {} | ||
199 | TD.contentright { text-align: right; } | ||
200 | TD.contentcenter { text-align: center; } | ||
201 | TD.align_top { vertical-align: top; } | ||
202 | </STYLE> | ||
203 | "; | ||
204 | |||
205 | StringBuilder output = new StringBuilder(); | ||
206 | HTMLUtil.HtmlHeaders_O(ref output); | ||
207 | output.Append(STYLESHEET); | ||
208 | HTMLUtil.HtmlHeaders_C(ref output); | ||
209 | |||
210 | HTMLUtil.AddReportLinks(ref output, reports, ""); | ||
211 | |||
212 | HTMLUtil.TABLE_O(ref output, "defaultr"); | ||
213 | HTMLUtil.TR_O(ref output, ""); | ||
214 | HTMLUtil.TD_O(ref output, "header"); | ||
215 | output.Append("ClientVersion"); | ||
216 | HTMLUtil.TD_C(ref output); | ||
217 | HTMLUtil.TD_O(ref output, "header"); | ||
218 | output.Append("Count/%"); | ||
219 | HTMLUtil.TD_C(ref output); | ||
220 | HTMLUtil.TD_O(ref output, "header"); | ||
221 | output.Append("SimFPS"); | ||
222 | HTMLUtil.TD_C(ref output); | ||
223 | HTMLUtil.TR_C(ref output); | ||
224 | |||
225 | foreach (ClientVersionData cvd in clidata) | ||
226 | { | ||
227 | HTMLUtil.TR_O(ref output, ""); | ||
228 | HTMLUtil.TD_O(ref output, "content"); | ||
229 | string linkhref = "sessions.report?VersionString=" + cvd.version; | ||
230 | HTMLUtil.A(ref output, cvd.version, linkhref, ""); | ||
231 | HTMLUtil.TD_C(ref output); | ||
232 | HTMLUtil.TD_O(ref output, "content"); | ||
233 | output.Append(cvd.count); | ||
234 | output.Append("/"); | ||
235 | if (totalclients > 0) | ||
236 | output.Append((((float)cvd.count / (float)totalclients)*100).ToString()); | ||
237 | else | ||
238 | output.Append(0); | ||
239 | |||
240 | output.Append("%"); | ||
241 | HTMLUtil.TD_C(ref output); | ||
242 | HTMLUtil.TD_O(ref output, "content"); | ||
243 | output.Append(cvd.fps); | ||
244 | HTMLUtil.TD_C(ref output); | ||
245 | HTMLUtil.TR_C(ref output); | ||
246 | } | ||
247 | HTMLUtil.TABLE_C(ref output); | ||
248 | |||
249 | if (cliRegData.Count > 0) | ||
250 | { | ||
251 | HTMLUtil.TABLE_O(ref output, "defaultr"); | ||
252 | HTMLUtil.TR_O(ref output, ""); | ||
253 | HTMLUtil.TD_O(ref output, "header"); | ||
254 | output.Append("Region"); | ||
255 | HTMLUtil.TD_C(ref output); | ||
256 | HTMLUtil.TD_O(ref output, "header"); | ||
257 | output.Append("ClientVersion"); | ||
258 | HTMLUtil.TD_C(ref output); | ||
259 | HTMLUtil.TD_O(ref output, "header"); | ||
260 | output.Append("Count/%"); | ||
261 | HTMLUtil.TD_C(ref output); | ||
262 | HTMLUtil.TD_O(ref output, "header"); | ||
263 | output.Append("SimFPS"); | ||
264 | HTMLUtil.TD_C(ref output); | ||
265 | HTMLUtil.TR_C(ref output); | ||
266 | |||
267 | foreach (ClientVersionData cvd in cliRegData) | ||
268 | { | ||
269 | HTMLUtil.TR_O(ref output, ""); | ||
270 | HTMLUtil.TD_O(ref output, "content"); | ||
271 | output.Append(regionNamefromUUID(m_scenes, cvd.region_id)); | ||
272 | HTMLUtil.TD_C(ref output); | ||
273 | HTMLUtil.TD_O(ref output, "content"); | ||
274 | output.Append(cvd.version); | ||
275 | HTMLUtil.TD_C(ref output); | ||
276 | HTMLUtil.TD_O(ref output, "content"); | ||
277 | output.Append(cvd.count); | ||
278 | output.Append("/"); | ||
279 | if ((int)regionTotals[cvd.region_id] > 0) | ||
280 | output.Append((((float)cvd.count / (float)((int)regionTotals[cvd.region_id])) * 100).ToString()); | ||
281 | else | ||
282 | output.Append(0); | ||
283 | |||
284 | output.Append("%"); | ||
285 | HTMLUtil.TD_C(ref output); | ||
286 | HTMLUtil.TD_O(ref output, "content"); | ||
287 | output.Append(cvd.fps); | ||
288 | HTMLUtil.TD_C(ref output); | ||
289 | HTMLUtil.TR_C(ref output); | ||
290 | } | ||
291 | HTMLUtil.TABLE_C(ref output); | ||
292 | |||
293 | } | ||
294 | |||
295 | output.Append("</BODY>"); | ||
296 | output.Append("</HTML>"); | ||
297 | return output.ToString(); | ||
298 | } | ||
299 | public string regionNamefromUUID(List<Scene> scenes, UUID region_id) | ||
300 | { | ||
301 | string returnstring = string.Empty; | ||
302 | foreach (Scene sn in scenes) | ||
303 | { | ||
304 | if (region_id == sn.RegionInfo.originRegionID) | ||
305 | { | ||
306 | returnstring = sn.RegionInfo.RegionName; | ||
307 | break; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | if (returnstring.Length == 0) | ||
312 | { | ||
313 | returnstring = region_id.ToString(); | ||
314 | } | ||
315 | |||
316 | return returnstring; | ||
317 | } | ||
318 | |||
319 | #endregion | ||
320 | } | ||
321 | |||
322 | public struct ClientVersionData | ||
323 | { | ||
324 | public UUID region_id; | ||
325 | public string version; | ||
326 | public int count; | ||
327 | public float fps; | ||
328 | } | ||
329 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs new file mode 100644 index 0000000..fabe3d4 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs | |||
@@ -0,0 +1,277 @@ | |||
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.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Framework.Monitoring; | ||
38 | |||
39 | |||
40 | namespace OpenSim.Region.UserStatistics | ||
41 | { | ||
42 | public class Default_Report : IStatsController | ||
43 | { | ||
44 | |||
45 | public string ReportName | ||
46 | { | ||
47 | get { return "Home"; } | ||
48 | } | ||
49 | |||
50 | #region IStatsController Members | ||
51 | |||
52 | public Hashtable ProcessModel(Hashtable pParams) | ||
53 | { | ||
54 | SqliteConnection conn = (SqliteConnection)pParams["DatabaseConnection"]; | ||
55 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
56 | |||
57 | stats_default_page_values mData = rep_DefaultReport_data(conn, m_scene); | ||
58 | mData.sim_stat_data = (Dictionary<UUID,USimStatsData>)pParams["SimStats"]; | ||
59 | mData.stats_reports = (Dictionary<string, IStatsController>) pParams["Reports"]; | ||
60 | |||
61 | Hashtable nh = new Hashtable(); | ||
62 | nh.Add("hdata", mData); | ||
63 | nh.Add("Reports", pParams["Reports"]); | ||
64 | |||
65 | return nh; | ||
66 | } | ||
67 | |||
68 | public string RenderView(Hashtable pModelResult) | ||
69 | { | ||
70 | stats_default_page_values mData = (stats_default_page_values) pModelResult["hdata"]; | ||
71 | return rep_Default_report_view(mData); | ||
72 | } | ||
73 | |||
74 | #endregion | ||
75 | |||
76 | public string rep_Default_report_view(stats_default_page_values values) | ||
77 | { | ||
78 | |||
79 | |||
80 | StringBuilder output = new StringBuilder(); | ||
81 | |||
82 | |||
83 | |||
84 | const string TableClass = "defaultr"; | ||
85 | const string TRClass = "defaultr"; | ||
86 | const string TDHeaderClass = "header"; | ||
87 | const string TDDataClass = "content"; | ||
88 | //const string TDDataClassRight = "contentright"; | ||
89 | const string TDDataClassCenter = "contentcenter"; | ||
90 | |||
91 | const string STYLESHEET = | ||
92 | @" | ||
93 | <STYLE> | ||
94 | body | ||
95 | { | ||
96 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
97 | } | ||
98 | TABLE.defaultr { } | ||
99 | TR.defaultr { padding: 5px; } | ||
100 | TD.header { font-weight:bold; padding:5px; } | ||
101 | TD.content {} | ||
102 | TD.contentright { text-align: right; } | ||
103 | TD.contentcenter { text-align: center; } | ||
104 | TD.align_top { vertical-align: top; } | ||
105 | </STYLE> | ||
106 | "; | ||
107 | HTMLUtil.HtmlHeaders_O(ref output); | ||
108 | |||
109 | HTMLUtil.InsertProtoTypeAJAX(ref output); | ||
110 | string[] ajaxUpdaterDivs = new string[3]; | ||
111 | int[] ajaxUpdaterSeconds = new int[3]; | ||
112 | string[] ajaxUpdaterReportFragments = new string[3]; | ||
113 | |||
114 | ajaxUpdaterDivs[0] = "activeconnections"; | ||
115 | ajaxUpdaterSeconds[0] = 10; | ||
116 | ajaxUpdaterReportFragments[0] = "activeconnectionsajax.html"; | ||
117 | |||
118 | ajaxUpdaterDivs[1] = "activesimstats"; | ||
119 | ajaxUpdaterSeconds[1] = 20; | ||
120 | ajaxUpdaterReportFragments[1] = "simstatsajax.html"; | ||
121 | |||
122 | ajaxUpdaterDivs[2] = "activelog"; | ||
123 | ajaxUpdaterSeconds[2] = 5; | ||
124 | ajaxUpdaterReportFragments[2] = "activelogajax.html"; | ||
125 | |||
126 | HTMLUtil.InsertPeriodicUpdaters(ref output, ajaxUpdaterDivs, ajaxUpdaterSeconds, ajaxUpdaterReportFragments); | ||
127 | |||
128 | output.Append(STYLESHEET); | ||
129 | HTMLUtil.HtmlHeaders_C(ref output); | ||
130 | HTMLUtil.AddReportLinks(ref output, values.stats_reports, ""); | ||
131 | HTMLUtil.TABLE_O(ref output, TableClass); | ||
132 | HTMLUtil.TR_O(ref output, TRClass); | ||
133 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
134 | output.Append("# Users Total"); | ||
135 | HTMLUtil.TD_C(ref output); | ||
136 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
137 | output.Append("# Sessions Total"); | ||
138 | HTMLUtil.TD_C(ref output); | ||
139 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
140 | output.Append("Avg Client FPS"); | ||
141 | HTMLUtil.TD_C(ref output); | ||
142 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
143 | output.Append("Avg Client Mem Use"); | ||
144 | HTMLUtil.TD_C(ref output); | ||
145 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
146 | output.Append("Avg Sim FPS"); | ||
147 | HTMLUtil.TD_C(ref output); | ||
148 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
149 | output.Append("Avg Ping"); | ||
150 | HTMLUtil.TD_C(ref output); | ||
151 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
152 | output.Append("KB Out Total"); | ||
153 | HTMLUtil.TD_C(ref output); | ||
154 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
155 | output.Append("KB In Total"); | ||
156 | HTMLUtil.TD_C(ref output); | ||
157 | HTMLUtil.TR_C(ref output); | ||
158 | HTMLUtil.TR_O(ref output, TRClass); | ||
159 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
160 | output.Append(values.total_num_users); | ||
161 | HTMLUtil.TD_C(ref output); | ||
162 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
163 | output.Append(values.total_num_sessions); | ||
164 | HTMLUtil.TD_C(ref output); | ||
165 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
166 | output.Append(values.avg_client_fps); | ||
167 | HTMLUtil.TD_C(ref output); | ||
168 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
169 | output.Append(values.avg_client_mem_use); | ||
170 | HTMLUtil.TD_C(ref output); | ||
171 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
172 | output.Append(values.avg_sim_fps); | ||
173 | HTMLUtil.TD_C(ref output); | ||
174 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
175 | output.Append(values.avg_ping); | ||
176 | HTMLUtil.TD_C(ref output); | ||
177 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
178 | output.Append(values.total_kb_out); | ||
179 | HTMLUtil.TD_C(ref output); | ||
180 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
181 | output.Append(values.total_kb_in); | ||
182 | HTMLUtil.TD_C(ref output); | ||
183 | HTMLUtil.TR_C(ref output); | ||
184 | HTMLUtil.TABLE_C(ref output); | ||
185 | |||
186 | HTMLUtil.HR(ref output, ""); | ||
187 | HTMLUtil.TABLE_O(ref output, ""); | ||
188 | HTMLUtil.TR_O(ref output, ""); | ||
189 | HTMLUtil.TD_O(ref output, "align_top"); | ||
190 | output.Append("<DIV id=\"activeconnections\">Active Connections loading...</DIV>"); | ||
191 | HTMLUtil.TD_C(ref output); | ||
192 | HTMLUtil.TD_O(ref output, "align_top"); | ||
193 | output.Append("<DIV id=\"activesimstats\">SimStats loading...</DIV>"); | ||
194 | output.Append("<DIV id=\"activelog\">ActiveLog loading...</DIV>"); | ||
195 | HTMLUtil.TD_C(ref output); | ||
196 | HTMLUtil.TR_C(ref output); | ||
197 | HTMLUtil.TABLE_C(ref output); | ||
198 | output.Append("</BODY></HTML>"); | ||
199 | // TODO: FIXME: template | ||
200 | return output.ToString(); | ||
201 | } | ||
202 | |||
203 | |||
204 | |||
205 | public stats_default_page_values rep_DefaultReport_data(SqliteConnection db, List<Scene> m_scene) | ||
206 | { | ||
207 | stats_default_page_values returnstruct = new stats_default_page_values(); | ||
208 | returnstruct.all_scenes = m_scene.ToArray(); | ||
209 | lock (db) | ||
210 | { | ||
211 | string SQL = @"SELECT COUNT(DISTINCT agent_id) as agents, COUNT(*) as sessions, AVG(avg_fps) as client_fps, | ||
212 | AVG(avg_sim_fps) as savg_sim_fps, AVG(avg_ping) as sav_ping, SUM(n_out_kb) as num_in_kb, | ||
213 | SUM(n_out_pk) as num_in_packets, SUM(n_in_kb) as num_out_kb, SUM(n_in_pk) as num_out_packets, AVG(mem_use) as sav_mem_use | ||
214 | FROM stats_session_data;"; | ||
215 | SqliteCommand cmd = new SqliteCommand(SQL, db); | ||
216 | SqliteDataReader sdr = cmd.ExecuteReader(); | ||
217 | if (sdr.HasRows) | ||
218 | { | ||
219 | sdr.Read(); | ||
220 | returnstruct.total_num_users = Convert.ToInt32(sdr["agents"]); | ||
221 | returnstruct.total_num_sessions = Convert.ToInt32(sdr["sessions"]); | ||
222 | returnstruct.avg_client_fps = Convert.ToSingle(sdr["client_fps"]); | ||
223 | returnstruct.avg_sim_fps = Convert.ToSingle(sdr["savg_sim_fps"]); | ||
224 | returnstruct.avg_ping = Convert.ToSingle(sdr["sav_ping"]); | ||
225 | returnstruct.total_kb_out = Convert.ToSingle(sdr["num_out_kb"]); | ||
226 | returnstruct.total_kb_in = Convert.ToSingle(sdr["num_in_kb"]); | ||
227 | returnstruct.avg_client_mem_use = Convert.ToSingle(sdr["sav_mem_use"]); | ||
228 | |||
229 | } | ||
230 | } | ||
231 | return returnstruct; | ||
232 | } | ||
233 | |||
234 | /// <summary> | ||
235 | /// Return summar information in the form: | ||
236 | /// <pre> | ||
237 | /// {"totalUsers": "34", | ||
238 | /// "totalSessions": "233", | ||
239 | /// ... | ||
240 | /// } | ||
241 | /// </pre> | ||
242 | /// </summary> | ||
243 | /// <param name="pModelResult"></param> | ||
244 | /// <returns></returns> | ||
245 | public string RenderJson(Hashtable pModelResult) { | ||
246 | stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"]; | ||
247 | |||
248 | OSDMap summaryInfo = new OSDMap(); | ||
249 | summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString())); | ||
250 | summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString())); | ||
251 | summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString())); | ||
252 | summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString())); | ||
253 | summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString())); | ||
254 | summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString())); | ||
255 | summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString())); | ||
256 | summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString())); | ||
257 | return summaryInfo.ToString(); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | public struct stats_default_page_values | ||
262 | { | ||
263 | public int total_num_users; | ||
264 | public int total_num_sessions; | ||
265 | public float avg_client_fps; | ||
266 | public float avg_client_mem_use; | ||
267 | public float avg_sim_fps; | ||
268 | public float avg_ping; | ||
269 | public float total_kb_out; | ||
270 | public float total_kb_in; | ||
271 | public float avg_client_resends; | ||
272 | public Scene[] all_scenes; | ||
273 | public Dictionary<UUID, USimStatsData> sim_stat_data; | ||
274 | public Dictionary<string, IStatsController> stats_reports; | ||
275 | } | ||
276 | |||
277 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs new file mode 100644 index 0000000..c07619f --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs | |||
@@ -0,0 +1,263 @@ | |||
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.Generic; | ||
30 | using System.Text; | ||
31 | |||
32 | namespace OpenSim.Region.UserStatistics | ||
33 | { | ||
34 | public static class HTMLUtil | ||
35 | { | ||
36 | |||
37 | public static void TR_O(ref StringBuilder o, string pclass) | ||
38 | { | ||
39 | o.Append("<tr"); | ||
40 | if (pclass.Length > 0) | ||
41 | { | ||
42 | GenericClass(ref o, pclass); | ||
43 | } | ||
44 | o.Append(">\n\t"); | ||
45 | } | ||
46 | |||
47 | public static void TR_C(ref StringBuilder o) | ||
48 | { | ||
49 | o.Append("</tr>\n"); | ||
50 | } | ||
51 | |||
52 | public static void TD_O(ref StringBuilder o, string pclass) | ||
53 | { | ||
54 | TD_O(ref o, pclass, 0, 0); | ||
55 | } | ||
56 | |||
57 | public static void TD_O(ref StringBuilder o, string pclass, int rowspan, int colspan) | ||
58 | { | ||
59 | o.Append("<td"); | ||
60 | if (pclass.Length > 0) | ||
61 | { | ||
62 | GenericClass(ref o, pclass); | ||
63 | } | ||
64 | if (rowspan > 1) | ||
65 | { | ||
66 | o.Append(" rowspan=\""); | ||
67 | o.Append(rowspan); | ||
68 | o.Append("\""); | ||
69 | } | ||
70 | if (colspan > 1) | ||
71 | { | ||
72 | o.Append(" colspan=\""); | ||
73 | o.Append(colspan); | ||
74 | o.Append("\""); | ||
75 | } | ||
76 | o.Append(">"); | ||
77 | } | ||
78 | |||
79 | public static void TD_C(ref StringBuilder o) | ||
80 | { | ||
81 | o.Append("</td>"); | ||
82 | } | ||
83 | |||
84 | public static void TABLE_O(ref StringBuilder o, string pclass) | ||
85 | { | ||
86 | o.Append("<table"); | ||
87 | if (pclass.Length > 0) | ||
88 | { | ||
89 | GenericClass(ref o, pclass); | ||
90 | } | ||
91 | o.Append(">\n\t"); | ||
92 | } | ||
93 | |||
94 | public static void TABLE_C(ref StringBuilder o) | ||
95 | { | ||
96 | o.Append("</table>\n"); | ||
97 | } | ||
98 | |||
99 | public static void BLOCKQUOTE_O(ref StringBuilder o, string pclass) | ||
100 | { | ||
101 | o.Append("<blockquote"); | ||
102 | if (pclass.Length > 0) | ||
103 | { | ||
104 | GenericClass(ref o, pclass); | ||
105 | } | ||
106 | o.Append(" />\n"); | ||
107 | } | ||
108 | |||
109 | public static void BLOCKQUOTE_C(ref StringBuilder o) | ||
110 | { | ||
111 | o.Append("</blockquote>\n"); | ||
112 | } | ||
113 | |||
114 | public static void BR(ref StringBuilder o) | ||
115 | { | ||
116 | o.Append("<br />\n"); | ||
117 | } | ||
118 | |||
119 | public static void HR(ref StringBuilder o, string pclass) | ||
120 | { | ||
121 | o.Append("<hr"); | ||
122 | if (pclass.Length > 0) | ||
123 | { | ||
124 | GenericClass(ref o, pclass); | ||
125 | } | ||
126 | o.Append(" />\n"); | ||
127 | } | ||
128 | |||
129 | public static void UL_O(ref StringBuilder o, string pclass) | ||
130 | { | ||
131 | o.Append("<ul"); | ||
132 | if (pclass.Length > 0) | ||
133 | { | ||
134 | GenericClass(ref o, pclass); | ||
135 | } | ||
136 | o.Append(" />\n"); | ||
137 | } | ||
138 | |||
139 | public static void UL_C(ref StringBuilder o) | ||
140 | { | ||
141 | o.Append("</ul>\n"); | ||
142 | } | ||
143 | |||
144 | public static void OL_O(ref StringBuilder o, string pclass) | ||
145 | { | ||
146 | o.Append("<ol"); | ||
147 | if (pclass.Length > 0) | ||
148 | { | ||
149 | GenericClass(ref o, pclass); | ||
150 | } | ||
151 | o.Append(" />\n"); | ||
152 | } | ||
153 | |||
154 | public static void OL_C(ref StringBuilder o) | ||
155 | { | ||
156 | o.Append("</ol>\n"); | ||
157 | } | ||
158 | |||
159 | public static void LI_O(ref StringBuilder o, string pclass) | ||
160 | { | ||
161 | o.Append("<li"); | ||
162 | if (pclass.Length > 0) | ||
163 | { | ||
164 | GenericClass(ref o, pclass); | ||
165 | } | ||
166 | o.Append(" />\n"); | ||
167 | } | ||
168 | |||
169 | public static void LI_C(ref StringBuilder o) | ||
170 | { | ||
171 | o.Append("</li>\n"); | ||
172 | } | ||
173 | |||
174 | public static void GenericClass(ref StringBuilder o, string pclass) | ||
175 | { | ||
176 | o.Append(" class=\""); | ||
177 | o.Append(pclass); | ||
178 | o.Append("\""); | ||
179 | } | ||
180 | |||
181 | public static void InsertProtoTypeAJAX(ref StringBuilder o) | ||
182 | { | ||
183 | o.Append("<script type=\"text/javascript\" src=\"prototype.js\"></script>\n"); | ||
184 | o.Append("<script type=\"text/javascript\" src=\"updater.js\"></script>\n"); | ||
185 | } | ||
186 | |||
187 | public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag) | ||
188 | { | ||
189 | o.Append("<script type=\"text/javascript\">\n"); | ||
190 | o.Append( | ||
191 | @" | ||
192 | // <![CDATA[ | ||
193 | document.observe('dom:loaded', function() { | ||
194 | /* | ||
195 | first arg : div to update | ||
196 | second arg : interval to poll in seconds | ||
197 | third arg : file to get data | ||
198 | */ | ||
199 | "); | ||
200 | for (int i = 0; i < divID.Length; i++) | ||
201 | { | ||
202 | |||
203 | o.Append("new updater('"); | ||
204 | o.Append(divID[i]); | ||
205 | o.Append("', "); | ||
206 | o.Append(seconds[i]); | ||
207 | o.Append(", '"); | ||
208 | o.Append(reportfrag[i]); | ||
209 | o.Append("');\n"); | ||
210 | } | ||
211 | |||
212 | o.Append(@" | ||
213 | }); | ||
214 | // ]]> | ||
215 | </script>"); | ||
216 | } | ||
217 | |||
218 | public static void HtmlHeaders_O(ref StringBuilder o) | ||
219 | { | ||
220 | o.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"); | ||
221 | o.Append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"nl\">"); | ||
222 | o.Append("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />"); | ||
223 | } | ||
224 | |||
225 | public static void HtmlHeaders_C(ref StringBuilder o) | ||
226 | { | ||
227 | o.Append("</HEAD>"); | ||
228 | o.Append("<BODY>"); | ||
229 | } | ||
230 | |||
231 | public static void AddReportLinks(ref StringBuilder o, Dictionary<string, IStatsController> reports, string pClass) | ||
232 | { | ||
233 | int repcount = 0; | ||
234 | foreach (string str in reports.Keys) | ||
235 | { | ||
236 | if (reports[str].ReportName.Length > 0) | ||
237 | { | ||
238 | if (repcount > 0) | ||
239 | { | ||
240 | o.Append("| "); | ||
241 | } | ||
242 | A(ref o, reports[str].ReportName, str, pClass); | ||
243 | o.Append(" "); | ||
244 | repcount++; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | public static void A(ref StringBuilder o, string linktext, string linkhref, string pClass) | ||
250 | { | ||
251 | o.Append("<A"); | ||
252 | if (pClass.Length > 0) | ||
253 | { | ||
254 | GenericClass(ref o, pClass); | ||
255 | } | ||
256 | o.Append(" href=\""); | ||
257 | o.Append(linkhref); | ||
258 | o.Append("\">"); | ||
259 | o.Append(linktext); | ||
260 | o.Append("</A>"); | ||
261 | } | ||
262 | } | ||
263 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs new file mode 100644 index 0000000..80c4487 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs | |||
@@ -0,0 +1,39 @@ | |||
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.Collections; | ||
29 | |||
30 | namespace OpenSim.Region.UserStatistics | ||
31 | { | ||
32 | public interface IStatsController | ||
33 | { | ||
34 | string ReportName { get; } | ||
35 | Hashtable ProcessModel(Hashtable pParams); | ||
36 | string RenderView(Hashtable pModelResult); | ||
37 | string RenderJson(Hashtable pModelResult); | ||
38 | } | ||
39 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs new file mode 100644 index 0000000..4d45b80 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs | |||
@@ -0,0 +1,159 @@ | |||
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.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using Mono.Data.SqliteClient; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Monitoring; | ||
39 | |||
40 | namespace OpenSim.Region.UserStatistics | ||
41 | { | ||
42 | public class LogLinesAJAX : IStatsController | ||
43 | { | ||
44 | private Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline); | ||
45 | |||
46 | private Regex webFormat = new Regex(@"[^\s]*\s([^,]*),[^\s]*\s([A-Z]*)[^\s-][^\[]*\[([^\]]*)\]([^\n]*)", | ||
47 | RegexOptions.Singleline | RegexOptions.Compiled); | ||
48 | private Regex TitleColor = new Regex(@"[^\s]*\s(?:[^,]*),[^\s]*\s(?:[A-Z]*)[^\s-][^\[]*\[([^\]]*)\](?:[^\n]*)", | ||
49 | RegexOptions.Singleline | RegexOptions.Compiled); | ||
50 | |||
51 | |||
52 | #region IStatsController Members | ||
53 | |||
54 | public string ReportName | ||
55 | { | ||
56 | get { return ""; } | ||
57 | } | ||
58 | |||
59 | public Hashtable ProcessModel(Hashtable pParams) | ||
60 | { | ||
61 | Hashtable nh = new Hashtable(); | ||
62 | nh.Add("loglines", pParams["LogLines"]); | ||
63 | return nh; | ||
64 | } | ||
65 | |||
66 | public string RenderView(Hashtable pModelResult) | ||
67 | { | ||
68 | StringBuilder output = new StringBuilder(); | ||
69 | |||
70 | HTMLUtil.HR(ref output, ""); | ||
71 | output.Append("<H3>ActiveLog</H3>\n"); | ||
72 | |||
73 | string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n"); | ||
74 | |||
75 | string[] result = Regex.Split(tmp, "\n"); | ||
76 | |||
77 | string formatopen = ""; | ||
78 | string formatclose = ""; | ||
79 | |||
80 | for (int i = 0; i < result.Length; i++) | ||
81 | { | ||
82 | if (result[i].Length >= 30) | ||
83 | { | ||
84 | string logtype = result[i].Substring(24, 6); | ||
85 | switch (logtype) | ||
86 | { | ||
87 | case "WARN ": | ||
88 | formatopen = "<font color=\"#7D7C00\">"; | ||
89 | formatclose = "</font>"; | ||
90 | break; | ||
91 | |||
92 | case "ERROR ": | ||
93 | formatopen = "<font color=\"#FF0000\">"; | ||
94 | formatclose = "</font>"; | ||
95 | break; | ||
96 | |||
97 | default: | ||
98 | formatopen = ""; | ||
99 | formatclose = ""; | ||
100 | break; | ||
101 | |||
102 | } | ||
103 | } | ||
104 | StringBuilder replaceStr = new StringBuilder(); | ||
105 | //string titlecolorresults = | ||
106 | |||
107 | string formatresult = Regex.Replace(TitleColor.Replace(result[i], "$1"), "[^ABCDEFabcdef0-9]", ""); | ||
108 | if (formatresult.Length > 6) | ||
109 | { | ||
110 | formatresult = formatresult.Substring(0, 6); | ||
111 | |||
112 | } | ||
113 | for (int j = formatresult.Length; j <= 5; j++) | ||
114 | formatresult += "0"; | ||
115 | replaceStr.Append("$1 - [<font color=\"#"); | ||
116 | replaceStr.Append(formatresult); | ||
117 | replaceStr.Append("\">$3</font>] $4<br />"); | ||
118 | string repstr = replaceStr.ToString(); | ||
119 | |||
120 | output.Append(formatopen); | ||
121 | output.Append(webFormat.Replace(result[i], repstr)); | ||
122 | output.Append(formatclose); | ||
123 | } | ||
124 | |||
125 | |||
126 | return output.ToString(); | ||
127 | } | ||
128 | |||
129 | /// <summary> | ||
130 | /// Return the last log lines. Output in the format: | ||
131 | /// <pre> | ||
132 | /// {"logLines": [ | ||
133 | /// "line1", | ||
134 | /// "line2", | ||
135 | /// ... | ||
136 | /// ] | ||
137 | /// } | ||
138 | /// </pre> | ||
139 | /// </summary> | ||
140 | /// <param name="pModelResult"></param> | ||
141 | /// <returns></returns> | ||
142 | public string RenderJson(Hashtable pModelResult) | ||
143 | { | ||
144 | OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
145 | |||
146 | OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray(); | ||
147 | string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n"); | ||
148 | string[] result = Regex.Split(tmp, "\n"); | ||
149 | for (int i = 0; i < result.Length; i++) | ||
150 | { | ||
151 | logLines.Add(new OSDString(result[i])); | ||
152 | } | ||
153 | logInfo.Add("logLines", logLines); | ||
154 | return logInfo.ToString(); | ||
155 | } | ||
156 | |||
157 | #endregion | ||
158 | } | ||
159 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs new file mode 100644 index 0000000..6f8b2aa --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs | |||
@@ -0,0 +1,80 @@ | |||
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.IO; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Text; | ||
33 | using OpenSim.Framework; | ||
34 | |||
35 | namespace OpenSim.Region.UserStatistics | ||
36 | { | ||
37 | public class Prototype_distributor : IStatsController | ||
38 | { | ||
39 | private string jsFileName = "prototype.js"; | ||
40 | private string prototypejs = string.Empty; | ||
41 | |||
42 | public Prototype_distributor() | ||
43 | { | ||
44 | jsFileName = "prototype.js"; | ||
45 | } | ||
46 | |||
47 | public Prototype_distributor(string jsName) | ||
48 | { | ||
49 | jsFileName = jsName; | ||
50 | } | ||
51 | |||
52 | public string ReportName | ||
53 | { | ||
54 | get { return ""; } | ||
55 | } | ||
56 | public Hashtable ProcessModel(Hashtable pParams) | ||
57 | { | ||
58 | Hashtable pResult = new Hashtable(); | ||
59 | pResult["js"] = jsFileName; | ||
60 | return pResult; | ||
61 | } | ||
62 | |||
63 | public string RenderView(Hashtable pModelResult) | ||
64 | { | ||
65 | string fileName = (string)pModelResult["js"]; | ||
66 | using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open))) | ||
67 | { | ||
68 | prototypejs = fs.ReadToEnd(); | ||
69 | fs.Close(); | ||
70 | } | ||
71 | return prototypejs; | ||
72 | } | ||
73 | |||
74 | public string RenderJson(Hashtable pModelResult) | ||
75 | { | ||
76 | return "{}"; | ||
77 | } | ||
78 | |||
79 | } | ||
80 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs new file mode 100644 index 0000000..0e94912 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs | |||
@@ -0,0 +1,288 @@ | |||
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.Text; | ||
32 | using Mono.Data.SqliteClient; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | |||
36 | namespace OpenSim.Region.UserStatistics | ||
37 | { | ||
38 | public class Sessions_Report : IStatsController | ||
39 | { | ||
40 | #region IStatsController Members | ||
41 | |||
42 | public string ReportName | ||
43 | { | ||
44 | get { return "Sessions"; } | ||
45 | } | ||
46 | |||
47 | public Hashtable ProcessModel(Hashtable pParams) | ||
48 | { | ||
49 | Hashtable modeldata = new Hashtable(); | ||
50 | modeldata.Add("Scenes", pParams["Scenes"]); | ||
51 | modeldata.Add("Reports", pParams["Reports"]); | ||
52 | SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; | ||
53 | List<SessionList> lstSessions = new List<SessionList>(); | ||
54 | Hashtable requestvars = (Hashtable) pParams["RequestVars"]; | ||
55 | |||
56 | |||
57 | string puserUUID = string.Empty; | ||
58 | string clientVersionString = string.Empty; | ||
59 | int queryparams = 0; | ||
60 | |||
61 | if (requestvars != null) | ||
62 | { | ||
63 | if (requestvars.ContainsKey("UserID")) | ||
64 | { | ||
65 | UUID testUUID = UUID.Zero; | ||
66 | if (UUID.TryParse(requestvars["UserID"].ToString(), out testUUID)) | ||
67 | { | ||
68 | puserUUID = requestvars["UserID"].ToString(); | ||
69 | |||
70 | } | ||
71 | } | ||
72 | |||
73 | if (requestvars.ContainsKey("VersionString")) | ||
74 | { | ||
75 | clientVersionString = requestvars["VersionString"].ToString(); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | lock (dbConn) | ||
80 | { | ||
81 | string sql = | ||
82 | "SELECT distinct a.name_f, a.name_l, a.Agent_ID, b.Session_ID, b.client_version, b.last_updated, b.start_time FROM stats_session_data a LEFT OUTER JOIN stats_session_data b ON a.Agent_ID = b.Agent_ID"; | ||
83 | |||
84 | if (puserUUID.Length > 0) | ||
85 | { | ||
86 | if (queryparams == 0) | ||
87 | sql += " WHERE"; | ||
88 | else | ||
89 | sql += " AND"; | ||
90 | |||
91 | sql += " b.agent_id=:agent_id"; | ||
92 | queryparams++; | ||
93 | } | ||
94 | |||
95 | if (clientVersionString.Length > 0) | ||
96 | { | ||
97 | if (queryparams == 0) | ||
98 | sql += " WHERE"; | ||
99 | else | ||
100 | sql += " AND"; | ||
101 | |||
102 | sql += " b.client_version=:client_version"; | ||
103 | queryparams++; | ||
104 | } | ||
105 | |||
106 | sql += " ORDER BY a.name_f, a.name_l, b.last_updated;"; | ||
107 | |||
108 | SqliteCommand cmd = new SqliteCommand(sql, dbConn); | ||
109 | |||
110 | if (puserUUID.Length > 0) | ||
111 | cmd.Parameters.Add(new SqliteParameter(":agent_id", puserUUID)); | ||
112 | if (clientVersionString.Length > 0) | ||
113 | cmd.Parameters.Add(new SqliteParameter(":client_version", clientVersionString)); | ||
114 | |||
115 | SqliteDataReader sdr = cmd.ExecuteReader(); | ||
116 | |||
117 | if (sdr.HasRows) | ||
118 | { | ||
119 | UUID userUUID = UUID.Zero; | ||
120 | |||
121 | SessionList activeSessionList = new SessionList(); | ||
122 | activeSessionList.user_id=UUID.Random(); | ||
123 | while (sdr.Read()) | ||
124 | { | ||
125 | UUID readUUID = UUID.Parse(sdr["agent_id"].ToString()); | ||
126 | if (readUUID != userUUID) | ||
127 | { | ||
128 | activeSessionList = new SessionList(); | ||
129 | activeSessionList.user_id = readUUID; | ||
130 | activeSessionList.firstname = sdr["name_f"].ToString(); | ||
131 | activeSessionList.lastname = sdr["name_l"].ToString(); | ||
132 | activeSessionList.sessions = new List<ShortSessionData>(); | ||
133 | lstSessions.Add(activeSessionList); | ||
134 | } | ||
135 | |||
136 | ShortSessionData ssd = new ShortSessionData(); | ||
137 | |||
138 | ssd.last_update = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["last_updated"])); | ||
139 | ssd.start_time = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["start_time"])); | ||
140 | ssd.session_id = UUID.Parse(sdr["session_id"].ToString()); | ||
141 | ssd.client_version = sdr["client_version"].ToString(); | ||
142 | activeSessionList.sessions.Add(ssd); | ||
143 | |||
144 | userUUID = activeSessionList.user_id; | ||
145 | } | ||
146 | } | ||
147 | sdr.Close(); | ||
148 | sdr.Dispose(); | ||
149 | |||
150 | } | ||
151 | modeldata["SessionData"] = lstSessions; | ||
152 | return modeldata; | ||
153 | } | ||
154 | |||
155 | public string RenderView(Hashtable pModelResult) | ||
156 | { | ||
157 | List<SessionList> lstSession = (List<SessionList>) pModelResult["SessionData"]; | ||
158 | Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"]; | ||
159 | |||
160 | const string STYLESHEET = | ||
161 | @" | ||
162 | <STYLE> | ||
163 | body | ||
164 | { | ||
165 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
166 | } | ||
167 | TABLE.defaultr { } | ||
168 | TR.defaultr { padding: 5px; } | ||
169 | TD.header { font-weight:bold; padding:5px; } | ||
170 | TD.content {} | ||
171 | TD.contentright { text-align: right; } | ||
172 | TD.contentcenter { text-align: center; } | ||
173 | TD.align_top { vertical-align: top; } | ||
174 | </STYLE> | ||
175 | "; | ||
176 | |||
177 | StringBuilder output = new StringBuilder(); | ||
178 | HTMLUtil.HtmlHeaders_O(ref output); | ||
179 | output.Append(STYLESHEET); | ||
180 | HTMLUtil.HtmlHeaders_C(ref output); | ||
181 | |||
182 | HTMLUtil.AddReportLinks(ref output, reports, ""); | ||
183 | |||
184 | HTMLUtil.TABLE_O(ref output, "defaultr"); | ||
185 | HTMLUtil.TR_O(ref output, "defaultr"); | ||
186 | HTMLUtil.TD_O(ref output, "header"); | ||
187 | output.Append("FirstName"); | ||
188 | HTMLUtil.TD_C(ref output); | ||
189 | HTMLUtil.TD_O(ref output, "header"); | ||
190 | output.Append("LastName"); | ||
191 | HTMLUtil.TD_C(ref output); | ||
192 | HTMLUtil.TD_O(ref output, "header"); | ||
193 | output.Append("SessionEnd"); | ||
194 | HTMLUtil.TD_C(ref output); | ||
195 | HTMLUtil.TD_O(ref output, "header"); | ||
196 | output.Append("SessionLength"); | ||
197 | HTMLUtil.TD_C(ref output); | ||
198 | HTMLUtil.TD_O(ref output, "header"); | ||
199 | output.Append("Client"); | ||
200 | HTMLUtil.TD_C(ref output); | ||
201 | HTMLUtil.TR_C(ref output); | ||
202 | if (lstSession.Count == 0) | ||
203 | { | ||
204 | HTMLUtil.TR_O(ref output, ""); | ||
205 | HTMLUtil.TD_O(ref output, "align_top", 1, 5); | ||
206 | output.Append("No results for that query"); | ||
207 | HTMLUtil.TD_C(ref output); | ||
208 | HTMLUtil.TR_C(ref output); | ||
209 | } | ||
210 | foreach (SessionList ssnlst in lstSession) | ||
211 | { | ||
212 | int cnt = 0; | ||
213 | foreach (ShortSessionData sesdata in ssnlst.sessions) | ||
214 | { | ||
215 | HTMLUtil.TR_O(ref output, ""); | ||
216 | if (cnt++ == 0) | ||
217 | { | ||
218 | HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); | ||
219 | output.Append(ssnlst.firstname); | ||
220 | HTMLUtil.TD_C(ref output); | ||
221 | HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1); | ||
222 | output.Append(ssnlst.lastname); | ||
223 | HTMLUtil.TD_C(ref output); | ||
224 | } | ||
225 | HTMLUtil.TD_O(ref output, "content"); | ||
226 | output.Append(sesdata.last_update.ToShortDateString()); | ||
227 | output.Append(" - "); | ||
228 | output.Append(sesdata.last_update.ToShortTimeString()); | ||
229 | HTMLUtil.TD_C(ref output); | ||
230 | HTMLUtil.TD_O(ref output, "content"); | ||
231 | TimeSpan dtlength = sesdata.last_update.Subtract(sesdata.start_time); | ||
232 | if (dtlength.Days > 0) | ||
233 | { | ||
234 | output.Append(dtlength.Days); | ||
235 | output.Append(" Days "); | ||
236 | } | ||
237 | if (dtlength.Hours > 0) | ||
238 | { | ||
239 | output.Append(dtlength.Hours); | ||
240 | output.Append(" Hours "); | ||
241 | } | ||
242 | if (dtlength.Minutes > 0) | ||
243 | { | ||
244 | output.Append(dtlength.Minutes); | ||
245 | output.Append(" Minutes"); | ||
246 | } | ||
247 | HTMLUtil.TD_C(ref output); | ||
248 | HTMLUtil.TD_O(ref output, "content"); | ||
249 | output.Append(sesdata.client_version); | ||
250 | HTMLUtil.TD_C(ref output); | ||
251 | HTMLUtil.TR_C(ref output); | ||
252 | |||
253 | } | ||
254 | HTMLUtil.TR_O(ref output, ""); | ||
255 | HTMLUtil.TD_O(ref output, "align_top", 1, 5); | ||
256 | HTMLUtil.HR(ref output, ""); | ||
257 | HTMLUtil.TD_C(ref output); | ||
258 | HTMLUtil.TR_C(ref output); | ||
259 | } | ||
260 | HTMLUtil.TABLE_C(ref output); | ||
261 | output.Append("</BODY>\n</HTML>"); | ||
262 | return output.ToString(); | ||
263 | } | ||
264 | |||
265 | public class SessionList | ||
266 | { | ||
267 | public string firstname; | ||
268 | public string lastname; | ||
269 | public UUID user_id; | ||
270 | public List<ShortSessionData> sessions; | ||
271 | } | ||
272 | |||
273 | public struct ShortSessionData | ||
274 | { | ||
275 | public UUID session_id; | ||
276 | public string client_version; | ||
277 | public DateTime last_update; | ||
278 | public DateTime start_time; | ||
279 | } | ||
280 | |||
281 | public string RenderJson(Hashtable pModelResult) | ||
282 | { | ||
283 | return "{}"; | ||
284 | } | ||
285 | #endregion | ||
286 | } | ||
287 | |||
288 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs new file mode 100644 index 0000000..06d9e91 --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs | |||
@@ -0,0 +1,276 @@ | |||
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.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Framework.Monitoring; | ||
38 | |||
39 | namespace OpenSim.Region.UserStatistics | ||
40 | { | ||
41 | public class SimStatsAJAX : IStatsController | ||
42 | { | ||
43 | #region IStatsController Members | ||
44 | |||
45 | public string ReportName | ||
46 | { | ||
47 | get { return ""; } | ||
48 | } | ||
49 | |||
50 | public Hashtable ProcessModel(Hashtable pParams) | ||
51 | { | ||
52 | List<Scene> m_scene = (List<Scene>)pParams["Scenes"]; | ||
53 | |||
54 | Hashtable nh = new Hashtable(); | ||
55 | nh.Add("hdata", m_scene); | ||
56 | nh.Add("simstats", pParams["SimStats"]); | ||
57 | return nh; | ||
58 | } | ||
59 | |||
60 | public string RenderView(Hashtable pModelResult) | ||
61 | { | ||
62 | StringBuilder output = new StringBuilder(); | ||
63 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
64 | Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"]; | ||
65 | |||
66 | const string TableClass = "defaultr"; | ||
67 | const string TRClass = "defaultr"; | ||
68 | const string TDHeaderClass = "header"; | ||
69 | const string TDDataClass = "content"; | ||
70 | //const string TDDataClassRight = "contentright"; | ||
71 | const string TDDataClassCenter = "contentcenter"; | ||
72 | |||
73 | foreach (USimStatsData sdata in sdatadic.Values) | ||
74 | { | ||
75 | |||
76 | |||
77 | foreach (Scene sn in all_scenes) | ||
78 | { | ||
79 | if (sn.RegionInfo.RegionID == sdata.RegionId) | ||
80 | { | ||
81 | output.Append("<H2>"); | ||
82 | output.Append(sn.RegionInfo.RegionName); | ||
83 | output.Append("</H2>"); | ||
84 | } | ||
85 | } | ||
86 | HTMLUtil.TABLE_O(ref output, TableClass); | ||
87 | HTMLUtil.TR_O(ref output, TRClass); | ||
88 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
89 | output.Append("Dilatn"); | ||
90 | HTMLUtil.TD_C(ref output); | ||
91 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
92 | output.Append("SimFPS"); | ||
93 | HTMLUtil.TD_C(ref output); | ||
94 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
95 | output.Append("PhysFPS"); | ||
96 | HTMLUtil.TD_C(ref output); | ||
97 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
98 | output.Append("AgntUp"); | ||
99 | HTMLUtil.TD_C(ref output); | ||
100 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
101 | output.Append("RootAg"); | ||
102 | HTMLUtil.TD_C(ref output); | ||
103 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
104 | output.Append("ChldAg"); | ||
105 | HTMLUtil.TD_C(ref output); | ||
106 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
107 | output.Append("Prims"); | ||
108 | HTMLUtil.TD_C(ref output); | ||
109 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
110 | output.Append("ATvPrm"); | ||
111 | HTMLUtil.TD_C(ref output); | ||
112 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
113 | output.Append("AtvScr"); | ||
114 | HTMLUtil.TD_C(ref output); | ||
115 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
116 | output.Append("ScrLPS"); | ||
117 | HTMLUtil.TD_C(ref output); | ||
118 | HTMLUtil.TR_C(ref output); | ||
119 | HTMLUtil.TR_O(ref output, TRClass); | ||
120 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
121 | output.Append(sdata.TimeDilation); | ||
122 | HTMLUtil.TD_C(ref output); | ||
123 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
124 | output.Append(sdata.SimFps); | ||
125 | HTMLUtil.TD_C(ref output); | ||
126 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
127 | output.Append(sdata.PhysicsFps); | ||
128 | HTMLUtil.TD_C(ref output); | ||
129 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
130 | output.Append(sdata.AgentUpdates); | ||
131 | HTMLUtil.TD_C(ref output); | ||
132 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
133 | output.Append(sdata.RootAgents); | ||
134 | HTMLUtil.TD_C(ref output); | ||
135 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
136 | output.Append(sdata.ChildAgents); | ||
137 | HTMLUtil.TD_C(ref output); | ||
138 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
139 | output.Append(sdata.TotalPrims); | ||
140 | HTMLUtil.TD_C(ref output); | ||
141 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
142 | output.Append(sdata.ActivePrims); | ||
143 | HTMLUtil.TD_C(ref output); | ||
144 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
145 | output.Append(sdata.ActiveScripts); | ||
146 | HTMLUtil.TD_C(ref output); | ||
147 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
148 | output.Append(sdata.ScriptLinesPerSecond); | ||
149 | HTMLUtil.TD_C(ref output); | ||
150 | HTMLUtil.TR_C(ref output); | ||
151 | HTMLUtil.TR_O(ref output, TRClass); | ||
152 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
153 | output.Append("FrmMS"); | ||
154 | HTMLUtil.TD_C(ref output); | ||
155 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
156 | output.Append("AgtMS"); | ||
157 | HTMLUtil.TD_C(ref output); | ||
158 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
159 | output.Append("PhysMS"); | ||
160 | HTMLUtil.TD_C(ref output); | ||
161 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
162 | output.Append("OthrMS"); | ||
163 | HTMLUtil.TD_C(ref output); | ||
164 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
165 | output.Append("OutPPS"); | ||
166 | HTMLUtil.TD_C(ref output); | ||
167 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
168 | output.Append("InPPS"); | ||
169 | HTMLUtil.TD_C(ref output); | ||
170 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
171 | output.Append("NoAckKB"); | ||
172 | HTMLUtil.TD_C(ref output); | ||
173 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
174 | output.Append("PndDWN"); | ||
175 | HTMLUtil.TD_C(ref output); | ||
176 | HTMLUtil.TD_O(ref output, TDHeaderClass); | ||
177 | output.Append("PndUP"); | ||
178 | HTMLUtil.TD_C(ref output); | ||
179 | HTMLUtil.TR_C(ref output); | ||
180 | HTMLUtil.TR_O(ref output, TRClass); | ||
181 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
182 | output.Append(sdata.TotalFrameTime); | ||
183 | HTMLUtil.TD_C(ref output); | ||
184 | HTMLUtil.TD_O(ref output, TDDataClass); | ||
185 | output.Append(sdata.AgentFrameTime); | ||
186 | HTMLUtil.TD_C(ref output); | ||
187 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
188 | output.Append(sdata.PhysicsFrameTime); | ||
189 | HTMLUtil.TD_C(ref output); | ||
190 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
191 | output.Append(sdata.OtherFrameTime); | ||
192 | HTMLUtil.TD_C(ref output); | ||
193 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
194 | output.Append(sdata.OutPacketsPerSecond); | ||
195 | HTMLUtil.TD_C(ref output); | ||
196 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
197 | output.Append(sdata.InPacketsPerSecond); | ||
198 | HTMLUtil.TD_C(ref output); | ||
199 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
200 | output.Append(sdata.UnackedBytes); | ||
201 | HTMLUtil.TD_C(ref output); | ||
202 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
203 | output.Append(sdata.PendingDownloads); | ||
204 | HTMLUtil.TD_C(ref output); | ||
205 | HTMLUtil.TD_O(ref output, TDDataClassCenter); | ||
206 | output.Append(sdata.PendingUploads); | ||
207 | HTMLUtil.TD_C(ref output); | ||
208 | HTMLUtil.TR_C(ref output); | ||
209 | HTMLUtil.TABLE_C(ref output); | ||
210 | |||
211 | } | ||
212 | |||
213 | return output.ToString(); | ||
214 | } | ||
215 | |||
216 | /// <summary> | ||
217 | /// Return stat information for all regions in the sim. Returns data of the form: | ||
218 | /// <pre> | ||
219 | /// {"REGIONNAME": { | ||
220 | /// "region": "REGIONNAME", | ||
221 | /// "timeDilation": "101", | ||
222 | /// ... // the rest of the stat info | ||
223 | /// }, | ||
224 | /// ... // entries for each region | ||
225 | /// } | ||
226 | /// </pre> | ||
227 | /// </summary> | ||
228 | /// <param name="pModelResult"></param> | ||
229 | /// <returns></returns> | ||
230 | public string RenderJson(Hashtable pModelResult) | ||
231 | { | ||
232 | List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"]; | ||
233 | Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"]; | ||
234 | |||
235 | OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
236 | foreach (USimStatsData sdata in sdatadic.Values) | ||
237 | { | ||
238 | OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap(); | ||
239 | string regionName = "unknown"; | ||
240 | foreach (Scene sn in all_scenes) | ||
241 | { | ||
242 | if (sn.RegionInfo.RegionID == sdata.RegionId) | ||
243 | { | ||
244 | regionName = sn.RegionInfo.RegionName; | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | statsInfo.Add("region", new OSDString(regionName)); | ||
249 | statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString())); | ||
250 | statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString())); | ||
251 | statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString())); | ||
252 | statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString())); | ||
253 | statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString())); | ||
254 | statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString())); | ||
255 | statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString())); | ||
256 | statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString())); | ||
257 | statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString())); | ||
258 | statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString())); | ||
259 | statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString())); | ||
260 | statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString())); | ||
261 | statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString())); | ||
262 | statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString())); | ||
263 | statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString())); | ||
264 | statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString())); | ||
265 | statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString())); | ||
266 | statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString())); | ||
267 | statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString())); | ||
268 | |||
269 | allStatsInfo.Add(regionName, statsInfo); | ||
270 | } | ||
271 | return allStatsInfo.ToString(); | ||
272 | } | ||
273 | |||
274 | #endregion | ||
275 | } | ||
276 | } | ||
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs new file mode 100644 index 0000000..601e06b --- /dev/null +++ b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs | |||
@@ -0,0 +1,70 @@ | |||
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.IO; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Text; | ||
33 | using OpenSim.Framework; | ||
34 | |||
35 | namespace OpenSim.Region.UserStatistics | ||
36 | { | ||
37 | public class Updater_distributor : IStatsController | ||
38 | { | ||
39 | private string updaterjs = string.Empty; | ||
40 | |||
41 | public string ReportName | ||
42 | { | ||
43 | get { return ""; } | ||
44 | } | ||
45 | |||
46 | public Hashtable ProcessModel(Hashtable pParams) | ||
47 | { | ||
48 | Hashtable pResult = new Hashtable(); | ||
49 | if (updaterjs.Length == 0) | ||
50 | { | ||
51 | StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open)); | ||
52 | updaterjs = fs.ReadToEnd(); | ||
53 | fs.Close(); | ||
54 | fs.Dispose(); | ||
55 | } | ||
56 | pResult["js"] = updaterjs; | ||
57 | return pResult; | ||
58 | } | ||
59 | |||
60 | public string RenderView(Hashtable pModelResult) | ||
61 | { | ||
62 | return pModelResult["js"].ToString(); | ||
63 | } | ||
64 | |||
65 | public string RenderJson(Hashtable pModelResult) { | ||
66 | return "{}"; | ||
67 | } | ||
68 | |||
69 | } | ||
70 | } \ No newline at end of file | ||
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 | ||