1
0
mirror of https://github.com/chylex/Minecraft-Phantom-Panel.git synced 2024-11-25 16:42:54 +01:00

Compare commits

..

2 Commits

Author SHA1 Message Date
5ffbde6a04
Reimplement Web service 2023-12-02 06:30:07 +01:00
e69b0245aa
Refactor methods for sending messages and waiting for replies 2023-12-02 06:30:06 +01:00
12 changed files with 93 additions and 62 deletions

View File

@ -3,7 +3,7 @@
namespace Phantom.Common.Data.Web.EventLog; namespace Phantom.Common.Data.Web.EventLog;
[MemoryPackable(GenerateType.VersionTolerant)] [MemoryPackable(GenerateType.VersionTolerant)]
public sealed record EventLogItem( public sealed partial record EventLogItem(
[property: MemoryPackOrder(0)] DateTime UtcTime, [property: MemoryPackOrder(0)] DateTime UtcTime,
[property: MemoryPackOrder(1)] Guid? AgentGuid, [property: MemoryPackOrder(1)] Guid? AgentGuid,
[property: MemoryPackOrder(2)] EventLogEventType EventType, [property: MemoryPackOrder(2)] EventLogEventType EventType,

View File

@ -11,6 +11,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.Linq.Async" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -19,8 +19,8 @@ public sealed class AuditLogRepositoryReader {
.AsQueryable() .AsQueryable()
.OrderByDescending(static entity => entity.UtcTime) .OrderByDescending(static entity => entity.UtcTime)
.Take(count) .Take(count)
.Select(static entity => new AuditLogItem(entity.UtcTime, entity.UserGuid, entity.User == null ? null : entity.User.Name, entity.EventType, entity.SubjectType, entity.SubjectId, entity.Data == null ? null : entity.Data.RootElement.ToString()))
.AsAsyncEnumerable() .AsAsyncEnumerable()
.Select(static entity => new AuditLogItem(entity.UtcTime, entity.UserGuid, entity.User?.Name, entity.EventType, entity.SubjectType, entity.SubjectId, entity.Data?.RootElement.ToString()))
.ToImmutableArrayAsync(cancellationToken); .ToImmutableArrayAsync(cancellationToken);
} }
} }

View File

@ -0,0 +1,30 @@
using System.Collections.Immutable;
using Microsoft.EntityFrameworkCore;
using Phantom.Common.Data.Web.EventLog;
using Phantom.Controller.Database.Entities;
using Phantom.Utils.Collections;
namespace Phantom.Controller.Database.Repositories;
public sealed class EventLogRepository {
private readonly ILazyDbContext db;
public EventLogRepository(ILazyDbContext db) {
this.db = db;
}
public void AddItem(Guid eventGuid, DateTime utcTime, Guid? agentGuid, EventLogEventType eventType, string subjectId, Dictionary<string, object?>? extra = null) {
db.Ctx.EventLog.Add(new EventLogEntity(eventGuid, utcTime, agentGuid, eventType, subjectId, extra));
}
public Task<ImmutableArray<EventLogItem>> GetMostRecentItems(int count, CancellationToken cancellationToken) {
return db.Ctx
.EventLog
.AsQueryable()
.OrderByDescending(static entity => entity.UtcTime)
.Take(count)
.AsAsyncEnumerable()
.Select(static entity => new EventLogItem(entity.UtcTime, entity.AgentGuid, entity.EventType, entity.SubjectType, entity.SubjectId, entity.Data?.RootElement.ToString()))
.ToImmutableArrayAsync(cancellationToken);
}
}

View File

