use refit for client

This commit is contained in:
zznty
2022-07-21 22:41:28 +07:00
parent d1b7877f47
commit 2773531358
6 changed files with 67 additions and 59 deletions

View File

@@ -1,14 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using TorchRemote.Models.Requests; using Refit;
using TorchRemote.Models.Responses;
using TorchRemote.Models.Shared;
using Websocket.Client; using Websocket.Client;
namespace TorchRemote.Services; namespace TorchRemote.Services;
@@ -31,8 +26,10 @@ public class ApiClientService
public ApiClientService() public ApiClientService()
{ {
Api = RestService.For<IRemoteApi>(_client);
Task.Run(ConnectionTimer); Task.Run(ConnectionTimer);
} }
public IRemoteApi Api { get; }
private async Task ConnectionTimer() private async Task ConnectionTimer()
{ {
@@ -41,7 +38,7 @@ public class ApiClientService
await Task.Delay(1000); await Task.Delay(1000);
try try
{ {
await GetServerStatusAsync(CancellationToken.None); await Api.GetServerStatus();
break; break;
} }
catch catch
@@ -52,43 +49,6 @@ public class ApiClientService
Connected?.Invoke(this, EventArgs.Empty); Connected?.Invoke(this, EventArgs.Empty);
} }
public Task<ServerStatusResponse> GetServerStatusAsync(CancellationToken token) =>
_client.GetFromJsonAsync<ServerStatusResponse>("server/status", token)!;
public Task<ServerSettings> GetServerSettingsAsync(CancellationToken token) =>
_client.GetFromJsonAsync<ServerSettings>("server/settings", token)!;
public Task SetServerSettingsAsync(ServerSettings settings, CancellationToken token) =>
_client.PostAsJsonAsync("server/settings", settings, token);
public Task StartServerAsync(CancellationToken token) =>
_client.PostAsync("server/start", null, token);
public Task StopServerAsync(StopServerRequest request, CancellationToken token) =>
_client.PostAsJsonAsync("server/stop", request, token);
public Task<IEnumerable<Guid>> GetWorldsAsync(CancellationToken token) =>
_client.GetFromJsonAsync<IEnumerable<Guid>>("worlds", token)!;
public Task<WorldResponse> GetWorldAsync(Guid id, CancellationToken token) =>
_client.GetFromJsonAsync<WorldResponse>($"worlds/{id}", token)!;
public Task<Guid> GetSelectedWorld(CancellationToken token) =>
_client.GetFromJsonAsync<Guid>("worlds/selected", token);
public Task SelectWorldAsync(Guid id, CancellationToken token) =>
_client.PostAsync($"worlds/{id}/select", null, token);
public Task SendChatMessageAsync(ChatMessageRequest request, CancellationToken token) =>
_client.PostAsJsonAsync("chat/message", request, token);
public async Task<Guid> InvokeCommandAsync(ChatCommandRequest request, CancellationToken token)
{
var r = await _client.PostAsJsonAsync("chat/command", request, token);
r.EnsureSuccessStatusCode();
return await r.Content.ReadFromJsonAsync<Guid>(cancellationToken: token);
}
public Task<WebsocketClient> WatchChatAsync() => StartWebsocketConnectionAsync("live/chat"); public Task<WebsocketClient> WatchChatAsync() => StartWebsocketConnectionAsync("live/chat");
public Task<WebsocketClient> WatchLogLinesAsync() => StartWebsocketConnectionAsync("live/logs"); public Task<WebsocketClient> WatchLogLinesAsync() => StartWebsocketConnectionAsync("live/logs");

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Refit;
using TorchRemote.Models.Requests;
using TorchRemote.Models.Responses;
using TorchRemote.Models.Shared;
namespace TorchRemote.Services;
public interface IRemoteApi
{
#region Server
[Get("/server/status")]
Task<ServerStatusResponse> GetServerStatus();
[Post("/server/start")]
Task StartServer();
[Post("/server/stop")]
Task StopServer([Body] StopServerRequest request);
[Get("/server/settings")]
Task<ServerSettings> GetServerSettings();
[Post("/server/settings")]
Task SetServerSettings([Body] ServerSettings request);
#endregion
#region Chat
[Post("/chat/message")]
Task SendChatMessage([Body] ChatMessageRequest request);
[Post("/chat/command")]
Task<Guid> InvokeChatCommand([Body] ChatCommandRequest request);
#endregion
#region Worlds
[Get("/worlds")]
Task<IEnumerable<Guid>> GetWorlds();
[Get("/worlds/selected")]
Task<Guid> GetSelectedWorld();
[Get("/worlds/{id}")]
Task<WorldResponse> GetWorld(Guid id);
[Post("/worlds/{id}/select")]
Task SelectWorld(Guid id);
#endregion
#region Settings
[Get("/settings/{id}")]
Task<SettingInfoResponse> GetSetting(Guid id);
#endregion
}

View File

@@ -25,6 +25,7 @@
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.16" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.16" />
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" /> <PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
<PackageReference Include="ReactiveUI.Fody" Version="18.3.1" /> <PackageReference Include="ReactiveUI.Fody" Version="18.3.1" />
<PackageReference Include="Refit" Version="6.3.2" />
<PackageReference Include="System.Text.Json" Version="7.0.0-preview.6.22324.4" /> <PackageReference Include="System.Text.Json" Version="7.0.0-preview.6.22324.4" />
<PackageReference Include="Websocket.Client" Version="4.4.43" /> <PackageReference Include="Websocket.Client" Version="4.4.43" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" /> <PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />

