mirror of
https://github.com/spacebarchat/server.git
synced 2026-09-17 12:27:35 +00:00
client: gateway retry, session remove
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
@using System.Diagnostics
|
||||
@using ArcaneLibs.Blazor.Components.Services
|
||||
@using ArcaneLibs.Extensions
|
||||
@using Spacebar.Client.WebCore
|
||||
@using Spacebar.Client.WebCore.Client
|
||||
@using Spacebar.Models.Api
|
||||
@using Spacebar.Models.Gateway
|
||||
@using Spacebar.Sdk.Core
|
||||
@inject SessionStore sessionStore
|
||||
@@ -17,12 +19,15 @@
|
||||
private DebugBanner _dbgBanner = null!;
|
||||
private bool _readyReceived = false;
|
||||
|
||||
public ClientManager() {
|
||||
ClientAvailable = Task.Run(async () => {
|
||||
public ClientManager()
|
||||
{
|
||||
ClientAvailable = Task.Run(async () =>
|
||||
{
|
||||
while (Client is null) await Task.Delay(50);
|
||||
ClientAvailable = null;
|
||||
});
|
||||
ClientReady = Task.Run(async () => {
|
||||
ClientReady = Task.Run(async () =>
|
||||
{
|
||||
while (!_readyReceived) await Task.Delay(50);
|
||||
ClientAvailable = null;
|
||||
});
|
||||
@@ -38,40 +43,40 @@
|
||||
public Task? ClientAvailable { get; set; }
|
||||
public Task? ClientReady { get; set; }
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender) return;
|
||||
await _dbgBanner.SetStatus("Preparing for launch!");
|
||||
await Task.Delay(125);
|
||||
var session = await sessionStore.GetCurrentSessionAsync();
|
||||
if (session != null) {
|
||||
if (session != null)
|
||||
{
|
||||
Client = await clientProvider.GetAuthenticatedClientAsync(session.ServerName, session.AccessToken);
|
||||
await _dbgBanner.SetStatus($"Got authenticated client for {session.ProfileCache.Username}#{session.ProfileCache.Discriminator} on {session.ServerName}! Connecting to gateway...");
|
||||
Client.Gateway.IdentifyData.ClientProperties = new IdentifyClientProperties() {
|
||||
Client.Gateway.IdentifyData.ClientProperties = new IdentifyClientProperties()
|
||||
{
|
||||
HasClientMods = false,
|
||||
ApplicationArchitecture = "wasm"
|
||||
ApplicationArchitecture = "wasm",
|
||||
}.ToJsonNode().AsObject();
|
||||
StateHasChanged();
|
||||
await Client.Gateway.Connect();
|
||||
_ = Client.Gateway.Start().ContinueWith(ct => {
|
||||
jsConsole.Warn("[ClientManager] Heartbeat loop exited!");
|
||||
if (ct.IsFaulted) {
|
||||
jsConsole.Error("Unhandled exception during gateway connection:", ct.Exception.ToString());
|
||||
throw ct.Exception;
|
||||
}
|
||||
});
|
||||
Client.Gateway.OnceGatewayMessage.Add(async msg => {
|
||||
if (msg is { Opcode: GatewayOpcode.S2CDispatch, DispatchEventType: "READY" }) {
|
||||
_ = RunInnerLoopAsync();
|
||||
Client.Gateway.OnceGatewayMessage.Add(async msg =>
|
||||
{
|
||||
if (msg is { Opcode: GatewayOpcode.S2CDispatch, DispatchEventType: "READY" })
|
||||
{
|
||||
await _dbgBanner.SetStatus($"Got READY from gateway, deserializing...");
|
||||
var content = msg.GetData<ReadyResponse>();
|
||||
await _dbgBanner.SetStatus($"Deserialized READY from gateway, handling...");
|
||||
// ClientState.Guilds.AddRange(content.Guilds.ToDictionary(x=>x.Id, x=>x));
|
||||
foreach (var guild in content.Guilds) {
|
||||
foreach (var guild in content.Guilds)
|
||||
{
|
||||
ClientState.Guilds.Add(guild.Id, guild);
|
||||
await _dbgBanner.SetStatus($"Deserialized READY from gateway, handling... guilds ({ClientState.Guilds.Count})");
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
foreach (var guild in content.Relationships) {
|
||||
foreach (var guild in content.Relationships)
|
||||
{
|
||||
// ClientState.Relationships.Add(guild.Id, guild);
|
||||
await _dbgBanner.SetStatus($"Deserialized READY from gateway, handling... guilds ({ClientState.Guilds.Count}), relationships (0)");
|
||||
await Task.Delay(1);
|
||||
@@ -84,20 +89,66 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
if (msg is { Opcode: GatewayOpcode.S2CDispatch, DispatchEventType: "READY_SUPPLEMENTAL" }) {
|
||||
if (msg is { Opcode: GatewayOpcode.S2CDispatch, DispatchEventType: "READY_SUPPLEMENTAL" })
|
||||
{
|
||||
await _dbgBanner.SetStatus("Received READY_SUPPLEMENTAL...");
|
||||
await jsConsole.Info("Parsed ready_supplemental payload", new { original = msg.EventData });
|
||||
_ =_dbgBanner.SetStatus(null, 1750);
|
||||
_ = _dbgBanner.SetStatus(null, 1750);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
await _dbgBanner.SetStatus("No session marked as current... :(");
|
||||
await _dbgBanner.SetStatus(null, 1750);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunInnerLoopAsync()
|
||||
{
|
||||
var tries = 1;
|
||||
while (true)
|
||||
{
|
||||
var uptime = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
int delay = (int)((tries++ * 1.2) * 250);
|
||||
await jsConsole.Info("Starting gateway connection in", delay, "ms.");
|
||||
await Task.Delay(delay);
|
||||
await Client.Gateway.Connect();
|
||||
await Client.Gateway.Start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await Client.Gateway.Disconnect();
|
||||
await jsConsole.Warn($"[ClientManager] Heartbeat loop exited! ({Client.Gateway.RawClientWebSocket.CloseStatus}: {Client.Gateway.RawClientWebSocket.CloseStatusDescription})");
|
||||
await jsConsole.Error("Unhandled exception during gateway connection:", e.ToString());
|
||||
_ = _dbgBanner.SetStatus("Unhandled exception during gateway connection: " + string.Join("\n", e.ToString().Split("\n").Where(x => !x.Trim().StartsWith("at "))));
|
||||
if (uptime.Elapsed.TotalSeconds < 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _dbgBanner.SetStatus("Attempting to validate token...");
|
||||
await Client.GetCurrentUser();
|
||||
}
|
||||
catch (Exception ve)
|
||||
{
|
||||
await _dbgBanner.SetStatus(ve.ToString());
|
||||
await jsConsole.Error(ve.ToString());
|
||||
if (ve is SpacebarApiException { Code: 40001 })
|
||||
{
|
||||
await _dbgBanner.SetStatus("Invalid access token, please sign in again!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
}
|
||||
}
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
@using ArcaneLibs.Blazor.Components
|
||||
@using ArcaneLibs.Blazor.Components.Services
|
||||
@using Spacebar.Client.WebCore
|
||||
@using Spacebar.Sdk.Core
|
||||
@inject SessionStore sessionStore
|
||||
@inject SpacebarClientProviderService clientProvider
|
||||
@inject JsConsoleService jsConsole
|
||||
|
||||
<DebugBanner Name="@GetType().Name" @ref="_dbgBanner"/>
|
||||
@if (_sessionPickerVisible) {
|
||||
@if (_sessionPickerVisible)
|
||||
{
|
||||
<ModalWindow Title="Session manager" OnCloseClickedAsync="@(() => SetSessionPickerVisible(false))">
|
||||
@foreach (var (sessionId, session) in _sessionEntries) {
|
||||
@foreach (var (sessionId, session) in _sessionEntries)
|
||||
{
|
||||
<LinkButton
|
||||
OnClickAsync="@(() => SetCurrentSessionAsync(sessionId))">@(session.ProfileCache?.Username ?? "Unknown user")#@(session.ProfileCache?.Discriminator ?? "0000") <sub
|
||||
class="code">on @session.ServerName</sub></LinkButton>
|
||||
<LinkButton OnClickAsync="@(() => RemoveSessionAsync(sessionId))">x</LinkButton>
|
||||
}
|
||||
<br/><br/>
|
||||
<LinkButton href="/login">Log in</LinkButton>
|
||||
@@ -24,7 +29,8 @@
|
||||
|
||||
private Dictionary<Guid, SessionEntry> _sessionEntries = [];
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender) {
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (!firstRender) return;
|
||||
await _dbgBanner.SetStatus("Crunching numbers...");
|
||||
_sessionPickerVisible = await sessionStore.GetCurrentSessionAsync() == null;
|
||||
@@ -32,7 +38,8 @@
|
||||
await _dbgBanner.SetStatus(null, 1000);
|
||||
}
|
||||
|
||||
public async Task SetSessionPickerVisible(bool visible = true) {
|
||||
public async Task SetSessionPickerVisible(bool visible = true)
|
||||
{
|
||||
await jsConsole.Info("[SessionManager] showing session picker...");
|
||||
_sessionEntries = visible ? await sessionStore.GetAllSessionsAsync() : [];
|
||||
_sessionPickerVisible = visible;
|
||||
@@ -40,7 +47,8 @@
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
private async Task SetCurrentSessionAsync(Guid sessionId) {
|
||||
private async Task SetCurrentSessionAsync(Guid sessionId)
|
||||
{
|
||||
_sessionPickerVisible = false;
|
||||
StateHasChanged();
|
||||
await sessionStore.SetCurrentSessionAsync(sessionId);
|
||||
@@ -49,4 +57,25 @@
|
||||
await _dbgBanner.SetStatus(null, 3000);
|
||||
}
|
||||
|
||||
private async Task RemoveSessionAsync(Guid sessionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _dbgBanner.SetStatus("Trying to log out...");
|
||||
var sess = _sessionEntries[sessionId];
|
||||
var client = await clientProvider.GetAuthenticatedClientAsync(sess.ServerName, sess.AccessToken);
|
||||
await client.LogOutAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _dbgBanner.SetStatus("Failed to log out, removing anyway: " + string.Join("\n", e.ToString().Split("\n").Where(x => !x.Trim().StartsWith("at "))));
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
await sessionStore.RemoveSessionAsync(sessionId);
|
||||
await _dbgBanner.SetStatus("Session removed successfully!");
|
||||
await _dbgBanner.SetStatus(null, 1000);
|
||||
await SetSessionPickerVisible();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,10 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
|
||||
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
|
||||
<UseSystemResourceKeys>false</UseSystemResourceKeys>
|
||||
<UseSizeOptimizedLinq>false</UseSizeOptimizedLinq> <!-- makes Linq slightly faster -->
|
||||
<DebuggerSupport>true</DebuggerSupport>
|
||||
<TrimmerRemoveSymbols>false</TrimmerRemoveSymbols>
|
||||
|
||||
<!-- copied from https://cgit.rory.gay/matrix/tools/MatrixUtils.git/tree/MatrixUtils.Web/MatrixUtils.Web.csproj -->
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
|
||||
@@ -33,6 +33,17 @@ public class SessionStore(ILogger<SessionStore> logger, LocalStorageService loca
|
||||
public async Task SetCurrentSessionAsync(Guid sessionId) {
|
||||
await localStorage.SetItemAsJsonAsync(CurrentSessionKey, sessionId);
|
||||
}
|
||||
|
||||
public async Task RemoveSessionAsync(Guid sessionId)
|
||||
{
|
||||
var sessions = await GetAllSessionsAsync();
|
||||
sessions.Remove(sessionId);
|
||||
await localStorage.SetItemAsJsonAsync(AllSessionsKey, sessions);
|
||||
|
||||
if (await localStorage.ContainsKeyAsync(CurrentSessionKey))
|
||||
if (await localStorage.GetItemFromJsonAsync<Guid>(CurrentSessionKey) == sessionId)
|
||||
await localStorage.RemoveItemAsync(CurrentSessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
public class SessionEntry {
|
||||
|
||||
Reference in New Issue
Block a user