diff options
Diffstat (limited to 'OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs')
-rw-r--r-- | OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs | 308 |
1 files changed, 308 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 | } | ||