mirror of
https://github.com/BlossomiShymae/Needlework.Net.git
synced 2025-12-06 18:20:47 +01:00
feat: Add Game Client to Endpoints
This commit is contained in:
@@ -43,7 +43,7 @@ namespace Needlework.Net
|
||||
var lcuSchemaRaw = reader.Read(lcuSchemaStream, out var _);
|
||||
_lcuSchemaDocument = new Document(lcuSchemaRaw);
|
||||
|
||||
var lolClientStream = await _httpClient.GetStreamAsync("https://raw.githubusercontent.com/BlossomiShymae/poroschema/refs/heads/main/schemas/lolclient.json");
|
||||
var lolClientStream = await _httpClient.GetStreamAsync("https://raw.githubusercontent.com/AlsoSylv/Irelia/refs/heads/master/schemas/game_schema.json");
|
||||
var lolClientRaw = reader.Read(lolClientStream, out var _);
|
||||
_lolClientDocument = new Document(lolClientRaw);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Needlework.Net.ViewModels.Shared;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages;
|
||||
@@ -14,19 +15,19 @@ public partial class ConsoleViewModel : PageBase
|
||||
public IAvaloniaList<string> RequestPaths { get; } = new AvaloniaList<string>();
|
||||
|
||||
[ObservableProperty] private bool _isBusy = true;
|
||||
[ObservableProperty] private LcuRequestViewModel _lcuRequest;
|
||||
[ObservableProperty] private RequestViewModel _request;
|
||||
|
||||
private readonly DataSource _dataSource;
|
||||
|
||||
public ConsoleViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, DataSource dataSource) : base("Console", "terminal", -200)
|
||||
public ConsoleViewModel(ILogger<RequestViewModel> requestViewModelLogger, DataSource dataSource, HttpClient httpClient) : base("Console", "terminal", -200)
|
||||
{
|
||||
_lcuRequest = new(lcuRequestViewModelLogger);
|
||||
_request = new(requestViewModelLogger, Endpoints.Tab.LCU, httpClient);
|
||||
_dataSource = dataSource;
|
||||
}
|
||||
|
||||
public override async Task InitializeAsync()
|
||||
{
|
||||
var document = await _dataSource.GetLolClientDocumentAsync();
|
||||
var document = await _dataSource.GetLcuSchemaDocumentAsync();
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
RequestPaths.Clear();
|
||||
@@ -39,6 +40,6 @@ public partial class ConsoleViewModel : PageBase
|
||||
[RelayCommand]
|
||||
private async Task SendRequest()
|
||||
{
|
||||
await LcuRequest.ExecuteAsync();
|
||||
await Request.ExecuteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ public partial class EndpointViewModel : ObservableObject
|
||||
|
||||
public event EventHandler<string>? PathOperationSelected;
|
||||
|
||||
public EndpointViewModel(string endpoint, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||
public EndpointViewModel(string endpoint, ILogger<RequestViewModel> requestViewModelLogger, Models.Document document, Tab tab, System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
PathOperations = new AvaloniaList<PathOperationViewModel>(lcuSchemaDocument.Plugins[endpoint].Select(x => new PathOperationViewModel(x, lcuRequestViewModelLogger, lcuSchemaDocument)));
|
||||
PathOperations = new AvaloniaList<PathOperationViewModel>(document.Plugins[endpoint].Select(x => new PathOperationViewModel(x, requestViewModelLogger, document, tab, httpClient)));
|
||||
FilteredPathOperations = new AvaloniaList<PathOperationViewModel>(PathOperations);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,27 @@ public partial class EndpointsNavigationViewModel : ObservableObject
|
||||
|
||||
[ObservableProperty] private ObservableObject _activeViewModel;
|
||||
[ObservableProperty] private ObservableObject _endpointsViewModel;
|
||||
[ObservableProperty] private string _title = string.Empty;
|
||||
[ObservableProperty] private string _title;
|
||||
|
||||
private readonly Action<string?, Guid> _onEndpointNavigation;
|
||||
private readonly Tab _tab;
|
||||
|
||||
public EndpointsNavigationViewModel(IAvaloniaList<string> plugins, Action<string?, Guid> onEndpointNavigation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||
public EndpointsNavigationViewModel(IAvaloniaList<string> plugins, Action<string?, Guid> onEndpointNavigation, ILogger<RequestViewModel> requestViewModelLogger, Models.Document document, Tab tab, System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(plugins, OnClicked, lcuRequestViewModelLogger, lcuSchemaDocument);
|
||||
_activeViewModel = _endpointsViewModel = new EndpointsViewModel(plugins, OnClicked, requestViewModelLogger, document, tab, httpClient);
|
||||
_onEndpointNavigation = onEndpointNavigation;
|
||||
_tab = tab;
|
||||
_title = GetTitle(tab);
|
||||
}
|
||||
|
||||
private string GetTitle(Tab tab)
|
||||
{
|
||||
return tab switch
|
||||
{
|
||||
Tab.LCU => "LCU",
|
||||
Tab.GameClient => "Game Client",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private void OnClicked(ObservableObject viewModel)
|
||||
@@ -28,7 +41,7 @@ public partial class EndpointsNavigationViewModel : ObservableObject
|
||||
ActiveViewModel = viewModel;
|
||||
if (viewModel is EndpointViewModel endpoint)
|
||||
{
|
||||
Title = endpoint.Title;
|
||||
Title = $"{GetTitle(_tab)} - {endpoint.Title}";
|
||||
_onEndpointNavigation.Invoke(endpoint.Title, Guid);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +50,7 @@ public partial class EndpointsNavigationViewModel : ObservableObject
|
||||
private void GoBack()
|
||||
{
|
||||
ActiveViewModel = EndpointsViewModel;
|
||||
Title = string.Empty;
|
||||
Title = GetTitle(_tab);
|
||||
_onEndpointNavigation.Invoke(null, Guid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,22 @@
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Needlework.Net.Models;
|
||||
using Needlework.Net.ViewModels.Shared;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
public enum Tab
|
||||
{
|
||||
LCU,
|
||||
GameClient
|
||||
}
|
||||
|
||||
public partial class EndpointsTabViewModel : PageBase
|
||||
{
|
||||
public IAvaloniaList<string> Plugins { get; } = new AvaloniaList<string>();
|
||||
@@ -18,32 +25,41 @@ public partial class EndpointsTabViewModel : PageBase
|
||||
|
||||
[ObservableProperty] private bool _isBusy = true;
|
||||
|
||||
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
||||
private readonly ILogger<RequestViewModel> _requestViewModelLogger;
|
||||
private readonly DataSource _dataSource;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public EndpointsTabViewModel(ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, DataSource dataSource) : base("Endpoints", "list-alt", -500)
|
||||
public EndpointsTabViewModel(ILogger<RequestViewModel> requestViewModelLogger, DataSource dataSource, HttpClient httpClient) : base("Endpoints", "list-alt", -500)
|
||||
{
|
||||
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
||||
_requestViewModelLogger = requestViewModelLogger;
|
||||
_dataSource = dataSource;
|
||||
WeakReferenceMessenger.Default.RegisterAll(this);
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
public override async Task InitializeAsync()
|
||||
{
|
||||
var document = await _dataSource.GetLcuSchemaDocumentAsync();
|
||||
Plugins.Clear();
|
||||
Plugins.AddRange(document.Plugins.Keys);
|
||||
await Dispatcher.UIThread.Invoke(AddEndpoint);
|
||||
await Dispatcher.UIThread.Invoke(async () => await AddEndpoint(Tab.LCU));
|
||||
IsBusy = false;
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task AddEndpoint()
|
||||
private async Task AddEndpoint(Tab tab)
|
||||
{
|
||||
var lcuSchemaDocument = await _dataSource.GetLcuSchemaDocumentAsync();
|
||||
Document document = tab switch
|
||||
{
|
||||
Tab.LCU => await _dataSource.GetLcuSchemaDocumentAsync(),
|
||||
Tab.GameClient => await _dataSource.GetLolClientDocumentAsync(),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
Plugins.Clear();
|
||||
Plugins.AddRange(document.Plugins.Keys);
|
||||
|
||||
var vm = new EndpointsNavigationViewModel(Plugins, OnEndpointNavigation, _requestViewModelLogger, document, tab, _httpClient);
|
||||
Endpoints.Add(new()
|
||||
{
|
||||
Content = new EndpointsNavigationViewModel(Plugins, OnEndpointNavigation, _lcuRequestViewModelLogger, lcuSchemaDocument),
|
||||
Content = vm,
|
||||
Header = vm.Title,
|
||||
Selected = true
|
||||
});
|
||||
}
|
||||
@@ -54,7 +70,7 @@ public partial class EndpointsTabViewModel : PageBase
|
||||
{
|
||||
if (endpoint.Content.Guid.Equals(guid))
|
||||
{
|
||||
endpoint.Header = title ?? "Endpoints";
|
||||
endpoint.Header = endpoint.Content.Title;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +79,7 @@ public partial class EndpointsTabViewModel : PageBase
|
||||
|
||||
public partial class EndpointItem : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private string _header = "Endpoints";
|
||||
[ObservableProperty] private string _header = string.Empty;
|
||||
public IconSource IconSource { get; set; } = new SymbolIconSource() { Symbol = Symbol.Document, FontSize = 20.0, Foreground = Avalonia.Media.Brushes.White };
|
||||
public bool Selected { get; set; } = false;
|
||||
public required EndpointsNavigationViewModel Content { get; init; }
|
||||
|
||||
@@ -6,6 +6,7 @@ using Needlework.Net.Models;
|
||||
using Needlework.Net.ViewModels.Shared;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
|
||||
@@ -19,16 +20,20 @@ public partial class EndpointsViewModel : ObservableObject
|
||||
|
||||
public Action<ObservableObject> OnClicked { get; }
|
||||
|
||||
private readonly ILogger<LcuRequestViewModel> _lcuRequestViewModelLogger;
|
||||
private readonly Document _lcuSchemaDocument;
|
||||
private readonly ILogger<RequestViewModel> _requestViewModelLogger;
|
||||
private readonly Document _document;
|
||||
private readonly Tab _tab;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public EndpointsViewModel(IAvaloniaList<string> plugins, Action<ObservableObject> onClicked, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Models.Document lcuSchemaDocument)
|
||||
public EndpointsViewModel(IAvaloniaList<string> plugins, Action<ObservableObject> onClicked, ILogger<RequestViewModel> requestViewModelLogger, Models.Document document, Tab tab, System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
Plugins = new AvaloniaList<string>(plugins);
|
||||
Query = new AvaloniaList<string>(plugins);
|
||||
OnClicked = onClicked;
|
||||
_lcuRequestViewModelLogger = lcuRequestViewModelLogger;
|
||||
_lcuSchemaDocument = lcuSchemaDocument;
|
||||
_requestViewModelLogger = requestViewModelLogger;
|
||||
_document = document;
|
||||
_tab = tab;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
partial void OnSearchChanged(string value)
|
||||
@@ -45,6 +50,6 @@ public partial class EndpointsViewModel : ObservableObject
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) return;
|
||||
|
||||
OnClicked.Invoke(new EndpointViewModel(value, _lcuRequestViewModelLogger, _lcuSchemaDocument));
|
||||
OnClicked.Invoke(new EndpointViewModel(value, _requestViewModelLogger, _document, _tab, _httpClient));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Needlework.Net.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
@@ -21,23 +22,23 @@ public partial class OperationViewModel : ObservableObject
|
||||
public IAvaloniaReadOnlyList<ParameterViewModel> QueryParameters { get; }
|
||||
public string? RequestTemplate { get; }
|
||||
|
||||
public OperationViewModel(OpenApiOperation operation, Models.Document lcuSchemaDocument)
|
||||
public OperationViewModel(OpenApiOperation operation, Models.Document document)
|
||||
{
|
||||
Summary = operation.Summary ?? string.Empty;
|
||||
Description = operation.Description ?? string.Empty;
|
||||
IsRequestBody = operation.RequestBody != null;
|
||||
ReturnType = GetReturnType(operation.Responses);
|
||||
RequestClasses = GetRequestClasses(operation.RequestBody, lcuSchemaDocument);
|
||||
ResponseClasses = GetResponseClasses(operation.Responses, lcuSchemaDocument);
|
||||
RequestClasses = GetRequestClasses(operation.RequestBody, document);
|
||||
ResponseClasses = GetResponseClasses(operation.Responses, document);
|
||||
PathParameters = GetParameters(operation.Parameters, ParameterLocation.Path);
|
||||
QueryParameters = GetParameters(operation.Parameters, ParameterLocation.Query);
|
||||
RequestBodyType = GetRequestBodyType(operation.RequestBody);
|
||||
RequestTemplate = GetRequestTemplate(operation.RequestBody, lcuSchemaDocument);
|
||||
RequestTemplate = GetRequestTemplate(operation.RequestBody, document);
|
||||
}
|
||||
|
||||
private string? GetRequestTemplate(OpenApiRequestBody? requestBody, Document lcuSchemaDocument)
|
||||
private string? GetRequestTemplate(OpenApiRequestBody? requestBody, Document document)
|
||||
{
|
||||
var requestClasses = GetRequestClasses(requestBody, lcuSchemaDocument);
|
||||
var requestClasses = GetRequestClasses(requestBody, document);
|
||||
if (requestClasses.Count == 0)
|
||||
{
|
||||
var type = GetRequestBodyType(requestBody);
|
||||
@@ -132,17 +133,40 @@ public partial class OperationViewModel : ObservableObject
|
||||
return pathParameters;
|
||||
}
|
||||
|
||||
private AvaloniaList<PropertyClassViewModel> GetResponseClasses(OpenApiResponses responses, Document lcuSchemaDocument)
|
||||
private bool TryGetResponse(OpenApiResponses responses, [NotNullWhen(true)] out OpenApiResponse? response)
|
||||
{
|
||||
if (responses.TryGetValue("2XX", out var response)
|
||||
&& response.Content.TryGetValue("application/json", out var media))
|
||||
response = null;
|
||||
var flag = false;
|
||||
if (responses.TryGetValue("2XX", out var x))
|
||||
{
|
||||
var document = lcuSchemaDocument.OpenApiDocument;
|
||||
response = x;
|
||||
flag = true;
|
||||
}
|
||||
else if (responses.TryGetValue("200", out var y))
|
||||
{
|
||||
response = y;
|
||||
flag = true;
|
||||
}
|
||||
return flag;
|
||||
|
||||
}
|
||||
|
||||
private AvaloniaList<PropertyClassViewModel> GetResponseClasses(OpenApiResponses responses, Document document)
|
||||
{
|
||||
if (!TryGetResponse(responses, out var response))
|
||||
return [];
|
||||
|
||||
if (response.Content.TryGetValue("application/json", out var media))
|
||||
{
|
||||
var rawDocument = document.OpenApiDocument;
|
||||
var schema = media.Schema;
|
||||
if (schema == null) return [];
|
||||
|
||||
AvaloniaList<PropertyClassViewModel> propertyClasses = [];
|
||||
WalkSchema(schema, propertyClasses, document);
|
||||
WalkSchema(schema, propertyClasses, rawDocument);
|
||||
return propertyClasses;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -185,12 +209,12 @@ public partial class OperationViewModel : ObservableObject
|
||||
|| type.Contains("number"));
|
||||
}
|
||||
|
||||
private AvaloniaList<PropertyClassViewModel> GetRequestClasses(OpenApiRequestBody? requestBody, Document lcuSchemaDocument)
|
||||
private AvaloniaList<PropertyClassViewModel> GetRequestClasses(OpenApiRequestBody? requestBody, Document document)
|
||||
{
|
||||
if (requestBody == null) return [];
|
||||
if (requestBody.Content.TryGetValue("application/json", out var media))
|
||||
{
|
||||
var document = lcuSchemaDocument.OpenApiDocument;
|
||||
var rawDocument = document.OpenApiDocument;
|
||||
var schema = media.Schema;
|
||||
if (schema == null) return [];
|
||||
|
||||
@@ -198,9 +222,9 @@ public partial class OperationViewModel : ObservableObject
|
||||
if (IsComponent(type))
|
||||
{
|
||||
var componentId = GetComponentId(schema);
|
||||
var componentSchema = document.Components.Schemas[componentId];
|
||||
var componentSchema = rawDocument.Components.Schemas[componentId];
|
||||
AvaloniaList<PropertyClassViewModel> propertyClasses = [];
|
||||
WalkSchema(componentSchema, propertyClasses, document);
|
||||
WalkSchema(componentSchema, propertyClasses, rawDocument);
|
||||
return propertyClasses;
|
||||
}
|
||||
}
|
||||
@@ -209,12 +233,15 @@ public partial class OperationViewModel : ObservableObject
|
||||
|
||||
private string GetReturnType(OpenApiResponses responses)
|
||||
{
|
||||
if (responses.TryGetValue("2XX", out var response)
|
||||
&& response.Content.TryGetValue("application/json", out var media))
|
||||
if (!TryGetResponse(responses, out var response))
|
||||
return "none";
|
||||
|
||||
if (response.Content.TryGetValue("application/json", out var media))
|
||||
{
|
||||
var schema = media.Schema;
|
||||
return GetSchemaType(schema);
|
||||
}
|
||||
|
||||
return "none";
|
||||
}
|
||||
|
||||
@@ -223,6 +250,7 @@ public partial class OperationViewModel : ObservableObject
|
||||
if (schema.Reference != null) return schema.Reference.Id;
|
||||
if (schema.Type == "object" && schema.AdditionalProperties?.Reference != null) return schema.AdditionalProperties.Reference.Id;
|
||||
if (schema.Type == "integer" || schema.Type == "number") return $"{schema.Type}:{schema.Format}";
|
||||
if (schema.Type == "array" && schema.AdditionalProperties?.Reference != null) return schema.AdditionalProperties.Reference.Id;
|
||||
if (schema.Type == "array" && schema.Items.Reference != null) return $"{schema.Items.Reference.Id}[]";
|
||||
if (schema.Type == "array" && (schema.Items.Type == "integer" || schema.Items.Type == "number")) return $"{schema.Items.Type}:{schema.Items.Format}[]";
|
||||
if (schema.Type == "array") return $"{schema.Items.Type}[]";
|
||||
|
||||
@@ -17,13 +17,13 @@ public partial class PathOperationViewModel : ObservableObject
|
||||
public string Url { get; }
|
||||
|
||||
[ObservableProperty] private bool _isBusy;
|
||||
[ObservableProperty] private Lazy<LcuRequestViewModel> _lcuRequest;
|
||||
[ObservableProperty] private Lazy<RequestViewModel> _request;
|
||||
|
||||
public PathOperationViewModel(PathOperation pathOperation, ILogger<LcuRequestViewModel> lcuRequestViewModelLogger, Document lcuSchemaDocument)
|
||||
public PathOperationViewModel(PathOperation pathOperation, ILogger<RequestViewModel> requestViewModelLogger, Document document, Tab tab, System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
Path = pathOperation.Path;
|
||||
Operation = new OperationViewModel(pathOperation.Operation, lcuSchemaDocument);
|
||||
LcuRequest = new(() => new LcuRequestViewModel(lcuRequestViewModelLogger)
|
||||
Operation = new OperationViewModel(pathOperation.Operation, document);
|
||||
Request = new(() => new RequestViewModel(requestViewModelLogger, tab, httpClient)
|
||||
{
|
||||
Method = pathOperation.Method.ToUpper()
|
||||
});
|
||||
@@ -50,8 +50,8 @@ public partial class PathOperationViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
LcuRequest.Value.RequestPath = sb.ToString();
|
||||
await LcuRequest.Value.ExecuteAsync();
|
||||
Request.Value.RequestPath = sb.ToString();
|
||||
await Request.Value.ExecuteAsync();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Needlework.Net.Messages;
|
||||
using Needlework.Net.ViewModels.MainWindow;
|
||||
using Needlework.Net.ViewModels.Pages.Endpoints;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
@@ -12,7 +13,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Needlework.Net.ViewModels.Shared;
|
||||
|
||||
public partial class LcuRequestViewModel : ObservableObject
|
||||
public partial class RequestViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private string? _method = "GET";
|
||||
[ObservableProperty] private SolidColorBrush _color = new(GetColor("GET"));
|
||||
@@ -29,14 +30,18 @@ public partial class LcuRequestViewModel : ObservableObject
|
||||
[ObservableProperty] private string? _responseAuthorization = null;
|
||||
[ObservableProperty] private string? _responseBody = null;
|
||||
|
||||
public event EventHandler<LcuRequestViewModel>? RequestText;
|
||||
public event EventHandler<RequestViewModel>? RequestText;
|
||||
public event EventHandler<string>? UpdateText;
|
||||
|
||||
private readonly ILogger<LcuRequestViewModel> _logger;
|
||||
private readonly ILogger<RequestViewModel> _logger;
|
||||
private readonly Tab _tab;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public LcuRequestViewModel(ILogger<LcuRequestViewModel> logger)
|
||||
public RequestViewModel(ILogger<RequestViewModel> logger, Pages.Endpoints.Tab tab, HttpClient httpClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_tab = tab;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
partial void OnMethodChanged(string? oldValue, string? newValue)
|
||||
@@ -47,25 +52,80 @@ public partial class LcuRequestViewModel : ObservableObject
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync()
|
||||
{
|
||||
switch (_tab)
|
||||
{
|
||||
case Tab.LCU:
|
||||
await ExecuteLcuAsync();
|
||||
break;
|
||||
case Tab.GameClient:
|
||||
await ExecuteGameClientAsync();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteGameClientAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsRequestBusy = true;
|
||||
if (string.IsNullOrEmpty(RequestPath))
|
||||
throw new Exception("Path is empty.");
|
||||
var method = GetMethod();
|
||||
|
||||
var method = Method switch
|
||||
_logger.LogDebug("Sending request: {Tuple}", (Method, RequestPath));
|
||||
RequestText?.Invoke(this, this);
|
||||
var content = new StringContent(RequestBody ?? string.Empty, new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
|
||||
var responsePath = $"https://127.0.0.1:2999{RequestPath}";
|
||||
var response = await _httpClient.SendAsync(new HttpRequestMessage(method, responsePath) { Content = content });
|
||||
var responseBody = await response.Content.ReadAsByteArrayAsync();
|
||||
|
||||
var body = responseBody.Length > 0 ? JsonSerializer.Serialize(JsonSerializer.Deserialize<object>(responseBody), App.JsonSerializerOptions) : string.Empty;
|
||||
if (body.Length > App.MaxCharacters)
|
||||
{
|
||||
"GET" => HttpMethod.Get,
|
||||
"POST" => HttpMethod.Post,
|
||||
"PUT" => HttpMethod.Put,
|
||||
"DELETE" => HttpMethod.Delete,
|
||||
"HEAD" => HttpMethod.Head,
|
||||
"PATCH" => HttpMethod.Patch,
|
||||
"OPTIONS" => HttpMethod.Options,
|
||||
"TRACE" => HttpMethod.Trace,
|
||||
_ => throw new Exception("Method is not selected or missing."),
|
||||
};
|
||||
WeakReferenceMessenger.Default.Send(new OopsiesDialogRequestedMessage(body));
|
||||
UpdateText?.Invoke(this, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResponseBody = body;
|
||||
UpdateText?.Invoke(this, body);
|
||||
}
|
||||
|
||||
ResponseStatus = $"{(int)response.StatusCode} {response.StatusCode.ToString()}";
|
||||
ResponsePath = responsePath;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Request failed: {Tuple}", (Method, RequestPath));
|
||||
WeakReferenceMessenger.Default.Send(new InfoBarUpdateMessage(new InfoBarViewModel("Request Failed", true, ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error, TimeSpan.FromSeconds(5))));
|
||||
UpdateText?.Invoke(this, string.Empty);
|
||||
|
||||
ResponseStatus = null;
|
||||
ResponsePath = null;
|
||||
ResponseAuthentication = null;
|
||||
ResponseAuthorization = null;
|
||||
ResponseUsername = null;
|
||||
ResponsePassword = null;
|
||||
ResponseBody = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsRequestBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteLcuAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsRequestBusy = true;
|
||||
if (string.IsNullOrEmpty(RequestPath))
|
||||
throw new Exception("Path is empty.");
|
||||
var method = GetMethod();
|
||||
|
||||
_logger.LogDebug("Sending request: {Tuple}", (Method, RequestPath));
|
||||
|
||||
@@ -116,6 +176,22 @@ public partial class LcuRequestViewModel : ObservableObject
|
||||
}
|
||||
}
|
||||
|
||||
private HttpMethod GetMethod()
|
||||
{
|
||||
return Method switch
|
||||
{
|
||||
"GET" => HttpMethod.Get,
|
||||
"POST" => HttpMethod.Post,
|
||||
"PUT" => HttpMethod.Put,
|
||||
"DELETE" => HttpMethod.Delete,
|
||||
"HEAD" => HttpMethod.Head,
|
||||
"PATCH" => HttpMethod.Patch,
|
||||
"OPTIONS" => HttpMethod.Options,
|
||||
"TRACE" => HttpMethod.Trace,
|
||||
_ => throw new Exception("Method is not selected or missing."),
|
||||
};
|
||||
}
|
||||
|
||||
private static Color GetColor(string method) => method switch
|
||||
{
|
||||
"GET" => Avalonia.Media.Color.FromRgb(95, 99, 186),
|
||||
@@ -19,13 +19,13 @@
|
||||
<StackPanel Margin="0 0 0 16">
|
||||
<Grid RowDefinitions="auto" ColumnDefinitions="auto,*,auto">
|
||||
<ComboBox ItemsSource="{Binding RequestMethods}"
|
||||
SelectedItem="{Binding LcuRequest.Method}"
|
||||
SelectedItem="{Binding Request.Method}"
|
||||
Margin="0 0 8 0"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"/>
|
||||
<AutoCompleteBox
|
||||
ItemsSource="{Binding RequestPaths}"
|
||||
Text="{Binding LcuRequest.RequestPath}"
|
||||
Text="{Binding Request.RequestPath}"
|
||||
MaxDropDownHeight="400"
|
||||
FilterMode="StartsWith"
|
||||
Grid.Row="0"
|
||||
@@ -49,7 +49,7 @@
|
||||
<TextBox IsReadOnly="True"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Text="{Binding LcuRequest.ResponsePath}"/>
|
||||
Text="{Binding Request.ResponsePath}"/>
|
||||
<avaloniaEdit:TextEditor
|
||||
Name="RequestEditor"
|
||||
Text=""
|
||||
@@ -69,7 +69,7 @@
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0">
|
||||
<Button Content="{Binding LcuRequest.ResponseStatus}"
|
||||
<Button Content="{Binding Request.ResponseStatus}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
@@ -28,13 +28,13 @@ public partial class ConsoleView : UserControl
|
||||
_requestEditor?.ApplyJsonEditorSettings();
|
||||
|
||||
var vm = (ConsoleViewModel)DataContext!;
|
||||
vm.LcuRequest.RequestText += LcuRequest_RequestText; ;
|
||||
vm.LcuRequest.UpdateText += LcuRequest_UpdateText;
|
||||
vm.Request.RequestText += LcuRequest_RequestText; ;
|
||||
vm.Request.UpdateText += LcuRequest_UpdateText;
|
||||
|
||||
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
|
||||
}
|
||||
|
||||
private void LcuRequest_RequestText(object? sender, ViewModels.Shared.LcuRequestViewModel e)
|
||||
private void LcuRequest_RequestText(object? sender, ViewModels.Shared.RequestViewModel e)
|
||||
{
|
||||
e.RequestBody = _requestEditor!.Text;
|
||||
}
|
||||
@@ -49,8 +49,8 @@ public partial class ConsoleView : UserControl
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
|
||||
var vm = (ConsoleViewModel)DataContext!;
|
||||
vm.LcuRequest.RequestText -= LcuRequest_RequestText;
|
||||
vm.LcuRequest.UpdateText -= LcuRequest_UpdateText;
|
||||
vm.Request.RequestText -= LcuRequest_RequestText;
|
||||
vm.Request.UpdateText -= LcuRequest_UpdateText;
|
||||
}
|
||||
|
||||
private void OnBaseThemeChanged(ThemeVariant currentTheme)
|
||||
|
||||
@@ -64,8 +64,8 @@
|
||||
VerticalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
Margin="0 0 8 0"
|
||||
Text="{Binding LcuRequest.Value.Method}"
|
||||
Background="{Binding LcuRequest.Value.Color}"
|
||||
Text="{Binding Request.Value.Method}"
|
||||
Background="{Binding Request.Value.Color}"
|
||||
FontSize="8"
|
||||
Width="50"
|
||||
Padding="10 2 10 2"
|
||||
@@ -93,14 +93,14 @@
|
||||
ColumnDefinitions="auto,*,auto">
|
||||
<TextBox Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Text="{Binding SelectedPathOperation.LcuRequest.Value.Method}"
|
||||
Text="{Binding SelectedPathOperation.Request.Value.Method}"
|
||||
FontSize="12"
|
||||
IsReadOnly="True"
|
||||
Margin="0 0 8 0"/>
|
||||
<TextBox Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
FontSize="12"
|
||||
Text="{Binding SelectedPathOperation.LcuRequest.Value.ResponsePath}"
|
||||
Text="{Binding SelectedPathOperation.Request.Value.ResponsePath}"
|
||||
IsReadOnly="True"/>
|
||||
<StackPanel Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
@@ -194,7 +194,7 @@
|
||||
Grid.Column="1"
|
||||
Margin="0 0 0 8"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding SelectedPathOperation.LcuRequest.Value.ResponseUsername}" />
|
||||
Text="{Binding SelectedPathOperation.Request.Value.ResponseUsername}" />
|
||||
<TextBlock FontSize="12"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
@@ -206,7 +206,7 @@
|
||||
Grid.Column="1"
|
||||
Margin="0 0 0 8"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding SelectedPathOperation.LcuRequest.Value.ResponsePassword}"/>
|
||||
Text="{Binding SelectedPathOperation.Request.Value.ResponsePassword}"/>
|
||||
<TextBlock FontSize="12"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
@@ -217,7 +217,7 @@
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding SelectedPathOperation.LcuRequest.Value.ResponseAuthorization}"/>
|
||||
Text="{Binding SelectedPathOperation.Request.Value.ResponseAuthorization}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Schemas">
|
||||
@@ -309,7 +309,7 @@
|
||||
FontSize="10"
|
||||
Padding="12 4 12 4"
|
||||
Classes="Flat"
|
||||
Content="{Binding SelectedPathOperation.LcuRequest.Value.ResponseStatus}"/>
|
||||
Content="{Binding SelectedPathOperation.Request.Value.ResponseStatus}"/>
|
||||
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="1" Grid.Column="4">
|
||||
|
||||
@@ -13,7 +13,7 @@ public partial class EndpointView : UserControl
|
||||
{
|
||||
private TextEditor? _requestEditor;
|
||||
private TextEditor? _responseEditor;
|
||||
private LcuRequestViewModel? _lcuRequestVm;
|
||||
private RequestViewModel? _lcuRequestVm;
|
||||
|
||||
public EndpointView()
|
||||
{
|
||||
@@ -34,9 +34,9 @@ public partial class EndpointView : UserControl
|
||||
|
||||
if (vm.SelectedPathOperation != null)
|
||||
{
|
||||
_lcuRequestVm = vm.SelectedPathOperation.LcuRequest.Value;
|
||||
vm.SelectedPathOperation.LcuRequest.Value.RequestText += LcuRequest_RequestText;
|
||||
vm.SelectedPathOperation.LcuRequest.Value.UpdateText += LcuRequest_UpdateText;
|
||||
_lcuRequestVm = vm.SelectedPathOperation.Request.Value;
|
||||
vm.SelectedPathOperation.Request.Value.RequestText += LcuRequest_RequestText;
|
||||
vm.SelectedPathOperation.Request.Value.UpdateText += LcuRequest_UpdateText;
|
||||
}
|
||||
|
||||
OnBaseThemeChanged(Application.Current!.ActualThemeVariant);
|
||||
@@ -53,10 +53,10 @@ public partial class EndpointView : UserControl
|
||||
_lcuRequestVm.RequestText -= LcuRequest_RequestText;
|
||||
_lcuRequestVm.UpdateText -= LcuRequest_UpdateText;
|
||||
}
|
||||
vm.SelectedPathOperation.LcuRequest.Value.RequestText += LcuRequest_RequestText;
|
||||
vm.SelectedPathOperation.LcuRequest.Value.UpdateText += LcuRequest_UpdateText;
|
||||
_lcuRequestVm = vm.SelectedPathOperation.LcuRequest.Value;
|
||||
_responseEditor!.Text = vm.SelectedPathOperation.LcuRequest.Value.ResponseBody ?? string.Empty;
|
||||
vm.SelectedPathOperation.Request.Value.RequestText += LcuRequest_RequestText;
|
||||
vm.SelectedPathOperation.Request.Value.UpdateText += LcuRequest_UpdateText;
|
||||
_lcuRequestVm = vm.SelectedPathOperation.Request.Value;
|
||||
_responseEditor!.Text = vm.SelectedPathOperation.Request.Value.ResponseBody ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public partial class EndpointView : UserControl
|
||||
currentTheme == ThemeVariant.Dark ? ThemeName.DarkPlus : ThemeName.LightPlus);
|
||||
}
|
||||
|
||||
private void LcuRequest_RequestText(object? sender, LcuRequestViewModel e)
|
||||
private void LcuRequest_RequestText(object? sender, RequestViewModel e)
|
||||
{
|
||||
e.RequestBody = _requestEditor!.Text;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:i="https://github.com/projektanker/icons.avalonia"
|
||||
Name="EndpointsTab"
|
||||
xmlns:vm="using:Needlework.Net.ViewModels.Pages.Endpoints"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:controls="using:Needlework.Net.Controls"
|
||||
@@ -14,6 +15,7 @@
|
||||
<Grid>
|
||||
<ui:TabView TabItems="{Binding Endpoints}"
|
||||
AddTabButtonCommand="{Binding AddEndpointCommand}"
|
||||
AddTabButtonCommandParameter="{x:Static vm:Tab.LCU}"
|
||||
TabCloseRequested="TabView_TabCloseRequested">
|
||||
<!--Need to override Tab header for Mica theme...-->
|
||||
<ui:TabView.Resources>
|
||||
@@ -44,7 +46,24 @@
|
||||
Content="{Binding}">
|
||||
<ui:TabViewItem.ContentTemplate>
|
||||
<DataTemplate DataType="vm:EndpointItem">
|
||||
<ContentControl Content="{Binding Content}"/>
|
||||
<Grid RowDefinitions="auto,auto,*" ColumnDefinitions="*">
|
||||
<Menu Grid.Row="0"
|
||||
Grid.Column="0">
|
||||
<MenuItem Header="_New tab">
|
||||
<MenuItem Header="LCU"
|
||||
Command="{Binding #EndpointsTab.((vm:EndpointsTabViewModel)DataContext).AddEndpointCommand}"
|
||||
CommandParameter="{x:Static vm:Tab.LCU}"/>
|
||||
<MenuItem Header="Game Client"
|
||||
Command="{Binding #EndpointsTab.((vm:EndpointsTabViewModel)DataContext).AddEndpointCommand}"
|
||||
CommandParameter="{x:Static vm:Tab.GameClient}"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Separator Grid.Row="1"
|
||||
Grid.Column="0"/>
|
||||
<ContentControl Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Content="{Binding Content}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ui:TabViewItem.ContentTemplate>
|
||||
</ui:TabViewItem>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">
|
||||
Welcome to Needlework.Net
|
||||
</TextBlock>
|
||||
<TextBlock>Get started with LCU development by clicking on the endpoints tab in the left panel.</TextBlock>
|
||||
<TextBlock>Get started with LCU or Game Client development by clicking on the endpoints tab in the left panel.</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<controls:Card Margin="12">
|
||||
|
||||
Reference in New Issue
Block a user