feat: add server logs functionality with role-based access and system channel management

- Introduced a new migration to add the IsSystem column to the Channels table.
- Updated the DbContext model snapshot to reflect the new IsSystem property.
- Enhanced the ChannelService to manage system channels, including creation, visibility control, and protection against deletion.
- Implemented ServerLogsService to handle live server logging, including reading from log files and managing access based on user roles.
- Created ServerLogsSink to queue log events for streaming to the live log room.
- Developed ServerLogsStreamService to stream log events to clients in real-time.
- Added configuration options for server logs in appsettings.
- Implemented comprehensive unit tests for channel service system channel behavior and server logs functionality.
This commit is contained in:
HueByte
2026-07-17 20:44:47 +02:00
parent df1bd0119c
commit 38eca99fb1
22 changed files with 1569 additions and 17 deletions
+20 -1
View File
@@ -10,6 +10,7 @@ using EchoHub.Server.Data;
using EchoHub.Server.Hubs;
using EchoHub.Server.Irc;
using EchoHub.Server.Services;
using EchoHub.Server.Services.ServerLogs;
using EchoHub.Server.Setup;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.RateLimiting;
@@ -41,9 +42,23 @@ while (true)
builder.Services.Configure<HostOptions>(options =>
options.ShutdownTimeout = TimeSpan.FromSeconds(5));
// ── Server log room (admin-configurable via the "ServerLogs" section) ─
// Bound before Serilog so the live-log sink can be wired into the pipeline. The sink
// is a singleton shared between Serilog (producer) and the stream service (consumer).
var serverLogsOptions = builder.Configuration.GetSection("ServerLogs").Get<ServerLogsOptions>() ?? new ServerLogsOptions();
builder.Services.AddSingleton(serverLogsOptions);
builder.Services.AddSingleton<ServerLogsService>();
var serverLogsSink = serverLogsOptions.Enabled ? new ServerLogsSink(serverLogsOptions) : null;
if (serverLogsSink is not null)
builder.Services.AddSingleton(serverLogsSink);
// ── Serilog ──────────────────────────────────────────────────────────
builder.Host.UseSerilog((context, config) =>
config.ReadFrom.Configuration(context.Configuration));
{
config.ReadFrom.Configuration(context.Configuration);
if (serverLogsSink is not null)
config.WriteTo.Sink(serverLogsSink);
});
// ── SQLite + EF Core ─────────────────────────────────────────────────
var defaultDbPath = Path.Combine(AppContext.BaseDirectory, "echohub.db");
@@ -127,6 +142,10 @@ while (true)
builder.Services.AddHostedService<FileCleanupService>();
builder.Services.AddHostedService<MuteExpirationService>();
// Live server-log streaming (only when the sink is active)
if (serverLogsSink is not null)
builder.Services.AddHostedService<ServerLogsStreamService>();
// ── Encryption ─────────────────────────────────────────────────────
builder.Services.AddSingleton<IMessageEncryptionService, MessageEncryptionService>();