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.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using TorchRemote.Models.Requests;
using TorchRemote.Models.Responses;
using TorchRemote.Models.Shared;
using Refit;
using Websocket.Client;
namespace TorchRemote.Services;
@@ -31,8 +26,10 @@ public class ApiClientService
public ApiClientService()
{
Api = RestService.For<IRemoteApi>(_client);
Task.Run(ConnectionTimer);
}
public IRemoteApi Api { get; }
private async Task ConnectionTimer()
{
@@ -41,7 +38,7 @@ public class ApiClientService
await Task.Delay(1000);
try
{
await GetServerStatusAsync(CancellationToken.None);
await Api.GetServerStatus();
break;
}
catch
@@ -52,43 +49,6 @@ public class ApiClientService
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> 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="FluentAvaloniaUI" Version="1.4.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="Websocket.Client" Version="4.4.43" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />

View File

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

View File

@@ -22,7 +22,7 @@ public class DashboardViewModel : ViewModelBase
.Subscribe(_ =>
{
Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(10))
.Select(_ => Observable.FromAsync(t => _clientService.GetServerStatusAsync(t)))
.Select(_ => Observable.FromAsync(() => _clientService.Api.GetServerStatus()))
.Concat()
.ObserveOn(RxApp.MainThreadScheduler)
.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)
.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)
.Select(b => b is ServerStatus.Running));
}

View File

@@ -12,7 +12,7 @@ public class ServerConfigViewModel : ViewModelBase
{
Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetServerSettingsAsync))
.Select(_ => Observable.FromAsync(clientService.Api.GetServerSettings))
.Concat()
.Subscribe(b =>
{
@@ -24,33 +24,33 @@ public class ServerConfigViewModel : ViewModelBase
Port = b.ListenEndPoint.Port;
});
SaveCommand = ReactiveCommand.CreateFromTask(t =>
clientService.SetServerSettingsAsync(new(
SaveCommand = ReactiveCommand.CreateFromTask(() =>
clientService.Api.SetServerSettings(new(
Name,
MapName,
Description,
MemberLimit,
new(Ip, Port)
), t));
)));
Worlds = Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetWorldsAsync))
.Select(_ => Observable.FromAsync(clientService.Api.GetWorlds))
.Concat()
.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();
Observable.FromEventPattern(clientService, nameof(clientService.Connected))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(_ => Observable.FromAsync(clientService.GetSelectedWorld))
.Select(_ => Observable.FromAsync(clientService.Api.GetSelectedWorld))
.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()
.BindTo(this, 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()
.Subscribe(_ => { });
}