Files
Needlework.Net/Needlework.Net/ViewModels/Shared/RequestViewModel.cs
2025-06-13 22:52:58 -05:00

225 lines
7.5 KiB
C#

using Avalonia.Media;
using AvaloniaEdit.Document;
using BlossomiShymae.Briar;
using BlossomiShymae.Briar.Utils;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Needlework.Net.Extensions;
using Needlework.Net.Messages;
using Needlework.Net.Services;
using Needlework.Net.ViewModels.Pages.Endpoints;
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace Needlework.Net.ViewModels.Shared;
public partial class RequestViewModel : ObservableObject, IEnableLogger
{
private readonly NotificationService _notificationService;
private readonly Tab _tab;
public RequestViewModel(NotificationService notificationService, Tab tab)
{
_tab = tab;
_notificationService = notificationService;
}
[ObservableProperty]
private string? _method = "GET";
[ObservableProperty]
private SolidColorBrush _color = new(GetColor("GET"));
[ObservableProperty]
private bool _isRequestBusy;
[ObservableProperty]
private string? _requestPath;
[ObservableProperty]
private TextDocument _requestDocument = new();
[ObservableProperty]
private TextDocument _responseDocument = new();
[ObservableProperty]
private string? _responsePath;
[ObservableProperty]
private string? _responseStatus;
[ObservableProperty]
private string? _responseAuthentication;
[ObservableProperty]
private string? _responseUsername;
[ObservableProperty]
private string? _responsePassword;
[ObservableProperty]
private string? _responseAuthorization;
partial void OnMethodChanged(string? oldValue, string? newValue)
{
if (newValue == null) return;
Color = new(GetColor(newValue));
}
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();
this.Log()
.Debug("Sending request: {Tuple}", (Method, RequestPath));
var requestBody = RequestDocument.Text;
var content = new StringContent(requestBody, new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
var client = Connector.GetGameHttpClientInstance();
var response = await client.SendAsync(new HttpRequestMessage(method, RequestPath) { 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)
{
WeakReferenceMessenger.Default.Send(new OopsiesDialogRequestedMessage(body));
ResponseDocument = new();
}
else
{
ResponseDocument = new(body);
}
ResponseStatus = $"{(int)response.StatusCode} {response.StatusCode.ToString()}";
ResponsePath = $"https://127.0.0.1:2999{RequestPath}";
}
catch (Exception ex)
{
this.Log()
.Error(ex, "Request failed: {Tuple}", (Method, RequestPath));
_notificationService.Notify("Request failed", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
ResponseStatus = null;
ResponsePath = null;
ResponseAuthentication = null;
ResponseAuthorization = null;
ResponseUsername = null;
ResponsePassword = null;
ResponseDocument = new();
}
finally
{
IsRequestBusy = false;
}
}
private async Task ExecuteLcuAsync()
{
try
{
IsRequestBusy = true;
if (string.IsNullOrEmpty(RequestPath))
throw new Exception("Path is empty.");
var method = GetMethod();
this.Log()
.Debug("Sending request: {Tuple}", (Method, RequestPath));
var processInfo = ProcessFinder.GetProcessInfo();
var requestBody = RequestDocument.Text;
var content = new StringContent(requestBody, new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
var client = Connector.GetLcuHttpClientInstance();
var response = await client.SendAsync(new(method, RequestPath) { Content = content });
var riotAuthentication = new RiotAuthentication(processInfo.RemotingAuthToken);
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)
{
WeakReferenceMessenger.Default.Send(new OopsiesDialogRequestedMessage(body));
ResponseDocument = new();
}
else
{
ResponseDocument = new(body);
}
ResponseStatus = $"{(int)response.StatusCode} {response.StatusCode.ToString()}";
ResponsePath = $"https://127.0.0.1:{processInfo.AppPort}{RequestPath}";
ResponseAuthentication = riotAuthentication.Value;
ResponseAuthorization = $"Basic {riotAuthentication.Value}";
ResponseUsername = riotAuthentication.Username;
ResponsePassword = riotAuthentication.Password;
}
catch (Exception ex)
{
this.Log()
.Error(ex, "Request failed: {Tuple}", (Method, RequestPath));
_notificationService.Notify("Request failed", ex.Message, FluentAvalonia.UI.Controls.InfoBarSeverity.Error);
ResponseStatus = null;
ResponsePath = null;
ResponseAuthentication = null;
ResponseAuthorization = null;
ResponseUsername = null;
ResponsePassword = null;
ResponseDocument = new();
}
finally
{
IsRequestBusy = false;
}
}
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),
"POST" => Avalonia.Media.Color.FromRgb(103, 186, 95),
"PUT" => Avalonia.Media.Color.FromRgb(186, 139, 95),
"DELETE" => Avalonia.Media.Color.FromRgb(186, 95, 95),
"HEAD" => Avalonia.Media.Color.FromRgb(136, 95, 186),
"PATCH" => Avalonia.Media.Color.FromRgb(95, 186, 139),
_ => throw new InvalidOperationException("Method does not have assigned color.")
};
}