@ -20,7 +20,6 @@ public sealed class ControllerServices {
private AgentManager AgentManager { get; } private AgentManager AgentManager { get; }
private AgentJavaRuntimesManager AgentJavaRuntimesManager { get; } private AgentJavaRuntimesManager AgentJavaRuntimesManager { get; }
private EventLog EventLog { get; }
private InstanceManager InstanceManager { get; } private InstanceManager InstanceManager { get; }
private InstanceLogManager InstanceLogManager { get; } private InstanceLogManager InstanceLogManager { get; }
private EventLogManager EventLogManager { get; } private EventLogManager EventLogManager { get; }
@ -42,7 +41,6 @@ public sealed class ControllerServices {
this.AgentManager = new AgentManager(agentAuthToken, dbProvider, TaskManager, shutdownCancellationToken); this.AgentManager = new AgentManager(agentAuthToken, dbProvider, TaskManager, shutdownCancellationToken);
this.AgentJavaRuntimesManager = new AgentJavaRuntimesManager(); this.AgentJavaRuntimesManager = new AgentJavaRuntimesManager();
this.EventLog = new EventLog(dbProvider, TaskManager, shutdownCancellationToken);
this.InstanceManager = new InstanceManager(AgentManager, MinecraftVersions, dbProvider, shutdownCancellationToken); this.InstanceManager = new InstanceManager(AgentManager, MinecraftVersions, dbProvider, shutdownCancellationToken);
this.InstanceLogManager = new InstanceLogManager(); this.InstanceLogManager = new InstanceLogManager();
@ -52,7 +50,7 @@ public sealed class ControllerServices {
this.UserLoginManager = new UserLoginManager(UserManager, PermissionManager); this.UserLoginManager = new UserLoginManager(UserManager, PermissionManager);
this.AuditLogManager = new AuditLogManager(dbProvider); this.AuditLogManager = new AuditLogManager(dbProvider);
this.EventLogManager = new EventLogManager(dbProvider); this.EventLogManager = new EventLogManager(dbProvider, TaskManager, shutdownCancellationToken);
this.dbProvider = dbProvider; this.dbProvider = dbProvider;
this.webAuthToken = webAuthToken; this.webAuthToken = webAuthToken;
@ -60,7 +58,7 @@ public sealed class ControllerServices {
} }
public AgentMessageListener CreateAgentMessageListener(RpcConnectionToClient<IMessageToAgentListener> connection) { public AgentMessageListener CreateAgentMessageListener(RpcConnectionToClient<IMessageToAgentListener> connection) {
return new AgentMessageListener(connection, AgentManager, AgentJavaRuntimesManager, InstanceManager, InstanceLogManager, EventLog, cancellationToken); return new AgentMessageListener(connection, AgentManager, AgentJavaRuntimesManager, InstanceManager, InstanceLogManager, EventLogManager, cancellationToken);
} }
public WebMessageListener CreateWebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection) { public WebMessageListener CreateWebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection) {

View File

@ -1,43 +0,0 @@
using System.Collections.Immutable;
using Microsoft.EntityFrameworkCore;
using Phantom.Common.Data.Web.EventLog;
using Phantom.Controller.Database;
using Phantom.Controller.Database.Entities;
using Phantom.Utils.Collections;
using Phantom.Utils.Tasks;
namespace Phantom.Controller.Services.Events;
public sealed partial class EventLog {
private readonly IDbContextProvider dbProvider;
private readonly TaskManager taskManager;
private readonly CancellationToken cancellationToken;
public EventLog(IDbContextProvider dbProvider, TaskManager taskManager, CancellationToken cancellationToken) {
this.dbProvider = dbProvider;
this.taskManager = taskManager;
this.cancellationToken = cancellationToken;
}
private async Task AddEntityToDatabase(EventLogEntity logEntity) {
await using var ctx = dbProvider.Eager();
ctx.EventLog.Add(logEntity);
await ctx.SaveChangesAsync(cancellationToken);
}
private void AddItem(Guid eventGuid, DateTime utcTime, Guid? agentGuid, EventLogEventType eventType, string subjectId, Dictionary<string, object?>? extra = null) {
var logEntity = new EventLogEntity(eventGuid, utcTime, agentGuid, eventType, subjectId, extra);
taskManager.Run("Store event log item to database", () => AddEntityToDatabase(logEntity));
}
public async Task<ImmutableArray<EventLogItem>> GetItems(int count, CancellationToken cancellationToken) {
await using var ctx = dbProvider.Eager();
return await ctx.EventLog
.AsQueryable()
.OrderByDescending(static entity => entity.UtcTime)
.Take(count)
.Select(static entity => new EventLogItem(entity.UtcTime, entity.AgentGuid, entity.EventType, entity.SubjectType, entity.SubjectId, entity.Data))
.AsAsyncEnumerable()
.ToImmutableArrayAsync(cancellationToken);
}
}

View File

@ -4,20 +4,20 @@ using Phantom.Common.Data.Web.EventLog;
namespace Phantom.Controller.Services.Events; namespace Phantom.Controller.Services.Events;
public sealed partial class EventLog { sealed partial class EventLogManager {
internal IInstanceEventVisitor CreateInstanceEventVisitor(Guid eventGuid, DateTime utcTime, Guid agentGuid, Guid instanceGuid) { internal IInstanceEventVisitor CreateInstanceEventVisitor(Guid eventGuid, DateTime utcTime, Guid agentGuid, Guid instanceGuid) {
return new InstanceEventVisitor(this, utcTime, eventGuid, agentGuid, instanceGuid); return new InstanceEventVisitor(this, utcTime, eventGuid, agentGuid, instanceGuid);
} }
private sealed class InstanceEventVisitor : IInstanceEventVisitor { private sealed class InstanceEventVisitor : IInstanceEventVisitor {
private readonly EventLog eventLog; private readonly EventLogManager eventLogManager;
private readonly Guid eventGuid; private readonly Guid eventGuid;
private readonly DateTime utcTime; private readonly DateTime utcTime;
private readonly Guid agentGuid; private readonly Guid agentGuid;
private readonly Guid instanceGuid; private readonly Guid instanceGuid;
public InstanceEventVisitor(EventLog eventLog, DateTime utcTime, Guid eventGuid, Guid agentGuid, Guid instanceGuid) { public InstanceEventVisitor(EventLogManager eventLogManager, DateTime utcTime, Guid eventGuid, Guid agentGuid, Guid instanceGuid) {
this.eventLog = eventLog; this.eventLogManager = eventLogManager;
this.eventGuid = eventGuid; this.eventGuid = eventGuid;
this.utcTime = utcTime; this.utcTime = utcTime;
this.agentGuid = agentGuid; this.agentGuid = agentGuid;
@ -25,21 +25,21 @@ public sealed partial class EventLog {
} }
public void OnLaunchSucceeded(InstanceLaunchSuccededEvent e) { public void OnLaunchSucceeded(InstanceLaunchSuccededEvent e) {
eventLog.AddItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceLaunchSucceded, instanceGuid.ToString()); eventLogManager.EnqueueItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceLaunchSucceded, instanceGuid.ToString());
} }
public void OnLaunchFailed(InstanceLaunchFailedEvent e) { public void OnLaunchFailed(InstanceLaunchFailedEvent e) {
eventLog.AddItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceLaunchFailed, instanceGuid.ToString(), new Dictionary<string, object?> { eventLogManager.EnqueueItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceLaunchFailed, instanceGuid.ToString(), new Dictionary<string, object?> {
{ "reason", e.Reason.ToString() } { "reason", e.Reason.ToString() }
}); });
} }
public void OnCrashed(InstanceCrashedEvent e) { public void OnCrashed(InstanceCrashedEvent e) {
eventLog.AddItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceCrashed, instanceGuid.ToString()); eventLogManager.EnqueueItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceCrashed, instanceGuid.ToString());
} }
public void OnStopped(InstanceStoppedEvent e) { public void OnStopped(InstanceStoppedEvent e) {
eventLog.AddItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceStopped, instanceGuid.ToString()); eventLogManager.EnqueueItem(eventGuid, utcTime, agentGuid, EventLogEventType.InstanceStopped, instanceGuid.ToString());
} }
public void OnBackupCompleted(InstanceBackupCompletedEvent e) { public void OnBackupCompleted(InstanceBackupCompletedEvent e) {
@ -59,7 +59,7 @@ public sealed partial class EventLog {
dictionary["warnings"] = e.Warnings.ListFlags().Select(static warning => warning.ToString()).ToArray(); dictionary["warnings"] = e.Warnings.ListFlags().Select(static warning => warning.ToString()).ToArray();
} }
eventLog.AddItem(eventGuid, utcTime, agentGuid, eventType, instanceGuid.ToString(), dictionary.Count == 0 ? null : dictionary); eventLogManager.EnqueueItem(eventGuid, utcTime, agentGuid, eventType, instanceGuid.ToString(), dictionary.Count == 0 ? null : dictionary);
} }
} }
} }

