/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSimulator Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections; using System.Collections.Generic; using System.Text; using Mono.Data.SqliteClient; using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.UserStatistics { public class Clients_report : IStatsController { #region IStatsController Members public string ReportName { get { return "Client"; } } /// <summary> /// Return summar information in the form: /// <pre> /// {"totalUsers": "34", /// "totalSessions": "233", /// ... /// } /// </pre> /// </summary> /// <param name="pModelResult"></param> /// <returns></returns> public string RenderJson(Hashtable pModelResult) { stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"]; OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap(); summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString())); summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString())); summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString())); summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString())); summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString())); summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString())); summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString())); summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString())); return summaryInfo.ToString(); } public Hashtable ProcessModel(Hashtable pParams) { SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"]; List<ClientVersionData> clidata = new List<ClientVersionData>(); List<ClientVersionData> cliRegData = new List<ClientVersionData>(); Hashtable regionTotals = new Hashtable(); Hashtable modeldata = new Hashtable(); modeldata.Add("Scenes", pParams["Scenes"]); modeldata.Add("Reports", pParams["Reports"]); int totalclients = 0; int totalregions = 0; lock (dbConn) { string sql = "select count(distinct region_id) as regcnt from stats_session_data"; SqliteCommand cmd = new SqliteCommand(sql, dbConn); SqliteDataReader sdr = cmd.ExecuteReader(); if (sdr.HasRows) { sdr.Read(); totalregions = Convert.ToInt32(sdr["regcnt"]); } sdr.Close(); sdr.Dispose(); sql = "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;"; cmd = new SqliteCommand(sql, dbConn); sdr = cmd.ExecuteReader(); if (sdr.HasRows) { while (sdr.Read()) { ClientVersionData udata = new ClientVersionData(); udata.version = sdr["client_version"].ToString(); udata.count = Convert.ToInt32(sdr["cnt"]); udata.fps = Convert.ToSingle(sdr["simfps"]); clidata.Add(udata); totalclients += udata.count; } } sdr.Close(); sdr.Dispose(); if (totalregions > 1) { sql = "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;"; cmd = new SqliteCommand(sql, dbConn); sdr = cmd.ExecuteReader(); if (sdr.HasRows) { while (sdr.Read()) { ClientVersionData udata = new ClientVersionData(); udata.version = sdr["client_version"].ToString(); udata.count = Convert.ToInt32(sdr["cnt"]); udata.fps = Convert.ToSingle(sdr["simfps"]); udata.region_id = UUID.Parse(sdr["region_id"].ToString()); cliRegData.Add(udata); } } sdr.Close(); sdr.Dispose(); } } foreach (ClientVersionData cvd in cliRegData) { if (regionTotals.ContainsKey(cvd.region_id)) { int regiontotal = (int)regionTotals[cvd.region_id]; regiontotal += cvd.count; regionTotals[cvd.region_id] = regiontotal; } else { regionTotals.Add(cvd.region_id, cvd.count); } } modeldata["ClientData"] = clidata; modeldata["ClientRegionData"] = cliRegData; modeldata["RegionTotals"] = regionTotals; modeldata["Total"] = totalclients; return modeldata; } public string RenderView(Hashtable pModelResult) { List<ClientVersionData> clidata = (List<ClientVersionData>) pModelResult["ClientData"]; int totalclients = (int)pModelResult["Total"]; Hashtable regionTotals = (Hashtable) pModelResult["RegionTotals"]; List<ClientVersionData> cliRegData = (List<ClientVersionData>) pModelResult["ClientRegionData"]; List<Scene> m_scenes = (List<Scene>)pModelResult["Scenes"]; Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"]; const string STYLESHEET = @" <STYLE> body { font-size:15px; font-family:Helvetica, Verdana; color:Black; } TABLE.defaultr { } TR.defaultr { padding: 5px; } TD.header { font-weight:bold; padding:5px; } TD.content {} TD.contentright { text-align: right; } TD.contentcenter { text-align: center; } TD.align_top { vertical-align: top; } </STYLE> "; StringBuilder output = new StringBuilder(); HTMLUtil.HtmlHeaders_O(ref output); output.Append(STYLESHEET); HTMLUtil.HtmlHeaders_C(ref output); HTMLUtil.AddReportLinks(ref output, reports, ""); HTMLUtil.TABLE_O(ref output, "defaultr"); HTMLUtil.TR_O(ref output, ""); HTMLUtil.TD_O(ref output, "header"); output.Append("ClientVersion"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "header"); output.Append("Count/%"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "header"); output.Append("SimFPS"); HTMLUtil.TD_C(ref output); HTMLUtil.TR_C(ref output); foreach (ClientVersionData cvd in clidata) { HTMLUtil.TR_O(ref output, ""); HTMLUtil.TD_O(ref output, "content"); string linkhref = "sessions.report?VersionString=" + cvd.version; HTMLUtil.A(ref output, cvd.version, linkhref, ""); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "content"); output.Append(cvd.count); output.Append("/"); if (totalclients > 0) output.Append((((float)cvd.count / (float)totalclients)*100).ToString()); else output.Append(0); output.Append("%"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "content"); output.Append(cvd.fps); HTMLUtil.TD_C(ref output); HTMLUtil.TR_C(ref output); } HTMLUtil.TABLE_C(ref output); if (cliRegData.Count > 0) { HTMLUtil.TABLE_O(ref output, "defaultr"); HTMLUtil.TR_O(ref output, ""); HTMLUtil.TD_O(ref output, "header"); output.Append("Region"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "header"); output.Append("ClientVersion"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "header"); output.Append("Count/%"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "header"); output.Append("SimFPS"); HTMLUtil.TD_C(ref output); HTMLUtil.TR_C(ref output); foreach (ClientVersionData cvd in cliRegData) { HTMLUtil.TR_O(ref output, ""); HTMLUtil.TD_O(ref output, "content"); output.Append(regionNamefromUUID(m_scenes, cvd.region_id)); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "content"); output.Append(cvd.version); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "content"); output.Append(cvd.count); output.Append("/"); if ((int)regionTotals[cvd.region_id] > 0) output.Append((((float)cvd.count / (float)((int)regionTotals[cvd.region_id])) * 100).ToString()); else output.Append(0); output.Append("%"); HTMLUtil.TD_C(ref output); HTMLUtil.TD_O(ref output, "content"); output.Append(cvd.fps); HTMLUtil.TD_C(ref output); HTMLUtil.TR_C(ref output); } HTMLUtil.TABLE_C(ref output); } output.Append("</BODY>"); output.Append("</HTML>"); return output.ToString(); } public string regionNamefromUUID(List<Scene> scenes, UUID region_id) { string returnstring = string.Empty; foreach (Scene sn in scenes) { if (region_id == sn.RegionInfo.originRegionID) { returnstring = sn.RegionInfo.RegionName; break; } } if (returnstring.Length == 0) { returnstring = region_id.ToString(); } return returnstring; } #endregion } public struct ClientVersionData { public UUID region_id; public string version; public int count; public float fps; } }