- Timestamp:
- Jan 27, 2023, 7:28:00 PM (22 months ago)
- Location:
- binary-improvements2/WebServer/src/WebAPI/APIs
- Files:
-
- 1 added
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
binary-improvements2/WebServer/src/WebAPI/APIs/GetPlayerList.cs
r401 r402 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text.RegularExpressions; 5 using AllocsFixes.JSON; 6 using AllocsFixes.PersistentData; 7 using JetBrains.Annotations; 8 9 namespace Webserver.WebAPI { 10 [UsedImplicitly] 11 public class GetPlayerList : AbsWebAPI { 12 private static readonly Regex numberFilterMatcher = 13 new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$"); 14 15 private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Build"); 16 17 public override void HandleRequest (RequestContext _context) { 18 AdminTools admTools = GameManager.Instance.adminTools; 19 PlatformUserIdentifierAbs userId = _context.Connection?.UserId; 20 21 bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel); 22 23 // TODO: Sort (and filter?) prior to converting to JSON ... hard as how to get the correct column's data? (i.e. column name matches JSON object field names, not source data) 24 25 int rowsPerPage = 25; 26 if (_context.Request.QueryString ["rowsperpage"] != null) { 27 int.TryParse (_context.Request.QueryString ["rowsperpage"], out rowsPerPage); 28 } 29 30 int page = 0; 31 if (_context.Request.QueryString ["page"] != null) { 32 int.TryParse (_context.Request.QueryString ["page"], out page); 33 } 34 35 int firstEntry = page * rowsPerPage; 36 37 Players playersList = PersistentContainer.Instance.Players; 38 39 40 List<JsonObject> playerList = new List<JsonObject> (); 41 42 jsonSerializeSampler.Begin (); 43 44 foreach (KeyValuePair<PlatformUserIdentifierAbs, Player> kvp in playersList.Dict) { 45 Player p = kvp.Value; 46 47 if (bViewAll || p.PlatformId.Equals (userId)) { 48 JsonObject pos = new JsonObject (); 49 pos.Add ("x", new JsonNumber (p.LastPosition.x)); 50 pos.Add ("y", new JsonNumber (p.LastPosition.y)); 51 pos.Add ("z", new JsonNumber (p.LastPosition.z)); 52 53 JsonObject pJson = new JsonObject (); 54 pJson.Add ("steamid", new JsonString (kvp.Key.CombinedString)); 55 pJson.Add ("entityid", new JsonNumber (p.EntityID)); 56 pJson.Add ("ip", new JsonString (p.IP)); 57 pJson.Add ("name", new JsonString (p.Name)); 58 pJson.Add ("online", new JsonBoolean (p.IsOnline)); 59 pJson.Add ("position", pos); 60 61 pJson.Add ("totalplaytime", new JsonNumber (p.TotalPlayTime)); 62 pJson.Add ("lastonline", 63 new JsonString (p.LastOnline.ToUniversalTime ().ToString ("yyyy-MM-ddTHH:mm:ssZ"))); 64 pJson.Add ("ping", new JsonNumber (p.IsOnline ? p.ClientInfo.ping : -1)); 65 66 JsonBoolean banned = admTools != null ? new JsonBoolean (admTools.IsBanned (kvp.Key, out _, out _)) : new JsonBoolean (false); 67 68 pJson.Add ("banned", banned); 69 70 playerList.Add (pJson); 71 } 72 } 73 74 jsonSerializeSampler.End (); 75 76 IEnumerable<JsonObject> list = playerList; 77 78 foreach (string key in _context.Request.QueryString.AllKeys) { 79 if (!string.IsNullOrEmpty (key) && key.StartsWith ("filter[")) { 80 string filterCol = key.Substring (key.IndexOf ('[') + 1); 81 filterCol = filterCol.Substring (0, filterCol.Length - 1); 82 string filterVal = _context.Request.QueryString.Get (key).Trim (); 83 84 list = ExecuteFilter (list, filterCol, filterVal); 85 } 86 } 87 88 int totalAfterFilter = list.Count (); 89 90 foreach (string key in _context.Request.QueryString.AllKeys) { 91 if (!string.IsNullOrEmpty (key) && key.StartsWith ("sort[")) { 92 string sortCol = key.Substring (key.IndexOf ('[') + 1); 93 sortCol = sortCol.Substring (0, sortCol.Length - 1); 94 string sortVal = _context.Request.QueryString.Get (key); 95 96 list = ExecuteSort (list, sortCol, sortVal == "0"); 97 } 98 } 99 100 list = list.Skip (firstEntry); 101 list = list.Take (rowsPerPage); 102 103 104 JsonArray playersJsResult = new JsonArray (); 105 foreach (JsonObject jsO in list) { 106 playersJsResult.Add (jsO); 107 } 108 109 JsonObject result = new JsonObject (); 110 result.Add ("total", new JsonNumber (totalAfterFilter)); 111 result.Add ("totalUnfiltered", new JsonNumber (playerList.Count)); 112 result.Add ("firstResult", new JsonNumber (firstEntry)); 113 result.Add ("players", playersJsResult); 114 115 WebUtils.WriteJson (_context.Response, result); 116 } 117 118 private IEnumerable<JsonObject> ExecuteFilter (IEnumerable<JsonObject> _list, string _filterCol, 119 string _filterVal) { 120 if (!_list.Any()) { 121 return _list; 122 } 123 124 if (_list.First ().ContainsKey (_filterCol)) { 125 Type colType = _list.First () [_filterCol].GetType (); 126 if (colType == typeof (JsonNumber)) { 127 return ExecuteNumberFilter (_list, _filterCol, _filterVal); 128 } 129 130 if (colType == typeof (JsonBoolean)) { 131 bool value = StringParsers.ParseBool (_filterVal); 132 return _list.Where (_line => ((JsonBoolean) _line [_filterCol]).GetBool () == value); 133 } 134 135 if (colType == typeof (JsonString)) { 136 // regex-match whole ^string$, replace * by .*, ? by .?, + by .+ 137 _filterVal = _filterVal.Replace ("*", ".*").Replace ("?", ".?").Replace ("+", ".+"); 138 _filterVal = "^" + _filterVal + "$"; 139 140 //Log.Out ("GetPlayerList: Filter on String with Regex '" + _filterVal + "'"); 141 Regex matcher = new Regex (_filterVal, RegexOptions.IgnoreCase); 142 return _list.Where (_line => matcher.IsMatch (((JsonString) _line [_filterCol]).GetString ())); 143 } 144 } 145 146 return _list; 147 } 148 149 150 private IEnumerable<JsonObject> ExecuteNumberFilter (IEnumerable<JsonObject> _list, string _filterCol, 151 string _filterVal) { 152 // allow value (exact match), =, ==, >=, >, <=, < 153 Match filterMatch = numberFilterMatcher.Match (_filterVal); 154 if (filterMatch.Success) { 155 double value = StringParsers.ParseDouble (filterMatch.Groups [2].Value); 156 NumberMatchType matchType; 157 double epsilon = value / 100000; 158 switch (filterMatch.Groups [1].Value) { 159 case "": 160 case "=": 161 case "==": 162 matchType = NumberMatchType.Equal; 163 break; 164 case ">": 165 matchType = NumberMatchType.Greater; 166 break; 167 case ">=": 168 case "=>": 169 matchType = NumberMatchType.GreaterEqual; 170 break; 171 case "<": 172 matchType = NumberMatchType.Lesser; 173 break; 174 case "<=": 175 case "=<": 176 matchType = NumberMatchType.LesserEqual; 177 break; 178 default: 179 matchType = NumberMatchType.Equal; 180 break; 181 } 182 183 return _list.Where (delegate (JsonObject _line) { 184 double objVal = ((JsonNumber) _line [_filterCol]).GetDouble (); 185 switch (matchType) { 186 case NumberMatchType.Greater: 187 return objVal > value; 188 case NumberMatchType.GreaterEqual: 189 return objVal >= value; 190 case NumberMatchType.Lesser: 191 return objVal < value; 192 case NumberMatchType.LesserEqual: 193 return objVal <= value; 194 case NumberMatchType.Equal: 195 default: 196 return NearlyEqual (objVal, value, epsilon); 197 } 198 }); 199 } 200 201 Log.Out ("[Web] GetPlayerList: ignoring invalid filter for number-column '{0}': '{1}'", _filterCol, _filterVal); 202 return _list; 203 } 204 205 206 private IEnumerable<JsonObject> ExecuteSort (IEnumerable<JsonObject> _list, string _sortCol, bool _ascending) { 207 if (_list.Count () == 0) { 208 return _list; 209 } 210 211 if (_list.First ().ContainsKey (_sortCol)) { 212 Type colType = _list.First () [_sortCol].GetType (); 213 if (colType == typeof (JsonNumber)) { 214 if (_ascending) { 215 return _list.OrderBy (_line => ((JsonNumber) _line [_sortCol]).GetDouble ()); 216 } 217 218 return _list.OrderByDescending (_line => ((JsonNumber) _line [_sortCol]).GetDouble ()); 219 } 220 221 if (colType == typeof (JsonBoolean)) { 222 if (_ascending) { 223 return _list.OrderBy (_line => ((JsonBoolean) _line [_sortCol]).GetBool ()); 224 } 225 226 return _list.OrderByDescending (_line => ((JsonBoolean) _line [_sortCol]).GetBool ()); 227 } 228 229 if (_ascending) { 230 return _list.OrderBy (_line => _line [_sortCol].ToString ()); 231 } 232 233 return _list.OrderByDescending (_line => _line [_sortCol].ToString ()); 234 } 235 236 return _list; 237 } 238 239 240 private bool NearlyEqual (double _a, double _b, double _epsilon) { 241 double absA = Math.Abs (_a); 242 double absB = Math.Abs (_b); 243 double diff = Math.Abs (_a - _b); 244 245 if (_a == _b) { 246 return true; 247 } 248 249 if (_a == 0 || _b == 0 || diff < double.Epsilon) { 250 return diff < _epsilon; 251 } 252 253 return diff / (absA + absB) < _epsilon; 254 } 255 256 private enum NumberMatchType { 257 Equal, 258 Greater, 259 GreaterEqual, 260 Lesser, 261 LesserEqual 262 } 263 } 264 } 1 // using System; 2 // using System.Collections.Generic; 3 // using System.Linq; 4 // using System.Text.RegularExpressions; 5 // using AllocsFixes.PersistentData; 6 // using JetBrains.Annotations; 7 // 8 // namespace Webserver.WebAPI.APIs { 9 // [UsedImplicitly] 10 // public class GetPlayerList : AbsWebAPI { 11 // private static readonly Regex numberFilterMatcher = 12 // new Regex (@"^(>=|=>|>|<=|=<|<|==|=)?\s*([0-9]+(\.[0-9]*)?)$"); 13 // 14 // private static readonly UnityEngine.Profiling.CustomSampler jsonSerializeSampler = UnityEngine.Profiling.CustomSampler.Create ("JSON_Build"); 15 // 16 // public override void HandleRequest (RequestContext _context) { 17 // AdminTools admTools = GameManager.Instance.adminTools; 18 // PlatformUserIdentifierAbs userId = _context.Connection?.UserId; 19 // 20 // bool bViewAll = WebConnection.CanViewAllPlayers (_context.PermissionLevel); 21 // 22 // // TODO: Sort (and filter?) prior to converting to JSON ... hard as how to get the correct column's data? (i.e. column name matches JSON object field names, not source data) 23 // 24 // int rowsPerPage = 25; 25 // if (_context.Request.QueryString ["rowsperpage"] != null) { 26 // int.TryParse (_context.Request.QueryString ["rowsperpage"], out rowsPerPage); 27 // } 28 // 29 // int page = 0; 30 // if (_context.Request.QueryString ["page"] != null) { 31 // int.TryParse (_context.Request.QueryString ["page"], out page); 32 // } 33 // 34 // int firstEntry = page * rowsPerPage; 35 // 36 // Players playersList = PersistentContainer.Instance.Players; 37 // 38 // 39 // List<JsonObject> playerList = new List<JsonObject> (); 40 // 41 // jsonSerializeSampler.Begin (); 42 // 43 // foreach (KeyValuePair<PlatformUserIdentifierAbs, Player> kvp in playersList.Dict) { 44 // Player p = kvp.Value; 45 // 46 // if (bViewAll || p.PlatformId.Equals (userId)) { 47 // JsonObject pos = new JsonObject (); 48 // pos.Add ("x", new JsonNumber (p.LastPosition.x)); 49 // pos.Add ("y", new JsonNumber (p.LastPosition.y)); 50 // pos.Add ("z", new JsonNumber (p.LastPosition.z)); 51 // 52 // JsonObject pJson = new JsonObject (); 53 // pJson.Add ("steamid", new JsonString (kvp.Key.CombinedString)); 54 // pJson.Add ("entityid", new JsonNumber (p.EntityID)); 55 // pJson.Add ("ip", new JsonString (p.IP)); 56 // pJson.Add ("name", new JsonString (p.Name)); 57 // pJson.Add ("online", new JsonBoolean (p.IsOnline)); 58 // pJson.Add ("position", pos); 59 // 60 // pJson.Add ("totalplaytime", new JsonNumber (p.TotalPlayTime)); 61 // pJson.Add ("lastonline", 62 // new JsonString (p.LastOnline.ToUniversalTime ().ToString ("yyyy-MM-ddTHH:mm:ssZ"))); 63 // pJson.Add ("ping", new JsonNumber (p.IsOnline ? p.ClientInfo.ping : -1)); 64 // 65 // JsonBoolean banned = admTools != null ? new JsonBoolean (admTools.IsBanned (kvp.Key, out _, out _)) : new JsonBoolean (false); 66 // 67 // pJson.Add ("banned", banned); 68 // 69 // playerList.Add (pJson); 70 // } 71 // } 72 // 73 // jsonSerializeSampler.End (); 74 // 75 // IEnumerable<JsonObject> list = playerList; 76 // 77 // foreach (string key in _context.Request.QueryString.AllKeys) { 78 // if (!string.IsNullOrEmpty (key) && key.StartsWith ("filter[")) { 79 // string filterCol = key.Substring (key.IndexOf ('[') + 1); 80 // filterCol = filterCol.Substring (0, filterCol.Length - 1); 81 // string filterVal = _context.Request.QueryString.Get (key).Trim (); 82 // 83 // list = ExecuteFilter (list, filterCol, filterVal); 84 // } 85 // } 86 // 87 // int totalAfterFilter = list.Count (); 88 // 89 // foreach (string key in _context.Request.QueryString.AllKeys) { 90 // if (!string.IsNullOrEmpty (key) && key.StartsWith ("sort[")) { 91 // string sortCol = key.Substring (key.IndexOf ('[') + 1); 92 // sortCol = sortCol.Substring (0, sortCol.Length - 1); 93 // string sortVal = _context.Request.QueryString.Get (key); 94 // 95 // list = ExecuteSort (list, sortCol, sortVal == "0"); 96 // } 97 // } 98 // 99 // list = list.Skip (firstEntry); 100 // list = list.Take (rowsPerPage); 101 // 102 // 103 // JsonArray playersJsResult = new JsonArray (); 104 // foreach (JsonObject jsO in list) { 105 // playersJsResult.Add (jsO); 106 // } 107 // 108 // JsonObject result = new JsonObject (); 109 // result.Add ("total", new JsonNumber (totalAfterFilter)); 110 // result.Add ("totalUnfiltered", new JsonNumber (playerList.Count)); 111 // result.Add ("firstResult", new JsonNumber (firstEntry)); 112 // result.Add ("players", playersJsResult); 113 // 114 // WebUtils.WriteJson (_context.Response, result); 115 // } 116 // 117 // private IEnumerable<JsonObject> ExecuteFilter (IEnumerable<JsonObject> _list, string _filterCol, 118 // string _filterVal) { 119 // if (!_list.Any()) { 120 // return _list; 121 // } 122 // 123 // if (_list.First ().ContainsKey (_filterCol)) { 124 // Type colType = _list.First () [_filterCol].GetType (); 125 // if (colType == typeof (JsonNumber)) { 126 // return ExecuteNumberFilter (_list, _filterCol, _filterVal); 127 // } 128 // 129 // if (colType == typeof (JsonBoolean)) { 130 // bool value = StringParsers.ParseBool (_filterVal); 131 // return _list.Where (_line => ((JsonBoolean) _line [_filterCol]).GetBool () == value); 132 // } 133 // 134 // if (colType == typeof (JsonString)) { 135 // // regex-match whole ^string$, replace * by .*, ? by .?, + by .+ 136 // _filterVal = _filterVal.Replace ("*", ".*").Replace ("?", ".?").Replace ("+", ".+"); 137 // _filterVal = "^" + _filterVal + "$"; 138 // 139 // //Log.Out ("GetPlayerList: Filter on String with Regex '" + _filterVal + "'"); 140 // Regex matcher = new Regex (_filterVal, RegexOptions.IgnoreCase); 141 // return _list.Where (_line => matcher.IsMatch (((JsonString) _line [_filterCol]).GetString ())); 142 // } 143 // } 144 // 145 // return _list; 146 // } 147 // 148 // 149 // private IEnumerable<JsonObject> ExecuteNumberFilter (IEnumerable<JsonObject> _list, string _filterCol, 150 // string _filterVal) { 151 // // allow value (exact match), =, ==, >=, >, <=, < 152 // Match filterMatch = numberFilterMatcher.Match (_filterVal); 153 // if (filterMatch.Success) { 154 // double value = StringParsers.ParseDouble (filterMatch.Groups [2].Value); 155 // NumberMatchType matchType; 156 // double epsilon = value / 100000; 157 // switch (filterMatch.Groups [1].Value) { 158 // case "": 159 // case "=": 160 // case "==": 161 // matchType = NumberMatchType.Equal; 162 // break; 163 // case ">": 164 // matchType = NumberMatchType.Greater; 165 // break; 166 // case ">=": 167 // case "=>": 168 // matchType = NumberMatchType.GreaterEqual; 169 // break; 170 // case "<": 171 // matchType = NumberMatchType.Lesser; 172 // break; 173 // case "<=": 174 // case "=<": 175 // matchType = NumberMatchType.LesserEqual; 176 // break; 177 // default: 178 // matchType = NumberMatchType.Equal; 179 // break; 180 // } 181 // 182 // return _list.Where (delegate (JsonObject _line) { 183 // double objVal = ((JsonNumber) _line [_filterCol]).GetDouble (); 184 // switch (matchType) { 185 // case NumberMatchType.Greater: 186 // return objVal > value; 187 // case NumberMatchType.GreaterEqual: 188 // return objVal >= value; 189 // case NumberMatchType.Lesser: 190 // return objVal < value; 191 // case NumberMatchType.LesserEqual: 192 // return objVal <= value; 193 // case NumberMatchType.Equal: 194 // default: 195 // return NearlyEqual (objVal, value, epsilon); 196 // } 197 // }); 198 // } 199 // 200 // global::Log.Out ("[Web] GetPlayerList: ignoring invalid filter for number-column '{0}': '{1}'", _filterCol, _filterVal); 201 // return _list; 202 // } 203 // 204 // 205 // private IEnumerable<JsonObject> ExecuteSort (IEnumerable<JsonObject> _list, string _sortCol, bool _ascending) { 206 // if (_list.Count () == 0) { 207 // return _list; 208 // } 209 // 210 // if (_list.First ().ContainsKey (_sortCol)) { 211 // Type colType = _list.First () [_sortCol].GetType (); 212 // if (colType == typeof (JsonNumber)) { 213 // if (_ascending) { 214 // return _list.OrderBy (_line => ((JsonNumber) _line [_sortCol]).GetDouble ()); 215 // } 216 // 217 // return _list.OrderByDescending (_line => ((JsonNumber) _line [_sortCol]).GetDouble ()); 218 // } 219 // 220 // if (colType == typeof (JsonBoolean)) { 221 // if (_ascending) { 222 // return _list.OrderBy (_line => ((JsonBoolean) _line [_sortCol]).GetBool ()); 223 // } 224 // 225 // return _list.OrderByDescending (_line => ((JsonBoolean) _line [_sortCol]).GetBool ()); 226 // } 227 // 228 // if (_ascending) { 229 // return _list.OrderBy (_line => _line [_sortCol].ToString ()); 230 // } 231 // 232 // return _list.OrderByDescending (_line => _line [_sortCol].ToString ()); 233 // } 234 // 235 // return _list; 236 // } 237 // 238 // 239 // private bool NearlyEqual (double _a, double _b, double _epsilon) { 240 // double absA = Math.Abs (_a); 241 // double absB = Math.Abs (_b); 242 // double diff = Math.Abs (_a - _b); 243 // 244 // if (_a == _b) { 245 // return true; 246 // } 247 // 248 // if (_a == 0 || _b == 0 || diff < double.Epsilon) { 249 // return diff < _epsilon; 250 // } 251 // 252 // return diff / (absA + absB) < _epsilon; 253 // } 254 // 255 // private enum NumberMatchType { 256 // Equal, 257 // Greater, 258 // GreaterEqual, 259 // Lesser, 260 // LesserEqual 261 // } 262 // } 263 // }
Note:
See TracChangeset
for help on using the changeset viewer.