View File

@@ -34,9 +34,9 @@ public class ChatViewModel : ViewModelBase
.Subscribe(s => ChatLines += $"{s}{Environment.NewLine}"); .Subscribe(s => ChatLines += $"{s}{Environment.NewLine}");
}); });
SendMessageCommand = ReactiveCommand.CreateFromTask<string>((s, t) => s.StartsWith("!") ? SendMessageCommand = ReactiveCommand.CreateFromTask<string>(s => s.StartsWith("!") ?
clientService.InvokeCommandAsync(new(s[(s.IndexOf('!') + 1)..]), t) : clientService.Api.InvokeChatCommand(new(s[(s.IndexOf('!') + 1)..])) :
clientService.SendChatMessageAsync(new("Server", s, ChatChannel.GlobalScripted), t)); clientService.Api.SendChatMessage(new("Server", s, ChatChannel.GlobalScripted)));
InvalidCommandPopup = SendMessageCommand.ThrownExceptions InvalidCommandPopup = SendMessageCommand.ThrownExceptions
.Where(b => b is HttpRequestException {StatusCode: HttpStatusCode.NotFound or HttpStatusCode.BadRequest}) .Where(b => b is HttpRequestException {StatusCode: HttpStatusCode.NotFound or HttpStatusCode.BadRequest})

View File

@@ -22,7 +22,7 @@ public class DashboardViewModel : ViewModelBase
.Subscribe(_ => .Subscribe(_ =>
{ {
Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(10)) Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(10))
.Select(_ => Observable.FromAsync(t => _clientService.GetServerStatusAsync(t))) .Select(_ => Observable.FromAsync(() => _clientService.Api.GetServerStatus()))
.Concat() .Concat()
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(r => .Subscribe(r =>
@@ -49,11 +49,11 @@ public class DashboardViewModel : ViewModelBase
}); });
}); });
StartCommand = ReactiveCommand.CreateFromTask(t => _clientService.StartServerAsync(t), StartCommand = ReactiveCommand.CreateFromTask(() => _clientService.Api.StartServer(),
this.WhenAnyValue(x => x.Status) this.WhenAnyValue(x => x.Status)
.Select(b => b is ServerStatus.Stopped)); .Select(b => b is ServerStatus.Stopped));
StopCommand = ReactiveCommand.CreateFromTask<bool>((b, t) => _clientService.StopServerAsync(new(b), t), StopCommand = ReactiveCommand.CreateFromTask<bool>(b => _clientService.Api.StopServer(new(b)),
this.WhenAnyValue(x => x.Status) this.WhenAnyValue(x => x.Status)
.Select(b => b is ServerStatus.Running)); .Select(b => b is ServerStatus.Running));
} }

View File

@@ -12,7 +12,7 @@ public class ServerConfigViewModel : ViewModelBase
{ {
Observable.FromEventPattern(clientService, nameof(clientService.Connected)) Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetServerSettingsAsync)) .Select(_ => Observable.FromAsync(clientService.Api.GetServerSettings))
.Concat() .Concat()
.Subscribe(b => .Subscribe(b =>
{ {
@@ -24,33 +24,33 @@ public class ServerConfigViewModel : ViewModelBase
Port = b.ListenEndPoint.Port; Port = b.ListenEndPoint.Port;
}); });
SaveCommand = ReactiveCommand.CreateFromTask(t => SaveCommand = ReactiveCommand.CreateFromTask(() =>
clientService.SetServerSettingsAsync(new( clientService.Api.SetServerSettings(new(
Name, Name,
MapName, MapName,
Description, Description,
MemberLimit, MemberLimit,
new(Ip, Port) new(Ip, Port)
), t)); )));
Worlds = Observable.FromEventPattern(clientService, nameof(clientService.Connected)) Worlds = Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetWorldsAsync)) .Select(_ => Observable.FromAsync(clientService.Api.GetWorlds))
.Concat() .Concat()
.SelectMany(ids => ids) .SelectMany(ids => ids)
.Select(id => Observable.FromAsync(t => clientService.GetWorldAsync(id, t)).Select(b => new World(id, b.Name, b.SizeKb))) .Select(id => Observable.FromAsync(() => clientService.Api.GetWorld(id)).Select(b => new World(id, b.Name, b.SizeKb)))
.Concat(); .Concat();
Observable.FromEventPattern(clientService, nameof(clientService.Connected)) Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetSelectedWorld)) .Select(_ => Observable.FromAsync(clientService.Api.GetSelectedWorld))
.Concat() .Concat()
.Select(id => Observable.FromAsync(t => clientService.GetWorldAsync(id, t)).Select(b => new World(id, b.Name, b.SizeKb))) .Select(id => Observable.FromAsync(() => clientService.Api.GetWorld(id)).Select(b => new World(id, b.Name, b.SizeKb)))
.Concat() .Concat()
.BindTo(this, x => x.SelectedWorld); .BindTo(this, x => x.SelectedWorld);
this.ObservableForProperty(x => x.SelectedWorld) this.ObservableForProperty(x => x.SelectedWorld)
.Select(world => Observable.FromAsync(t => clientService.SelectWorldAsync(world.Value!.Id, t))) .Select(world => Observable.FromAsync(() => clientService.Api.SelectWorld(world.Value!.Id)))
.Concat() .Concat()
.Subscribe(_ => { }); .Subscribe(_ => { });
} }