Merge pull request #388 from Moonlight-Panel/v2_ImproveConsoleStreaming
Improved console streaming
This commit is contained in:
commit
fd01787dfb
9 changed files with 106 additions and 72 deletions
13
.idea/.idea.Moonlight/.idea/material_theme_project_new.xml
Normal file
13
.idea/.idea.Moonlight/.idea/material_theme_project_new.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MaterialThemeProjectNewConfig">
|
||||
<option name="metadata">
|
||||
<MTProjectMetadataState>
|
||||
<option name="migrated" value="true" />
|
||||
<option name="pristineConfig" value="false" />
|
||||
<option name="userId" value="52a374ed:18c1029d858:-8000" />
|
||||
<option name="version" value="8.13.2" />
|
||||
</MTProjectMetadataState>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -55,9 +55,9 @@ public class AvatarController : Controller
|
|||
if (!IdentityService.IsLoggedIn)
|
||||
return StatusCode(403);
|
||||
|
||||
if (ConfigService.Get().Security.EnforceAvatarPrivacy &&
|
||||
id != IdentityService.CurrentUser.Id &&
|
||||
IdentityService.CurrentUser.Permissions < 1000)
|
||||
if (ConfigService.Get().Security.EnforceAvatarPrivacy && // Do we need to enforce privacy?
|
||||
id != IdentityService.CurrentUser.Id && // is the user not viewing his own image?
|
||||
IdentityService.CurrentUser.Permissions < 1000) // and not an admin?
|
||||
{
|
||||
return StatusCode(403);
|
||||
}
|
||||
|
|
|
@ -22,13 +22,16 @@ public class DiagnoseService
|
|||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
|
||||
// Create in memory zip archive
|
||||
using var dataStream = new MemoryStream();
|
||||
var zipArchive = new ZipArchive(dataStream, ZipArchiveMode.Create, true);
|
||||
|
||||
// Call every plugin to perform their modifications to the file
|
||||
await PluginService.ExecuteFuncAsync<IDiagnoseAction>(
|
||||
async x => await x.GenerateReport(zipArchive, scope.ServiceProvider)
|
||||
);
|
||||
|
||||
// Add a timestamp
|
||||
await zipArchive.AddText("exported_at.txt", Formatter.FormatDate(DateTime.UtcNow));
|
||||
|
||||
zipArchive.Dispose();
|
||||
|
|
|
@ -5,7 +5,7 @@ using MoonCore.Helpers;
|
|||
namespace Moonlight.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a event to execute code when a user leaves the page
|
||||
/// This class provides an event to execute code when a user leaves the page
|
||||
/// </summary>
|
||||
|
||||
[Scoped]
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
using MoonCore.Helpers;
|
||||
using Moonlight.Features.Servers.Api.Packets;
|
||||
using Moonlight.Features.Servers.Entities;
|
||||
using Moonlight.Features.Servers.Models.Abstractions;
|
||||
using Moonlight.Features.Servers.Models.Enums;
|
||||
|
||||
namespace Moonlight.Features.Servers.Helpers;
|
||||
|
||||
public class ServerConsole
|
||||
public class ServerConsole : IDisposable
|
||||
{
|
||||
public SmartEventHandler<ServerState> OnStateChange { get; set; } = new();
|
||||
public SmartEventHandler<ServerStats> OnStatsChange { get; set; } = new();
|
||||
|
@ -23,7 +22,7 @@ public class ServerConsole
|
|||
private readonly Server Server;
|
||||
|
||||
private ClientWebSocket WebSocket;
|
||||
private WsPacketConnection PacketConnection;
|
||||
private AdvancedWebsocketStream WebsocketStream;
|
||||
|
||||
private CancellationTokenSource Cancellation = new();
|
||||
|
||||
|
@ -50,11 +49,11 @@ public class ServerConsole
|
|||
wsUrl = $"ws://{Server.Node.Fqdn}:{Server.Node.HttpPort}/servers/{Server.Id}/ws";
|
||||
|
||||
await WebSocket.ConnectAsync(new Uri(wsUrl), CancellationToken.None);
|
||||
PacketConnection = new WsPacketConnection(WebSocket);
|
||||
WebsocketStream = new AdvancedWebsocketStream(WebSocket);
|
||||
|
||||
await PacketConnection.RegisterPacket<string>("output");
|
||||
await PacketConnection.RegisterPacket<ServerState>("state");
|
||||
await PacketConnection.RegisterPacket<ServerStats>("stats");
|
||||
WebsocketStream.RegisterPacket<string>(1);
|
||||
WebsocketStream.RegisterPacket<ServerState>(2);
|
||||
WebsocketStream.RegisterPacket<ServerStats>(3);
|
||||
|
||||
Task.Run(Worker);
|
||||
}
|
||||
|
@ -65,7 +64,7 @@ public class ServerConsole
|
|||
{
|
||||
try
|
||||
{
|
||||
var packet = await PacketConnection.Receive();
|
||||
var packet = await WebsocketStream.ReceivePacket();
|
||||
|
||||
if (packet == null)
|
||||
continue;
|
||||
|
@ -100,9 +99,11 @@ public class ServerConsole
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is not WebSocketException)
|
||||
if (e is WebSocketException)
|
||||
Logger.Warn($"Lost connection to daemon server websocket: {e.Message}");
|
||||
else
|
||||
{
|
||||
Logger.Warn("Lost connection to daemon server websocket");
|
||||
Logger.Warn("Server console ws disconnected because of application error:");
|
||||
Logger.Warn(e);
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,7 @@ public class ServerConsole
|
|||
}
|
||||
|
||||
await OnDisconnected.Invoke();
|
||||
await PacketConnection.Close();
|
||||
await WebsocketStream.Close();
|
||||
}
|
||||
|
||||
public async Task Close()
|
||||
|
@ -119,8 +120,8 @@ public class ServerConsole
|
|||
if(!Cancellation.IsCancellationRequested)
|
||||
Cancellation.Cancel();
|
||||
|
||||
if(PacketConnection != null)
|
||||
await PacketConnection.Close();
|
||||
if(WebsocketStream != null)
|
||||
await WebsocketStream.Close();
|
||||
}
|
||||
|
||||
private string[] GetMessageCache()
|
||||
|
@ -128,4 +129,14 @@ public class ServerConsole
|
|||
lock (MessageCache)
|
||||
return MessageCache.ToArray();
|
||||
}
|
||||
|
||||
public async void Dispose()
|
||||
{
|
||||
MessageCache.Clear();
|
||||
|
||||
if (WebSocket.State == WebSocketState.Open)
|
||||
await WebsocketStream.Close();
|
||||
|
||||
WebSocket.Dispose();
|
||||
}
|
||||
}
|
|
@ -36,9 +36,9 @@ public class ServersControllers : Controller
|
|||
var websocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||
|
||||
// Build connection wrapper
|
||||
var wsPacketConnection = new WsPacketConnection(websocket);
|
||||
await wsPacketConnection.RegisterPacket<int>("amount");
|
||||
await wsPacketConnection.RegisterPacket<ServerConfiguration>("serverConfiguration");
|
||||
var websocketStream = new AdvancedWebsocketStream(websocket);
|
||||
websocketStream.RegisterPacket<int>(1);
|
||||
websocketStream.RegisterPacket<ServerConfiguration>(2);
|
||||
|
||||
// Read server data for the node
|
||||
var node = (HttpContext.Items["Node"] as ServerNode)!;
|
||||
|
@ -62,13 +62,13 @@ public class ServersControllers : Controller
|
|||
.ToArray();
|
||||
|
||||
// Send the amount of configs the node will receive
|
||||
await wsPacketConnection.Send(servers.Length);
|
||||
await websocketStream.SendPacket(servers.Length);
|
||||
|
||||
// Send the server configurations
|
||||
foreach (var serverConfiguration in serverConfigurations)
|
||||
await wsPacketConnection.Send(serverConfiguration);
|
||||
await websocketStream.SendPacket(serverConfiguration);
|
||||
|
||||
await wsPacketConnection.WaitForClose();
|
||||
await websocketStream.WaitForClose();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
|
|
@ -113,13 +113,7 @@
|
|||
<ServerNavigation Index="@GetIndex()" ServerId="@Id"/>
|
||||
|
||||
<div class="mt-3">
|
||||
@if (IsInstalling)
|
||||
{
|
||||
<div class="card card-body bg-black p-3">
|
||||
<Terminal @ref="InstallTerminal" EnableClipboard="false"/>
|
||||
</div>
|
||||
}
|
||||
else if (IsConsoleDisconnected)
|
||||
@if (IsConsoleDisconnected)
|
||||
{
|
||||
<IconAlert Title="Connection to server lost" Color="danger" Icon="bx-error">
|
||||
We lost the connection to the server. Please refresh the page in order to retry. If this error persists please contact the support
|
||||
|
@ -137,6 +131,12 @@
|
|||
The node this server is on is still booting. Please refresh the page in order to retry. If this error persists please contact the support
|
||||
</IconAlert>
|
||||
}
|
||||
else if (IsInstalling)
|
||||
{
|
||||
<div class="card card-body bg-black p-3">
|
||||
<Terminal @ref="InstallTerminal" EnableClipboard="false"/>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<CascadingValue Value="Server">
|
||||
|
@ -217,37 +217,7 @@
|
|||
Console = new ServerConsole(Server);
|
||||
|
||||
// Configure
|
||||
Console.OnStateChange += async state =>
|
||||
{
|
||||
// General rerender to update the state text in the ui
|
||||
// NOTE: Obsolete because of the update timer
|
||||
//await InvokeAsync(StateHasChanged);
|
||||
|
||||
// Change from offline to installing
|
||||
// This will trigger the initialisation of the install view
|
||||
if (state == ServerState.Installing && !IsInstalling)
|
||||
{
|
||||
IsInstalling = true;
|
||||
|
||||
// After this call, we should have access to the install terminal reference
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
Console.OnNewMessage += OnInstallConsoleMessage;
|
||||
}
|
||||
// Change from installing to offline
|
||||
// This will trigger the destruction of the install view
|
||||
else if (state == ServerState.Offline && IsInstalling)
|
||||
{
|
||||
IsInstalling = false;
|
||||
|
||||
Console.OnNewMessage -= OnInstallConsoleMessage;
|
||||
|
||||
// After this call, the install terminal will disappear
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
await ToastService.Info("Server installation complete");
|
||||
}
|
||||
};
|
||||
Console.OnStateChange += async state => await HandleStateChange(state);
|
||||
|
||||
Console.OnDisconnected += async () =>
|
||||
{
|
||||
|
@ -288,6 +258,41 @@
|
|||
}
|
||||
|
||||
UpdateTimer = new Timer(async _ => { await InvokeAsync(StateHasChanged); }, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
|
||||
|
||||
var state = await ServerService.GetState(Server);
|
||||
await HandleStateChange(state);
|
||||
}
|
||||
|
||||
private async Task HandleStateChange(ServerState state)
|
||||
{
|
||||
// General rerender to update the state text in the ui
|
||||
// NOTE: Obsolete because of the update timer
|
||||
//await InvokeAsync(StateHasChanged);
|
||||
|
||||
// Change from offline to installing
|
||||
// This will trigger the initialisation of the install view
|
||||
if (state == ServerState.Installing && !IsInstalling)
|
||||
{
|
||||
IsInstalling = true;
|
||||
|
||||
// After this call, we should have access to the install terminal reference
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
Console.OnNewMessage += OnInstallConsoleMessage;
|
||||
}
|
||||
// Change from installing to offline
|
||||
// This will trigger the destruction of the install view
|
||||
else if (state == ServerState.Offline && IsInstalling)
|
||||
{
|
||||
IsInstalling = false;
|
||||
|
||||
Console.OnNewMessage -= OnInstallConsoleMessage;
|
||||
|
||||
// After this call, the install terminal will disappear
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
await ToastService.Info("Server installation complete");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnInstallConsoleMessage(string message)
|
||||
|
@ -308,7 +313,10 @@
|
|||
await UpdateTimer.DisposeAsync();
|
||||
|
||||
if (Console != null)
|
||||
{
|
||||
await Console.Close();
|
||||
Console.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetIndex()
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@using Moonlight.Features.Servers.Models.Abstractions
|
||||
@using Moonlight.Features.Servers.Services
|
||||
@using Moonlight.Features.Servers.UI.Components
|
||||
@using Moonlight.Features.Servers.Entities
|
||||
|
@ -6,7 +5,6 @@
|
|||
@using Moonlight.Features.Servers.Api.Packets
|
||||
@using Moonlight.Features.Servers.Models.Enums
|
||||
@using MoonCore.Helpers
|
||||
@using ApexCharts
|
||||
|
||||
@inject ServerService ServerService
|
||||
|
||||
|
@ -79,13 +77,14 @@
|
|||
var text = "";
|
||||
|
||||
foreach (var line in ServerConsole.Messages.TakeLast(50))
|
||||
text += line + "\n\r";
|
||||
{
|
||||
var lineModified = line.Replace("\n", "\n\r");
|
||||
text += lineModified + "\n\r";
|
||||
}
|
||||
|
||||
await Terminal.Write(text);
|
||||
|
||||
|
||||
ServerConsole.OnNewMessage += OnMessage;
|
||||
|
||||
ServerConsole.OnStatsChange += HandleStats;
|
||||
ServerConsole.OnStateChange += HandleState;
|
||||
}
|
||||
|
@ -108,7 +107,7 @@
|
|||
|
||||
private async Task OnMessage(string message)
|
||||
{
|
||||
await Terminal.WriteLine(message);
|
||||
await Terminal.Write(message + "\n\r");
|
||||
}
|
||||
|
||||
private async Task SendCommand()
|
||||
|
|
|
@ -74,8 +74,7 @@
|
|||
<Folder Include="Features\FileManager\Http\Requests\" />
|
||||
<Folder Include="Features\FileManager\Http\Resources\" />
|
||||
<Folder Include="Features\Servers\Http\Resources\" />
|
||||
<Folder Include="storage\assetOverrides\x\y\" />
|
||||
<Folder Include="storage\logs\" />
|
||||
<Folder Include="storage\" />
|
||||
<Folder Include="Styles\" />
|
||||
<Folder Include="wwwroot\css\" />
|
||||
</ItemGroup>
|
||||
|
@ -90,7 +89,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MoonCore" Version="1.1.9" />
|
||||
<PackageReference Include="MoonCore" Version="1.2.7" />
|
||||
<PackageReference Include="MoonCoreUI" Version="1.1.5" />
|
||||
<PackageReference Include="Otp.NET" Version="1.3.0" />
|
||||
<PackageReference Include="QRCoder" Version="1.4.3" />
|
||||
|
@ -114,6 +113,7 @@
|
|||
<_ContentIncludedByDefault Remove="Features\FileManager\UI\Components\FileManager.razor" />
|
||||
<_ContentIncludedByDefault Remove="Features\FileManager\UI\Components\FileUploader.razor" />
|
||||
<_ContentIncludedByDefault Remove="Features\FileManager\UI\Components\FileView.razor" />
|
||||
<_ContentIncludedByDefault Remove="storage\configs\core.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Reference in a new issue