View File

@ -0,0 +1,34 @@
using System.Collections.Immutable;
using Phantom.Common.Data.Web.EventLog;
using Phantom.Controller.Database;
using Phantom.Controller.Database.Repositories;
using Phantom.Utils.Tasks;
namespace Phantom.Controller.Services.Events;
sealed partial class EventLogManager {
private readonly IDbContextProvider dbProvider;
private readonly TaskManager taskManager;
private readonly CancellationToken cancellationToken;
public EventLogManager(IDbContextProvider dbProvider, TaskManager taskManager, CancellationToken cancellationToken) {
this.dbProvider = dbProvider;
this.taskManager = taskManager;
this.cancellationToken = cancellationToken;
}
public void EnqueueItem(Guid eventGuid, DateTime utcTime, Guid? agentGuid, EventLogEventType eventType, string subjectId, Dictionary<string, object?>? extra = null) {
taskManager.Run("Store event log item to database", () => AddItem(eventGuid, utcTime, agentGuid, eventType, subjectId, extra));
}
public async Task AddItem(Guid eventGuid, DateTime utcTime, Guid? agentGuid, EventLogEventType eventType, string subjectId, Dictionary<string, object?>? extra = null) {
await using var db = dbProvider.Lazy();
new EventLogRepository(db).AddItem(eventGuid, utcTime, agentGuid, eventType, subjectId, extra);
await db.Ctx.SaveChangesAsync(cancellationToken);
}
public async Task<ImmutableArray<EventLogItem>> GetMostRecentItems(int count) {
await using var db = dbProvider.Lazy();
return await new EventLogRepository(db).GetMostRecentItems(count, cancellationToken);
}
}

