Ignore:
Timestamp:
Jan 27, 2023, 7:28:00 PM (22 months ago)
Author:
alloc
Message:
  • Major refactoring
  • Using Utf8Json for (de)serialization
  • Moving APIs to REST
  • Removing dependencies from WebServer and MapRenderer to ServerFixes
Location:
binary-improvements2/WebServer/src/UrlHandlers
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • binary-improvements2/WebServer/src/UrlHandlers/ApiHandler.cs

    r399 r402  
    4545                private void addApi (AbsWebAPI _api) {
    4646                        apis.Add (_api.Name, _api);
    47                         WebPermissions.Instance.AddKnownModule ("webapi." + _api.Name, _api.DefaultPermissionLevel ());
     47                        WebPermissions.Instance.AddKnownModule ($"webapi.{_api.Name}", _api.DefaultPermissionLevel ());
    4848                }
    4949
     
    9292
    9393                private bool IsAuthorizedForApi (string _apiName, int _permissionLevel) {
    94                         return WebPermissions.Instance.ModuleAllowedWithLevel ("webapi." + _apiName, _permissionLevel);
     94                        return WebPermissions.Instance.ModuleAllowedWithLevel ($"webapi.{_apiName}", _permissionLevel);
    9595                }
    9696        }
  • binary-improvements2/WebServer/src/UrlHandlers/ItemIconHandler.cs

    r399 r402  
    33using System.IO;
    44using System.Net;
    5 using AllocsFixes;
    65using UnityEngine;
    76using Object = UnityEngine.Object;
     
    4544                                _context.Response.StatusCode = (int) HttpStatusCode.NotFound;
    4645                                if (logMissingFiles) {
    47                                         Log.Out ("[Web] IconHandler: FileNotFound: \"" + _context.RequestPath + "\" ");
     46                                        Log.Out ($"[Web] IconHandler: FileNotFound: \"{_context.RequestPath}\" ");
    4847                                }
    4948                        }
     49                }
     50
     51                private class LoadingStats {
     52                        public int Files;
     53                        public int Tints;
     54                        public readonly MicroStopwatch MswTotal = new MicroStopwatch (false);
     55                        public readonly MicroStopwatch MswLoading = new MicroStopwatch (false);
     56                        public readonly MicroStopwatch MswEncoding = new MicroStopwatch (false);
     57                        public readonly MicroStopwatch MswTinting = new MicroStopwatch (false);
    5058                }
    5159
     
    5765                                }
    5866
    59                                 MicroStopwatch microStopwatch = new MicroStopwatch ();
     67                                LoadingStats stats = new LoadingStats ();
     68                                stats?.MswTotal.Start ();
    6069
    6170                                // Get list of used tints for all items
     
    7281
    7382                                        string name = ic.GetIconName ();
    74                                         if (!tintedIcons.ContainsKey (name)) {
    75                                                 tintedIcons.Add (name, new List<Color> ());
     83                                        if (!tintedIcons.TryGetValue (name, out List<Color> tintsList)) {
     84                                                tintsList = new List<Color> ();
     85                                                tintedIcons.Add (name, tintsList);
    7686                                        }
    7787
    78                                         List<Color> list = tintedIcons [name];
    79                                         list.Add (tintColor);
     88                                        tintsList.Add (tintColor);
    8089                                }
    8190
    8291                                try {
    83                                         loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons);
     92                                        loadIconsFromFolder (GameIO.GetGameDir ("Data/ItemIcons"), tintedIcons, stats);
    8493                                } catch (Exception e) {
    8594                                        Log.Error ("[Web] Failed loading icons from base game");
     
    9099                                foreach (Mod mod in ModManager.GetLoadedMods ()) {
    91100                                        try {
    92                                                 string modIconsPath = mod.Path + "/ItemIcons";
    93                                                 loadIconsFromFolder (modIconsPath, tintedIcons);
     101                                                string modIconsPath = $"{mod.Path}/ItemIcons";
     102                                                loadIconsFromFolder (modIconsPath, tintedIcons, stats);
    94103                                        } catch (Exception e) {
    95                                                 Log.Error ("[Web] Failed loading icons from mod " + mod.ModInfo.Name.Value);
     104                                                Log.Error ($"[Web] Failed loading icons from mod {mod.Name}");
    96105                                                Log.Exception (e);
    97106                                        }
    98107                                }
     108                               
     109                                loaded = true;
    99110
    100                                 loaded = true;
    101                                 Log.Out ("[Web] IconHandler: Icons loaded - {0} ms", microStopwatch.ElapsedMilliseconds);
     111                                if (stats == null) {
     112                                        Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons");
     113                                } else {
     114                                        stats?.MswTotal.Stop ();
     115                                        Log.Out ($"[Web] IconHandler: Loaded {icons.Count} icons ({stats.Files} source images with {stats.Tints} tints applied)");
     116                                        Log.Out ($"[Web] IconHandler: Total time {stats.MswTotal.ElapsedMilliseconds} ms, loading files {stats.MswLoading.ElapsedMilliseconds} ms, tinting files {stats.MswTinting.ElapsedMilliseconds} ms, encoding files {stats.MswEncoding.ElapsedMilliseconds} ms");
     117
     118                                        int totalSize = 0;
     119                                        foreach ((string _, byte[] iconData) in icons) {
     120                                                totalSize += iconData.Length;
     121                                        }
     122                                       
     123                                        Log.Out ($"[Web] IconHandler: Cached {totalSize / 1024} KiB");
     124                                }
    102125
    103126                                return true;
     
    105128                }
    106129
    107                 private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons) {
     130                private void loadIconsFromFolder (string _path, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
    108131                        if (!Directory.Exists (_path)) {
    109132                                return;
     
    118141                                        string name = Path.GetFileNameWithoutExtension (file);
    119142                                        Texture2D tex = new Texture2D (1, 1, TextureFormat.ARGB32, false);
    120                                         if (!tex.LoadImage (File.ReadAllBytes (file))) {
     143                                       
     144                                        _stats?.MswLoading.Start ();
     145                                        byte[] sourceBytes = File.ReadAllBytes (file);
     146                                        if (!tex.LoadImage (sourceBytes)) {
     147                                                _stats?.MswLoading.Stop ();
    121148                                                continue;
    122149                                        }
     150                                        _stats?.MswLoading.Stop ();
    123151
    124                                         AddIcon (name, tex, _tintedIcons);
     152                                        AddIcon (name, sourceBytes, tex, _tintedIcons, _stats);
    125153
    126154                                        Object.Destroy (tex);
     
    131159                }
    132160
    133                 private void AddIcon (string _name, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons) {
    134                         icons [_name + "__FFFFFF"] = _tex.EncodeToPNG ();
     161                private void AddIcon (string _name, byte[] _sourceBytes, Texture2D _tex, Dictionary<string, List<Color>> _tintedIcons, LoadingStats _stats) {
     162                        _stats?.MswEncoding.Start ();
     163                        icons [$"{_name}__FFFFFF"] = _sourceBytes;
     164                        _stats?.MswEncoding.Stop ();
    135165
    136                         if (!_tintedIcons.ContainsKey (_name)) {
     166                        if (_stats != null) {
     167                                _stats.Files++;
     168                        }
     169
     170                        if (!_tintedIcons.TryGetValue (_name, out List<Color> tintsList)) {
    137171                                return;
    138172                        }
    139173
    140                         foreach (Color c in _tintedIcons [_name]) {
    141                                 string tintedName = _name + "__" + AllocsUtils.ColorToHex (c);
     174                        foreach (Color c in tintsList) {
     175                                string tintedName = $"{_name}__{c.ToHexCode ()}";
    142176                                if (icons.ContainsKey (tintedName)) {
    143177                                        continue;
     
    146180                                Texture2D tintedTex = new Texture2D (_tex.width, _tex.height, TextureFormat.ARGB32, false);
    147181
    148                                 for (int x = 0; x < _tex.width; x++) {
    149                                         for (int y = 0; y < _tex.height; y++) {
    150                                                 tintedTex.SetPixel (x, y, _tex.GetPixel (x, y) * c);
    151                                         }
    152                                 }
     182                                _stats?.MswTinting.Start ();
     183                                TextureUtils.ApplyTint (_tex, tintedTex, c);
     184                                _stats?.MswTinting.Stop ();
    153185
     186                                _stats?.MswEncoding.Start ();
    154187                                icons [tintedName] = tintedTex.EncodeToPNG ();
     188                                _stats?.MswEncoding.Stop ();
    155189
    156190                                Object.Destroy (tintedTex);
     191
     192                                if (_stats != null) {
     193                                        _stats.Tints++;
     194                                }
    157195                        }
    158196                }
     197               
    159198        }
    160199}
  • binary-improvements2/WebServer/src/UrlHandlers/RewriteHandler.cs

    r391 r402  
    1010
    1111                public override void HandleRequest (RequestContext _context) {
    12                         _context.RequestPath = fixedTarget ? target : target + _context.RequestPath.Remove (0, urlBasePath.Length);
     12                        _context.RequestPath = fixedTarget ? target : $"{target}{_context.RequestPath.Remove (0, urlBasePath.Length)}";
    1313                        parent.ApplyPathHandler (_context);
    1414                }
  • binary-improvements2/WebServer/src/UrlHandlers/SessionHandler.cs

    r399 r402  
    11using System;
     2using System.Collections.Generic;
     3using System.IO;
    24using System.Net;
     5using Platform.Steam;
     6using Utf8Json;
    37
    48namespace Webserver.UrlHandlers {
     
    610                private const string pageBasePath = "/app";
    711                private const string pageErrorPath = "/app/error/";
     12               
    813                private const string steamOpenIdVerifyUrl = "verifysteamopenid";
    914                private const string steamLoginUrl = "loginsteam";
     15                private const string userPassLoginUrl = "login";
    1016
    1117                private readonly ConnectionHandler connectionHandler;
     
    3743                                return;
    3844                        }
     45                       
     46                        if (subpath.StartsWith (userPassLoginUrl)) {
     47                                HandleUserPassLogin (_context);
     48                                return;
     49                        }
    3950
    4051                        _context.Response.Redirect (pageErrorPath + "InvalidSessionsCommand");
    4152                }
    4253
     54                private void HandleUserPassLogin (RequestContext _context) {
     55                        if (!_context.Request.HasEntityBody) {
     56                                _context.Response.Redirect (pageErrorPath + "NoLoginData");
     57                                return;
     58                        }
     59
     60                        Stream requestInputStream = _context.Request.InputStream;
     61
     62                        byte[] jsonInputData = new byte[_context.Request.ContentLength64];
     63                        requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
     64
     65                        IDictionary<string, object> inputJson;
     66                        try {
     67                                inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
     68                        } catch (Exception e) {
     69                                Log.Error ("Error deserializing JSON from user/password login:");
     70                                Log.Exception (e);
     71                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     72                                return;
     73                        }
     74
     75                        if (!inputJson.TryGetValue ("username", out object fieldNode) || fieldNode is not string username) {
     76                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     77                                return;
     78                        }
     79
     80                        if (!inputJson.TryGetValue ("password", out fieldNode) || fieldNode is not string password) {
     81                                _context.Response.Redirect (pageErrorPath + "InvalidLoginJson");
     82                                return;
     83                        }
     84
     85                        // TODO: Apply login
     86
     87                        string remoteEndpointString = _context.Request.RemoteEndPoint!.ToString ();
     88
     89                        if (username != "test" || password != "123") {
     90                                // TODO: failed login
     91                                Log.Out ($"[Web] User/pass login failed from {remoteEndpointString}");
     92                                _context.Response.Redirect (pageErrorPath + "UserPassInvalid");
     93                                return;
     94                        }
     95                       
     96                        try {
     97                                // TODO: Match username/password to UserIdentifierAbs / serveradmins.xml
     98                               
     99                                WebConnection con = connectionHandler.LogIn (new UserIdentifierSteam (76561198066968172ul), _context.Request.RemoteEndPoint.Address);
     100                                int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
     101                                Log.Out ($"[Web] User/pass login from {remoteEndpointString} with ID {con.UserId}, permission level {level}");
     102
     103                                Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
     104                                        Expired = false,
     105                                        Expires = DateTime.MinValue,
     106                                        HttpOnly = true,
     107                                        Secure = false
     108                                };
     109                                _context.Response.AppendCookie (cookie);
     110                                _context.Response.Redirect (pageBasePath);
     111
     112                                return;
     113                        } catch (Exception e) {
     114                                Log.Error ("[Web] Error during user/pass login:");
     115                                Log.Exception (e);
     116                        }
     117
     118                        _context.Response.Redirect (pageErrorPath + "UserPassLoginFailed");
     119                }
     120
    43121                private void HandleSteamLogin (RequestContext _context) {
    44                         string host = (WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://") + _context.Request.UserHostName;
    45                         string url = OpenID.GetOpenIdLoginUrl (host, host + urlBasePath + steamOpenIdVerifyUrl);
     122                        string host = $"{(WebUtils.IsSslRedirected (_context.Request) ? "https://" : "http://")}{_context.Request.UserHostName}";
     123                        string url = OpenID.GetOpenIdLoginUrl (host, $"{host}{urlBasePath}{steamOpenIdVerifyUrl}");
    46124                        _context.Response.Redirect (url);
    47125                }
     
    68146                                ulong id = OpenID.Validate (_context.Request);
    69147                                if (id > 0) {
    70                                         WebConnection con = connectionHandler.LogIn (id, _context.Request.RemoteEndPoint.Address);
     148                                        WebConnection con = connectionHandler.LogIn (new UserIdentifierSteam (id), _context.Request.RemoteEndPoint.Address);
    71149                                        int level = GameManager.Instance.adminTools.GetUserPermissionLevel (con.UserId);
    72                                         Log.Out ("[Web] Steam OpenID login from {0} with ID {1}, permission level {2}",
    73                                                 remoteEndpointString, con.UserId, level);
     150                                        Log.Out ($"[Web] Steam OpenID login from {remoteEndpointString} with ID {con.UserId}, permission level {level}");
    74151
    75152                                        Cookie cookie = new Cookie ("sid", con.SessionID, "/") {
  • binary-improvements2/WebServer/src/UrlHandlers/SseHandler.cs

    r399 r402  
    3939                        base.SetBasePathAndParent (_parent, _relativePath);
    4040
    41                         queueThead = ThreadManager.StartThread ("SSE-Processing_" + urlBasePath, QueueProcessThread, ThreadPriority.BelowNormal,
     41                        queueThead = ThreadManager.StartThread ($"SSE-Processing_{urlBasePath}", QueueProcessThread, ThreadPriority.BelowNormal,
    4242                                _useRealThread: true);
    4343                }
     
    4949                }
    5050
     51                // ReSharper disable once MemberCanBePrivate.Global
    5152                public void AddEvent (string _eventName, AbsEvent _eventInstance) {
    5253                        events.Add (_eventName, _eventInstance);
    53                         WebPermissions.Instance.AddKnownModule ("webevent." + _eventName, _eventInstance.DefaultPermissionLevel ());
     54                        WebPermissions.Instance.AddKnownModule ($"webevent.{_eventName}", _eventInstance.DefaultPermissionLevel ());
    5455                }
    5556
     
    8889
    8990                private bool IsAuthorizedForEvent (string _eventName, int _permissionLevel) {
    90                         return WebPermissions.Instance.ModuleAllowedWithLevel ("webevent." + _eventName, _permissionLevel);
     91                        return WebPermissions.Instance.ModuleAllowedWithLevel ($"webevent.{_eventName}", _permissionLevel);
    9192                }
    9293
  • binary-improvements2/WebServer/src/UrlHandlers/StaticHandler.cs

    r399 r402  
    11using System.IO;
    22using System.Net;
    3 using AllocsFixes.FileCache;
     3using Webserver.FileCache;
    44
    55namespace Webserver.UrlHandlers {
     
    1111                public StaticHandler (string _filePath, AbstractCache _cache, bool _logMissingFiles,
    1212                        string _moduleName = null) : base (_moduleName) {
    13                         datapath = _filePath + (_filePath [_filePath.Length - 1] == '/' ? "" : "/");
     13                        datapath = $"{_filePath}{(_filePath [^1] == '/' ? "" : "/")}";
    1414                        cache = _cache;
    1515                        logMissingFiles = _logMissingFiles;
     
    1919                        string fn = _context.RequestPath.Remove (0, urlBasePath.Length);
    2020
    21                         byte[] content = cache.GetFileContent (datapath + fn);
     21                        byte[] content = cache.GetFileContent ($"{datapath}{fn}");
    2222
    2323                        if (content != null) {
     
    2828                                _context.Response.StatusCode = (int) HttpStatusCode.NotFound;
    2929                                if (logMissingFiles) {
    30                                         Log.Warning ("[Web] Static: FileNotFound: \"" + _context.RequestPath + "\" @ \"" + datapath + fn + "\"");
     30                                        Log.Warning ($"[Web] Static: FileNotFound: \"{_context.RequestPath}\" @ \"{datapath}{fn}\"");
    3131                                }
    3232                        }
  • binary-improvements2/WebServer/src/UrlHandlers/UserStatusHandler.cs

    r391 r402  
    1 using AllocsFixes.JSON;
     1using Utf8Json;
    22
    33namespace Webserver.UrlHandlers {
     
    66                }
    77
     8                private static readonly byte[] jsonLoggedInKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("loggedIn");
     9                private static readonly byte[] jsonUsernameKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("username");
     10                private static readonly byte[] jsonPermissionsKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("permissions");
     11
     12                private static readonly byte[] jsonModuleKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("module");
     13                private static readonly byte[] jsonAllowedKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("allowed");
     14
    815                public override void HandleRequest (RequestContext _context) {
    9                         JsonObject result = new JsonObject ();
     16                        WebUtils.PrepareEnvelopedResult (out JsonWriter writer);
     17                       
     18                        writer.WriteRaw (jsonLoggedInKey);
     19                        writer.WriteBoolean (_context.Connection != null);
     20                       
     21                        writer.WriteRaw (jsonUsernameKey);
     22                        writer.WriteString (_context.Connection != null ? _context.Connection.UserId.ToString () : string.Empty);
     23                       
     24                        writer.WriteRaw (jsonPermissionsKey);
     25                        writer.WriteBeginArray ();
    1026
    11                         result.Add ("loggedin", new JsonBoolean (_context.Connection != null));
    12                         result.Add ("username", new JsonString (_context.Connection != null ? _context.Connection.UserId.ToString () : string.Empty));
     27                        bool first = true;
     28                        foreach (WebPermissions.WebModulePermission perm in WebPermissions.Instance.GetModules ()) {
     29                                if (!first) {
     30                                        writer.WriteValueSeparator ();
     31                                }
    1332
    14                         JsonArray perms = new JsonArray ();
    15                         foreach (WebPermissions.WebModulePermission perm in WebPermissions.Instance.GetModules ()) {
    16                                 JsonObject permObj = new JsonObject ();
    17                                 permObj.Add ("module", new JsonString (perm.module));
    18                                 permObj.Add ("allowed", new JsonBoolean (perm.permissionLevel >= _context.PermissionLevel));
    19                                 perms.Add (permObj);
     33                                first = false;
     34                               
     35                                writer.WriteRaw (jsonModuleKey);
     36                                writer.WriteString (perm.module);
     37                               
     38                                writer.WriteRaw (jsonAllowedKey);
     39                                writer.WriteBoolean (perm.permissionLevel >= _context.PermissionLevel);
     40                               
     41                                writer.WriteEndObject ();
    2042                        }
    2143
    22                         result.Add ("permissions", perms);
    23 
    24                         WebUtils.WriteJson (_context.Response, result);
     44                        writer.WriteEndArray ();
     45                       
     46                        writer.WriteEndObject ();
     47                       
     48                        WebUtils.SendEnvelopedResult (_context, ref writer);
    2549                }
    2650        }
Note: See TracChangeset for help on using the changeset viewer.