source: binary-improvements/MapRendering/Web/API/GetPlayerList.cs@ 446

Last change on this file since 446 was 446, checked in by alloc, 17 months ago

24_27_41

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