View File

@ -19,18 +19,18 @@ public sealed class AgentMessageListener : IMessageToControllerListener {
private readonly AgentJavaRuntimesManager agentJavaRuntimesManager; private readonly AgentJavaRuntimesManager agentJavaRuntimesManager;
private readonly InstanceManager instanceManager; private readonly InstanceManager instanceManager;
private readonly InstanceLogManager instanceLogManager; private readonly InstanceLogManager instanceLogManager;
private readonly EventLog eventLog; private readonly EventLogManager eventLogManager;
private readonly CancellationToken cancellationToken; private readonly CancellationToken cancellationToken;
private readonly TaskCompletionSource<Guid> agentGuidWaiter = AsyncTasks.CreateCompletionSource<Guid>(); private readonly TaskCompletionSource<Guid> agentGuidWaiter = AsyncTasks.CreateCompletionSource<Guid>();
internal AgentMessageListener(RpcConnectionToClient<IMessageToAgentListener> connection, AgentManager agentManager, AgentJavaRuntimesManager agentJavaRuntimesManager, InstanceManager instanceManager, InstanceLogManager instanceLogManager, EventLog eventLog, CancellationToken cancellationToken) { internal AgentMessageListener(RpcConnectionToClient<IMessageToAgentListener> connection, AgentManager agentManager, AgentJavaRuntimesManager agentJavaRuntimesManager, InstanceManager instanceManager, InstanceLogManager instanceLogManager, EventLogManager eventLogManager, CancellationToken cancellationToken) {
this.connection = connection; this.connection = connection;
this.agentManager = agentManager; this.agentManager = agentManager;
this.agentJavaRuntimesManager = agentJavaRuntimesManager; this.agentJavaRuntimesManager = agentJavaRuntimesManager;
this.instanceManager = instanceManager; this.instanceManager = instanceManager;
this.instanceLogManager = instanceLogManager; this.instanceLogManager = instanceLogManager;
this.eventLog = eventLog; this.eventLogManager = eventLogManager;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
} }
@ -83,7 +83,7 @@ public sealed class AgentMessageListener : IMessageToControllerListener {
} }
public async Task<NoReply> HandleReportInstanceEvent(ReportInstanceEventMessage message) { public async Task<NoReply> HandleReportInstanceEvent(ReportInstanceEventMessage message) {
message.Event.Accept(eventLog.CreateInstanceEventVisitor(message.EventGuid, message.UtcTime, await WaitForAgentGuid(), message.InstanceGuid)); message.Event.Accept(eventLogManager.CreateInstanceEventVisitor(message.EventGuid, message.UtcTime, await WaitForAgentGuid(), message.InstanceGuid));
return NoReply.Instance; return NoReply.Instance;
} }

