From 3a7d39971a20d13689c716866b4249dc6f94b94f Mon Sep 17 00:00:00 2001 From: AoshiW Date: Fri, 16 Aug 2024 08:17:43 +0200 Subject: [PATCH 1/2] bug fix in WebsocketView, optimization and others --- .../Needlework.Net.Desktop.csproj | 2 +- .../ViewModels/ConsoleViewModel.cs | 22 +++++++---- .../ViewModels/EndpointViewModel.cs | 13 ++++--- .../ViewModels/EndpointsViewModel.cs | 15 +++++--- .../ViewModels/MainWindowViewModel.cs | 4 +- .../ViewModels/PathOperationViewModel.cs | 37 +++++++++++-------- .../ViewModels/WebsocketViewModel.cs | 24 +++++------- .../Views/EndpointView.axaml | 1 + Needlework.Net.Desktop/Views/MainWindow.axaml | 3 +- .../Views/WebsocketView.axaml.cs | 2 +- 10 files changed, 71 insertions(+), 52 deletions(-) diff --git a/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj b/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj index be22c18..9d05620 100644 --- a/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj +++ b/Needlework.Net.Desktop/Needlework.Net.Desktop.csproj @@ -12,7 +12,7 @@ app.ico NeedleworkDotNet 0.4.1.0 - 0.4.1.0 + $(AssemblyVersion) False diff --git a/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs b/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs index ada8b48..43612b8 100644 --- a/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/ConsoleViewModel.cs @@ -16,10 +16,10 @@ namespace Needlework.Net.Desktop.ViewModels public partial class ConsoleViewModel : PageBase, IRecipient { public IAvaloniaReadOnlyList RequestMethods { get; } = new AvaloniaList(["GET", "POST", "PUT", "DELETE", "HEAD", "PATCH", "OPTIONS", "TRACE"]); + public IAvaloniaList RequestPaths { get; } = new AvaloniaList(); [ObservableProperty] private bool _isBusy = true; [ObservableProperty] private bool _isRequestBusy = false; - [ObservableProperty] private IAvaloniaReadOnlyList _requestPaths = new AvaloniaList(); [ObservableProperty] private string? _requestMethodSelected = "GET"; [ObservableProperty] private string? _requestPath = null; [ObservableProperty] private string? _requestBody = null; @@ -60,18 +60,25 @@ namespace Needlework.Net.Desktop.ViewModels var processInfo = Connector.GetProcessInfo(); var requestBody = WeakReferenceMessenger.Default.Send(new ContentRequestMessage(), "ConsoleRequestEditor").Response; var content = new StringContent(Regex.Replace(requestBody, @"\s+", ""), new System.Net.Http.Headers.MediaTypeHeaderValue("application/json")); - var response = await Connector.SendAsync(method, RequestPath, content) ?? throw new Exception("Response is null."); + var response = await Connector.SendAsync(method, RequestPath, content); var riotAuthentication = new RiotAuthentication(processInfo.RemotingAuthToken); - var body = await response.Content.ReadAsStringAsync(); - - body = !string.IsNullOrEmpty(body) ? JsonSerializer.Serialize(JsonSerializer.Deserialize(body), App.JsonSerializerOptions) : string.Empty; + var responseBody = +#if DEBUG + await response.Content.ReadAsStringAsync(); +#else + await response.Content.ReadAsByteArrayAsync(); +#endif + + var body = responseBody.Length > 0 + ? JsonSerializer.Serialize(JsonSerializer.Deserialize(responseBody), App.JsonSerializerOptions) + : string.Empty; if (body.Length >= App.MaxCharacters) { WindowService.ShowOopsiesWindow(body); WeakReferenceMessenger.Default.Send(new ResponseUpdatedMessage(string.Empty), nameof(ConsoleViewModel)); } else WeakReferenceMessenger.Default.Send(new ResponseUpdatedMessage(body), nameof(ConsoleViewModel)); - + ResponseStatus = $"{(int)response.StatusCode} {response.StatusCode.ToString()}"; ResponsePath = $"https://127.0.0.1:{processInfo.AppPort}{RequestPath}"; ResponseAuthorization = $"Basic {riotAuthentication.Value}"; @@ -94,7 +101,8 @@ namespace Needlework.Net.Desktop.ViewModels { Avalonia.Threading.Dispatcher.UIThread.Invoke(() => { - RequestPaths = new AvaloniaList([.. message.Value.Paths]); + RequestPaths.Clear(); + RequestPaths.AddRange(message.Value.Paths); IsBusy = false; }); } diff --git a/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs b/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs index e202243..81353fe 100644 --- a/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/EndpointViewModel.cs @@ -2,6 +2,8 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using Needlework.Net.Desktop.Messages; +using System; +using System.Collections.Generic; using System.Linq; namespace Needlework.Net.Desktop.ViewModels @@ -12,11 +14,11 @@ namespace Needlework.Net.Desktop.ViewModels public string Title => Endpoint; - [ObservableProperty] private IAvaloniaReadOnlyList _pathOperations; + public IAvaloniaReadOnlyList PathOperations { get; } [ObservableProperty] private PathOperationViewModel? _selectedPathOperation; [ObservableProperty] private string? _search; - [ObservableProperty] private IAvaloniaReadOnlyList _filteredPathOperations; + public IAvaloniaList FilteredPathOperations { get; } public EndpointViewModel(string endpoint) { @@ -29,13 +31,14 @@ namespace Needlework.Net.Desktop.ViewModels partial void OnSearchChanged(string? value) { + FilteredPathOperations.Clear(); + if (string.IsNullOrWhiteSpace(value)) { - FilteredPathOperations = new AvaloniaList(PathOperations); + FilteredPathOperations.AddRange(PathOperations); return; } - - FilteredPathOperations = new AvaloniaList(PathOperations.Where(o => o.Path.ToLower().Contains(value.ToLower()))); + FilteredPathOperations.AddRange(PathOperations.Where(o => o.Path.Contains(value, StringComparison.InvariantCultureIgnoreCase))); } partial void OnSelectedPathOperationChanged(PathOperationViewModel? value) diff --git a/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs b/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs index 4e8a5ef..2ed28e4 100644 --- a/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/EndpointsViewModel.cs @@ -15,11 +15,11 @@ namespace Needlework.Net.Desktop.ViewModels public string Title => "Endpoints"; public Action OnClicked; + public IAvaloniaList Plugins { get; } = new AvaloniaList(); + public IAvaloniaList Query { get; } = new AvaloniaList(); - [ObservableProperty] private IAvaloniaReadOnlyList _plugins = new AvaloniaList(); [ObservableProperty] private bool _isBusy = true; [ObservableProperty] private string _search = string.Empty; - [ObservableProperty] private IAvaloniaReadOnlyList _query = new AvaloniaList(); [ObservableProperty] private string? _selectedQuery = string.Empty; public EndpointsViewModel(HttpClient httpClient, Action onClicked) @@ -33,16 +33,19 @@ namespace Needlework.Net.Desktop.ViewModels public void Receive(DataReadyMessage message) { IsBusy = false; - Plugins = new AvaloniaList([.. message.Value.Plugins.Keys]); - Query = new AvaloniaList([.. Plugins]); + Plugins.Clear(); + Plugins.AddRange(message.Value.Plugins.Keys); + Query.Clear(); + Query.AddRange(Plugins); } partial void OnSearchChanged(string value) { + Query.Clear(); if (!string.IsNullOrEmpty(Search)) - Query = new AvaloniaList(Plugins.Where(x => x.Contains(value))); + Query.AddRange(Plugins.Where(x => x.Contains(value, StringComparison.InvariantCultureIgnoreCase))); else - Query = Plugins; + Query.AddRange(Plugins); } [RelayCommand] diff --git a/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs b/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs index a7d50b3..87d2293 100644 --- a/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/MainWindowViewModel.cs @@ -63,7 +63,7 @@ namespace Needlework.Net.Desktop.ViewModels private void ProcessEvents(object? obj) { - while (true) + while (!IsUpdateShown) { Task.Run(CheckLatestVersionAsync); @@ -84,7 +84,7 @@ namespace Needlework.Net.Desktop.ViewModels var currentVersion = int.Parse(Version.Replace(".", "")); - if (release.IsLatest(currentVersion) && !IsUpdateShown) + if (release.IsLatest(currentVersion)) { Avalonia.Threading.Dispatcher.UIThread.Post(async () => { diff --git a/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs b/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs index fa4c053..b527f0b 100644 --- a/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/PathOperationViewModel.cs @@ -7,6 +7,7 @@ using Needlework.Net.Core; using Needlework.Net.Desktop.Messages; using System; using System.Net.Http; +using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -32,14 +33,18 @@ namespace Needlework.Net.Desktop.ViewModels public PathOperationViewModel(PathOperation pathOperation) { Method = pathOperation.Method.ToUpper(); - Color = new SolidColorBrush(GetColor(pathOperation.Method.ToUpper())); + Color = new SolidColorBrush(GetColor(Method)); Path = pathOperation.Path; Operation = new OperationViewModel(pathOperation.Operation); ProcessInfo = GetProcessInfo(); - ResponsePath = ProcessInfo != null ? $"https://127.0.0.1:{ProcessInfo.AppPort}{Path}" : null; - ResponseUsername = ProcessInfo != null ? new RiotAuthentication(ProcessInfo.RemotingAuthToken).Username : null; - ResponsePassword = ProcessInfo != null ? new RiotAuthentication(ProcessInfo.RemotingAuthToken).Password : null; - ResponseAuthorization = ProcessInfo != null ? $"Basic {new RiotAuthentication(ProcessInfo.RemotingAuthToken).Value}" : null; + if (ProcessInfo != null) + { + ResponsePath = $"https://127.0.0.1:{ProcessInfo.AppPort}{Path}"; + var riotAuth = new RiotAuthentication(ProcessInfo.RemotingAuthToken); + ResponseUsername = riotAuth.Username; + ResponsePassword = riotAuth.Password; + ResponseAuthorization = $"Basic {riotAuth.Value}"; + } } private ProcessInfo? GetProcessInfo() @@ -60,7 +65,7 @@ namespace Needlework.Net.Desktop.ViewModels { IsBusy = true; - var method = Method.ToUpper() switch + var method = Method switch { "GET" => HttpMethod.Get, "POST" => HttpMethod.Post, @@ -74,26 +79,28 @@ namespace Needlework.Net.Desktop.ViewModels }; var processInfo = Connector.GetProcessInfo(); - var path = Path; + var sb = new StringBuilder(Path); foreach (var pathParameter in Operation.PathParameters) { - path = path.Replace($"{{{pathParameter.Name}}}", pathParameter.Value); + sb.Replace($"{{{pathParameter.Name}}}", pathParameter.Value); } - var query = ""; + var firstQueryAdded = false; foreach (var queryParameter in Operation.QueryParameters) { - if (query.Length != 0 && !string.IsNullOrWhiteSpace(queryParameter.Value)) - query += $"&{queryParameter.Name}={Uri.EscapeDataString(queryParameter.Value)}"; - else if (query.Length == 0 && !string.IsNullOrWhiteSpace(queryParameter.Value)) - query += $"?{queryParameter.Name}={Uri.EscapeDataString(queryParameter.Value)}"; + if (!string.IsNullOrWhiteSpace(queryParameter.Value)) + { + sb.Append(firstQueryAdded ? '&' : '?'); + firstQueryAdded = true; + sb.Append($"{queryParameter.Name}={Uri.EscapeDataString(queryParameter.Value)}"); + } } - var uri = $"{path}{query}"; + var uri = sb.ToString(); var requestBody = WeakReferenceMessenger.Default.Send(new ContentRequestMessage(), "EndpointRequestEditor").Response; var content = new StringContent(Regex.Replace(requestBody, @"\s+", ""), new System.Net.Http.Headers.MediaTypeHeaderValue("application/json")); - var response = await Connector.SendAsync(method, $"{uri}", content) ?? throw new Exception("Response is null."); + var response = await Connector.SendAsync(method, uri, content) ?? throw new Exception("Response is null."); var riotAuthentication = new RiotAuthentication(processInfo.RemotingAuthToken); var responseBody = await response.Content.ReadAsStringAsync(); diff --git a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs index 27584a3..71d5548 100644 --- a/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs +++ b/Needlework.Net.Desktop/ViewModels/WebsocketViewModel.cs @@ -17,8 +17,7 @@ namespace Needlework.Net.Desktop.ViewModels { public partial class WebsocketViewModel : PageBase { - [NotifyPropertyChangedFor(nameof(FilteredEventLog))] - [ObservableProperty] private ObservableCollection _eventLog = []; + public ObservableCollection EventLog { get; } = []; [NotifyPropertyChangedFor(nameof(FilteredEventLog))] [ObservableProperty] private string _search = string.Empty; [ObservableProperty] private bool _isAttach = true; @@ -31,12 +30,12 @@ namespace Needlework.Net.Desktop.ViewModels public WindowService WindowService { get; } - public List FilteredEventLog => string.IsNullOrWhiteSpace(Search) ? [.. EventLog] : [.. EventLog.Where(x => x.ToLower().Contains(Search.ToLower()))]; + public IReadOnlyList FilteredEventLog => string.IsNullOrWhiteSpace(Search) ? EventLog : [.. EventLog.Where(x => x.Contains(Search, StringComparison.InvariantCultureIgnoreCase))]; public WebsocketViewModel(WindowService windowService) : base("Event Viewer", "plug", -100) { WindowService = windowService; - + EventLog.CollectionChanged += (s, e) => OnPropertyChanged(nameof(FilteredEventLog)); var thread = new Thread(InitializeWebsocket) { IsBackground = true }; thread.Start(); } @@ -65,7 +64,8 @@ namespace Needlework.Net.Desktop.ViewModels [RelayCommand] private void Clear() { - EventLog = []; + _events.Clear(); + EventLog.Clear(); } partial void OnSelectedEventLogChanged(string? value) @@ -99,25 +99,21 @@ namespace Needlework.Net.Desktop.ViewModels if (!IsAttach) return; var line = $"{DateTime.Now:HH:mm:ss.fff} {message.Data?.EventType.ToUpper()} {message.Data?.Uri}"; - var log = EventLog.ToList(); Trace.WriteLine($"Message: {line}"); - if (log.Count < 1000) + if (EventLog.Count < 1000) { - log.Add(line); + EventLog.Add(line); _events[line] = message; } else { - var key = $"{log[0]}"; - log.RemoveAt(0); + var key = EventLog[0]; + EventLog.RemoveAt(0); _events.Remove(key); - log.Add(line); + EventLog.Add(line); _events[line] = message; } - - EventLog = []; // This is a hack needed to update for ListBox - EventLog = new ObservableCollection(log); }); } } diff --git a/Needlework.Net.Desktop/Views/EndpointView.axaml b/Needlework.Net.Desktop/Views/EndpointView.axaml index ebb7553..9a06d6e 100644 --- a/Needlework.Net.Desktop/Views/EndpointView.axaml +++ b/Needlework.Net.Desktop/Views/EndpointView.axaml @@ -55,6 +55,7 @@ +