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
File:
1 edited

Legend:

Unmodified
Added
Removed
  • binary-improvements2/WebServer/src/WebAPI/AbsRestApi.cs

    r394 r402  
    11using System;
     2using System.Collections.Generic;
    23using System.IO;
    34using System.Net;
    4 using AllocsFixes.JSON;
     5using Utf8Json;
    56
    67namespace Webserver.WebAPI {
     
    910
    1011                public sealed override void HandleRequest (RequestContext _context) {
    11                         JsonNode jsonBody = null;
     12                        IDictionary<string, object> inputJson = null;
     13                        byte[] jsonInputData = null;
     14                       
     15                        if (_context.Request.HasEntityBody) {
     16                                Stream requestInputStream = _context.Request.InputStream;
     17                               
     18                                jsonInputData = new byte[_context.Request.ContentLength64];
     19                                requestInputStream.Read (jsonInputData, 0, (int)_context.Request.ContentLength64);
     20                               
     21                                try {
     22                                        jsonDeserializeSampler.Begin ();
     23                                        inputJson = JsonSerializer.Deserialize<IDictionary<string, object>> (jsonInputData);
     24                                       
     25                                        // Log.Out ("JSON body:");
     26                                        // foreach ((string key, object value) in inputJson) {
     27                                        //      Log.Out ($" - {key} = {value} ({value.GetType ()})");
     28                                        // }
     29                                       
     30                                        jsonDeserializeSampler.End ();
     31                                } catch (Exception e) {
     32                                        jsonDeserializeSampler.End ();
    1233
    13                         if (_context.Request.HasEntityBody) {
    14                                 string body = new StreamReader (_context.Request.InputStream).ReadToEnd ();
    15 
    16                                 if (!string.IsNullOrEmpty (body)) {
    17                                         try {
    18                                                 jsonDeserializeSampler.Begin ();
    19                                                 jsonBody = Parser.Parse (body);
    20                                                 jsonDeserializeSampler.End ();
    21                                         } catch (Exception e) {
    22                                                 jsonDeserializeSampler.End ();
    23 
    24                                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
    25                                                 return;
    26                                         }
     34                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_BODY", e);
     35                                        return;
    2736                                }
    2837                        }
     
    3140                                switch (_context.Request.HttpMethod) {
    3241                                        case "GET":
    33                                                 if (jsonBody != null) {
    34                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "GET_WITH_BODY");
     42                                                if (inputJson != null) {
     43                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "GET_WITH_BODY");
    3544                                                        return;
    3645                                                }
     
    4049                                        case "POST":
    4150                                                if (!string.IsNullOrEmpty (_context.RequestPath)) {
    42                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "POST_WITH_ID");
     51                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "POST_WITH_ID");
    4352                                                        return;
    4453                                                }
    4554
    46                                                 if (jsonBody == null) {
    47                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
     55                                                if (inputJson == null) {
     56                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "POST_WITHOUT_BODY");
    4857                                                        return;
    4958                                                }
    5059
    51                                                 HandleRestPost (_context, jsonBody);
     60                                                HandleRestPost (_context, inputJson, jsonInputData);
    5261                                                return;
    5362                                        case "PUT":
    5463                                                if (string.IsNullOrEmpty (_context.RequestPath)) {
    55                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "PUT_WITHOUT_ID");
     64                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "PUT_WITHOUT_ID");
    5665                                                        return;
    5766                                                }
    5867
    59                                                 if (jsonBody == null) {
    60                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
     68                                                if (inputJson == null) {
     69                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "PUT_WITHOUT_BODY");
    6170                                                        return;
    6271                                                }
    6372
    64                                                 HandleRestPut (_context, jsonBody);
     73                                                HandleRestPut (_context, inputJson, jsonInputData);
    6574                                                return;
    6675                                        case "DELETE":
    6776                                                if (string.IsNullOrEmpty (_context.RequestPath)) {
    68                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, jsonBody, "DELETE_WITHOUT_ID");
     77                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, jsonInputData, "DELETE_WITHOUT_ID");
    6978                                                        return;
    7079                                                }
    7180
    72                                                 if (jsonBody != null) {
    73                                                         SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
     81                                                if (inputJson != null) {
     82                                                        SendErrorResult (_context, HttpStatusCode.BadRequest, null, "DELETE_WITH_BODY");
    7483                                                        return;
    7584                                                }
     
    7887                                                return;
    7988                                        default:
    80                                                 SendEnvelopedResult (_context, null, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
     89                                                SendErrorResult (_context, HttpStatusCode.BadRequest, null, "INVALID_METHOD");
    8190                                                return;
    8291                                }
    8392                        } catch (Exception e) {
    84                                 SendEnvelopedResult (_context, null, HttpStatusCode.InternalServerError, jsonBody, "ERROR_PROCESSING", e);
     93                                SendErrorResult (_context, HttpStatusCode.InternalServerError, jsonInputData, "ERROR_PROCESSING", e);
    8594                        }
    8695                }
    8796
    88                 private static readonly JsonArray emptyData = new JsonArray ();
    89 
    90                 protected void SendEnvelopedResult (RequestContext _context, JsonNode _resultData, HttpStatusCode _statusCode = HttpStatusCode.OK,
    91                         JsonNode _jsonInputBody = null, string _errorCode = null, Exception _exception = null) {
    92                         JsonObject meta = new JsonObject ();
    93 
    94                         meta.Add ("serverTime", new JsonString (DateTime.Now.ToString ("o")));
    95                         if (!string.IsNullOrEmpty (_errorCode)) {
    96                                 meta.Add ("requestMethod", new JsonString (_context.Request.HttpMethod));
    97                                 meta.Add ("requestSubpath", new JsonString (_context.RequestPath));
    98                                 meta.Add ("requestBody", new JsonString (_jsonInputBody?.ToString () ?? "-empty-"));
    99                                 meta.Add ("errorCode", new JsonString (_errorCode));
    100                                 if (_exception != null) {
    101                                         meta.Add ("exceptionMessage", new JsonString (_exception.Message));
    102                                         meta.Add ("exceptionTrace", new JsonString (_exception.StackTrace));
    103                                 }
    104                         }
    105 
    106                         JsonObject envelope = new JsonObject ();
    107                         envelope.Add ("meta", meta);
    108                         envelope.Add ("data", _resultData ?? emptyData);
    109 
    110                         WebUtils.WriteJson (_context.Response, envelope, _statusCode);
     97                protected void SendErrorResult (RequestContext _context, HttpStatusCode _statusCode, byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
     98                        PrepareEnvelopedResult (out JsonWriter writer);
     99                        writer.WriteRaw (JsonEmptyData);
     100                        SendEnvelopedResult (_context, ref writer, _statusCode, _jsonInputData, _errorCode, _exception);
    111101                }
    112102
    113                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out int _value) {
     103                static AbsRestApi () {
     104                        JsonWriter writer = new JsonWriter ();
     105                        writer.WriteBeginArray ();
     106                        writer.WriteEndArray ();
     107                        JsonEmptyData = writer.ToUtf8ByteArray ();
     108                }
     109
     110                protected static readonly byte[] JsonEmptyData;
     111               
     112                protected void PrepareEnvelopedResult (out JsonWriter _writer) {
     113                        WebUtils.PrepareEnvelopedResult (out _writer);
     114                }
     115
     116                protected void SendEnvelopedResult (RequestContext _context, ref JsonWriter _writer, HttpStatusCode _statusCode = HttpStatusCode.OK,
     117                        byte[] _jsonInputData = null, string _errorCode = null, Exception _exception = null) {
     118                       
     119                        WebUtils.SendEnvelopedResult (_context, ref _writer, _statusCode, _jsonInputData, _errorCode, _exception);
     120                }
     121
     122                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out int _value) {
    114123                        _value = default;
    115124                       
    116                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     125                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    117126                                return false;
    118127                        }
    119128
    120                         if (!(fieldNode is JsonValue valueField)) {
     129                        if (fieldNode is not double value) {
    121130                                return false;
    122131                        }
    123132
    124133                        try {
    125                                 _value = valueField.AsInt;
     134                                _value = (int)value;
    126135                                return true;
    127136                        } catch (Exception) {
     
    130139                }
    131140
    132                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out double _value) {
     141                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out double _value) {
    133142                        _value = default;
    134143                       
    135                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     144                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    136145                                return false;
    137146                        }
    138147
    139                         if (!(fieldNode is JsonValue valueField)) {
     148                        if (fieldNode is not double value) {
    140149                                return false;
    141150                        }
    142151
    143152                        try {
    144                                 _value = valueField.AsDouble;
     153                                _value = value;
    145154                                return true;
    146155                        } catch (Exception) {
     
    149158                }
    150159
    151                 protected bool TryGetJsonField (JsonObject _jsonObject, string _fieldName, out string _value) {
     160                protected bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out string _value) {
    152161                        _value = default;
    153162                       
    154                         if (!_jsonObject.TryGetValue (_fieldName, out JsonNode fieldNode)) {
     163                        if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
    155164                                return false;
    156165                        }
    157166
    158                         if (!(fieldNode is JsonValue valueField)) {
     167                        if (fieldNode is not string value) {
    159168                                return false;
    160169                        }
    161170
    162171                        try {
    163                                 _value = valueField.AsString;
     172                                _value = value;
    164173                                return true;
    165174                        } catch (Exception) {
     
    168177                }
    169178
    170                 protected abstract void HandleRestGet (RequestContext _context);
     179                protected virtual void HandleRestGet (RequestContext _context) {
     180                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
     181                }
    171182
    172                 protected abstract void HandleRestPost (RequestContext _context, JsonNode _jsonBody);
     183                protected virtual void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     184                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
     185                }
    173186
    174                 protected abstract void HandleRestPut (RequestContext _context, JsonNode _jsonBody);
     187                protected virtual void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
     188                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, _jsonInputData, "Unsupported");
     189                }
    175190
    176                 protected abstract void HandleRestDelete (RequestContext _context);
     191                protected virtual void HandleRestDelete (RequestContext _context) {
     192                        SendErrorResult (_context, HttpStatusCode.MethodNotAllowed, null, "Unsupported");
     193                }
    177194        }
    178195}
Note: See TracChangeset for help on using the changeset viewer.