View File

@ -5,6 +5,7 @@ using Phantom.Common.Data.Minecraft;
using Phantom.Common.Data.Replies; using Phantom.Common.Data.Replies;
using Phantom.Common.Data.Web.Agent; using Phantom.Common.Data.Web.Agent;
using Phantom.Common.Data.Web.AuditLog; using Phantom.Common.Data.Web.AuditLog;
using Phantom.Common.Data.Web.EventLog;
using Phantom.Common.Data.Web.Instance; using Phantom.Common.Data.Web.Instance;
using Phantom.Common.Data.Web.Users; using Phantom.Common.Data.Web.Users;
using Phantom.Common.Logging; using Phantom.Common.Logging;
@ -15,6 +16,7 @@ using Phantom.Common.Messages.Web.ToWeb;
using Phantom.Controller.Minecraft; using Phantom.Controller.Minecraft;
using Phantom.Controller.Rpc; using Phantom.Controller.Rpc;
using Phantom.Controller.Services.Agents; using Phantom.Controller.Services.Agents;
using Phantom.Controller.Services.Events;
using Phantom.Controller.Services.Instances; using Phantom.Controller.Services.Instances;
using Phantom.Controller.Services.Users; using Phantom.Controller.Services.Users;
using Phantom.Utils.Rpc.Message; using Phantom.Utils.Rpc.Message;
@ -35,6 +37,7 @@ public sealed class WebMessageListener : IMessageToControllerListener {
private readonly AgentJavaRuntimesManager agentJavaRuntimesManager; private readonly AgentJavaRuntimesManager agentJavaRuntimesManager;
private readonly InstanceManager instanceManager; private readonly InstanceManager instanceManager;
private readonly MinecraftVersions minecraftVersions; private readonly MinecraftVersions minecraftVersions;
private readonly EventLogManager eventLogManager;
private readonly TaskManager taskManager; private readonly TaskManager taskManager;
internal WebMessageListener( internal WebMessageListener(
@ -47,6 +50,7 @@ public sealed class WebMessageListener : IMessageToControllerListener {
AgentJavaRuntimesManager agentJavaRuntimesManager, AgentJavaRuntimesManager agentJavaRuntimesManager,
InstanceManager instanceManager, InstanceManager instanceManager,
MinecraftVersions minecraftVersions, MinecraftVersions minecraftVersions,
EventLogManager eventLogManager,
TaskManager taskManager TaskManager taskManager
) { ) {
this.connection = connection; this.connection = connection;
@ -60,6 +64,8 @@ public sealed class WebMessageListener : IMessageToControllerListener {
this.agentJavaRuntimesManager = agentJavaRuntimesManager; this.agentJavaRuntimesManager = agentJavaRuntimesManager;
this.instanceManager = instanceManager; this.instanceManager = instanceManager;
this.minecraftVersions = minecraftVersions; this.minecraftVersions = minecraftVersions;
this.eventLogManager = eventLogManager;
this.taskManager = taskManager; this.taskManager = taskManager;
} }
@ -131,6 +137,10 @@ public sealed class WebMessageListener : IMessageToControllerListener {
return auditLogManager.GetMostRecentItems(message.Count); return auditLogManager.GetMostRecentItems(message.Count);
} }
public Task<ImmutableArray<EventLogItem>> HandleGetEventLog(GetEventLogMessage message) {
return eventLogManager.GetMostRecentItems(message.Count);
}
public Task<LogInSuccess?> HandleLogIn(LogInMessage message) { public Task<LogInSuccess?> HandleLogIn(LogInMessage message) {
return userLoginManager.LogIn(message.Username, message.Password); return userLoginManager.LogIn(message.Username, message.Password);
} }

View File

@ -6,6 +6,7 @@
<PackageReference Update="Microsoft.EntityFrameworkCore.Relational" Version="7.0.11" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Relational" Version="7.0.11" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11" />
<PackageReference Update="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" /> <PackageReference Update="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
<PackageReference Update="System.Linq.Async" Version="4.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>