Functional server start/stop with log output
This commit is contained in:
parent
c618e05cf0
commit
8f1b013c0a
10 changed files with 231 additions and 9 deletions
|
@ -2,13 +2,13 @@
|
||||||
{
|
{
|
||||||
public class Server : BaseModel
|
public class Server : BaseModel
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; } = "";
|
||||||
public string Path { get; set; }
|
public string Path { get; set; } = "";
|
||||||
public string Arguments { get; set; }
|
public string Arguments { get; set; } = "";
|
||||||
public string WorkingDirectory { get; set; }
|
public string WorkingDirectory { get; set; } = "";
|
||||||
|
|
||||||
public string OnStartScriptPath { get; set; }
|
public string OnStartScriptPath { get; set; } = "";
|
||||||
public string OnStopScriptPath { get; set; }
|
public string OnStopScriptPath { get; set; } = "";
|
||||||
|
|
||||||
public bool Autostart { get; set; }
|
public bool Autostart { get; set; }
|
||||||
}
|
}
|
||||||
|
|
12
LANCommander/Hubs/LoggingHub.cs
Normal file
12
LANCommander/Hubs/LoggingHub.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace LANCommander.Hubs
|
||||||
|
{
|
||||||
|
public class LoggingHub : Hub
|
||||||
|
{
|
||||||
|
public void Log(string logMessage)
|
||||||
|
{
|
||||||
|
Clients.All.SendAsync("Log", logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
|
||||||
|
@ -34,6 +35,8 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
|
||||||
|
<PackageReference Include="NLog" Version="5.1.3" />
|
||||||
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.2.3" />
|
||||||
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
|
||||||
<PackageReference Include="swashbuckle" Version="5.6.0" />
|
<PackageReference Include="swashbuckle" Version="5.6.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
|
59
LANCommander/Logging/LoggingHubConnection.cs
Normal file
59
LANCommander/Logging/LoggingHubConnection.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
|
|
||||||
|
namespace LANCommander.Logging
|
||||||
|
{
|
||||||
|
public class LoggingHubConnection : IAsyncDisposable
|
||||||
|
{
|
||||||
|
private HubConnection? HubConnection;
|
||||||
|
private string HubUrl;
|
||||||
|
|
||||||
|
public LoggingHubConnection(string hubUrl)
|
||||||
|
{
|
||||||
|
HubUrl = hubUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Log(string logMessage)
|
||||||
|
{
|
||||||
|
await EnsureConnection();
|
||||||
|
|
||||||
|
if (HubConnection != null)
|
||||||
|
await HubConnection.SendAsync("Log", logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task EnsureConnection()
|
||||||
|
{
|
||||||
|
if (HubConnection == null)
|
||||||
|
{
|
||||||
|
HubConnection = new HubConnectionBuilder()
|
||||||
|
.WithUrl(HubUrl)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await HubConnection.StartAsync();
|
||||||
|
}
|
||||||
|
else if (HubConnection.State == HubConnectionState.Disconnected)
|
||||||
|
{
|
||||||
|
await HubConnection.StartAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (HubConnection != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await HubConnection.StopAsync();
|
||||||
|
await HubConnection.DisposeAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
NLog.Common.InternalLogger.Error(ex, "Exception in LoggingHubConnection.DisposeAsync");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
HubConnection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
LANCommander/Logging/LoggingHubTarget.cs
Normal file
37
LANCommander/Logging/LoggingHubTarget.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using NLog;
|
||||||
|
using NLog.Config;
|
||||||
|
using NLog.Targets;
|
||||||
|
|
||||||
|
namespace LANCommander.Logging
|
||||||
|
{
|
||||||
|
[Target("LoggingHub")]
|
||||||
|
public class LoggingHubTarget : AsyncTaskTarget
|
||||||
|
{
|
||||||
|
private LoggingHubConnection? Connection;
|
||||||
|
|
||||||
|
[RequiredParameter]
|
||||||
|
public string HubUrl { get; set; }
|
||||||
|
|
||||||
|
protected override void InitializeTarget()
|
||||||
|
{
|
||||||
|
Connection = new LoggingHubConnection(HubUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task WriteAsyncTask(LogEventInfo logEvent, CancellationToken token)
|
||||||
|
{
|
||||||
|
string message = Layout.Render(logEvent);
|
||||||
|
|
||||||
|
if (Connection != null)
|
||||||
|
await Connection.Log(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async void CloseTarget()
|
||||||
|
{
|
||||||
|
if (Connection != null)
|
||||||
|
{
|
||||||
|
await Connection.DisposeAsync();
|
||||||
|
Connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
<Space Direction="DirectionVHType.Horizontal">
|
<Space Direction="DirectionVHType.Horizontal">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
<Button OnClick="() => Edit(context)">Edit</Button>
|
<Button OnClick="() => Edit(context)">Edit</Button>
|
||||||
|
<Button OnClick="() => Logs(context)">Logs</Button>
|
||||||
<Button OnClick="() => Start(context)">Start</Button>
|
<Button OnClick="() => Start(context)">Start</Button>
|
||||||
<Button OnClick="() => Stop(context)">Stop</Button>
|
<Button OnClick="() => Stop(context)">Stop</Button>
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
|
@ -63,6 +64,11 @@
|
||||||
NavigationManager.NavigateTo($"/Servers/{server.Id}/Edit");
|
NavigationManager.NavigateTo($"/Servers/{server.Id}/Edit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Logs(Server server)
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo($"/Servers/{server.Id}/Logs");
|
||||||
|
}
|
||||||
|
|
||||||
private void Start(Server server)
|
private void Start(Server server)
|
||||||
{
|
{
|
||||||
ServerProcessService.StartServer(server);
|
ServerProcessService.StartServer(server);
|
||||||
|
|
42
LANCommander/Pages/Servers/Logs.razor
Normal file
42
LANCommander/Pages/Servers/Logs.razor
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
@page "/Servers/{id:guid}/Logs"
|
||||||
|
@using Microsoft.AspNetCore.SignalR.Client
|
||||||
|
@attribute [Authorize]
|
||||||
|
@inject ServerService ServerService
|
||||||
|
@inject ServerProcessService ServerProcessService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@implements IAsyncDisposable
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@foreach (var message in Messages)
|
||||||
|
{
|
||||||
|
@message <br />
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter] public Guid Id { get; set; }
|
||||||
|
|
||||||
|
HubConnection? HubConnection;
|
||||||
|
List<string> Messages = new List<string>();
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
HubConnection = new HubConnectionBuilder()
|
||||||
|
.WithUrl(NavigationManager.ToAbsoluteUri("/hubs/logging"))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
HubConnection.On<string>("Log", (message) =>
|
||||||
|
{
|
||||||
|
Messages.Add(message);
|
||||||
|
InvokeAsync(StateHasChanged);
|
||||||
|
});
|
||||||
|
|
||||||
|
await HubConnection.StartAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (HubConnection is not null)
|
||||||
|
await HubConnection.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
using BeaconLib;
|
using BeaconLib;
|
||||||
using LANCommander.Data;
|
using LANCommander.Data;
|
||||||
using LANCommander.Data.Models;
|
using LANCommander.Data.Models;
|
||||||
|
using LANCommander.Hubs;
|
||||||
using LANCommander.Services;
|
using LANCommander.Services;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using NLog.Web;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
@ -114,6 +116,8 @@ builder.WebHost.UseKestrel(options =>
|
||||||
options.Limits.MaxRequestBodySize = 1024 * 1024 * 150;
|
options.Limits.MaxRequestBodySize = 1024 * 1024 * 150;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Host.UseNLog();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
@ -140,6 +144,8 @@ app.UseAuthorization();
|
||||||
|
|
||||||
app.UseMvcWithDefaultRoute();
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
|
app.MapHub<LoggingHub>("/hubs/logging");
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapBlazorHub();
|
endpoints.MapBlazorHub();
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
using LANCommander.Data.Models;
|
using LANCommander.Data.Models;
|
||||||
|
using NLog;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace LANCommander.Services
|
namespace LANCommander.Services
|
||||||
{
|
{
|
||||||
public class ServerProcessService
|
public class ServerProcessService
|
||||||
{
|
{
|
||||||
|
private readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public Dictionary<Guid, Process> Processes = new Dictionary<Guid, Process>();
|
public Dictionary<Guid, Process> Processes = new Dictionary<Guid, Process>();
|
||||||
public Dictionary<Guid, int> Threads { get; set; } = new Dictionary<Guid, int>();
|
public Dictionary<Guid, int> Threads { get; set; } = new Dictionary<Guid, int>();
|
||||||
|
|
||||||
|
@ -15,19 +18,40 @@ namespace LANCommander.Services
|
||||||
process.StartInfo.FileName = server.Path;
|
process.StartInfo.FileName = server.Path;
|
||||||
process.StartInfo.WorkingDirectory = server.WorkingDirectory;
|
process.StartInfo.WorkingDirectory = server.WorkingDirectory;
|
||||||
process.StartInfo.Arguments = server.Arguments;
|
process.StartInfo.Arguments = server.Arguments;
|
||||||
process.StartInfo.UseShellExecute = true;
|
process.StartInfo.UseShellExecute = false;
|
||||||
|
process.StartInfo.RedirectStandardOutput = true;
|
||||||
|
process.StartInfo.RedirectStandardError = true;
|
||||||
|
process.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
|
||||||
|
{
|
||||||
|
Logger.Info("Game Server {ServerName} ({ServerId}) Info: {Message}", server.Name, server.Id, e.Data);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
|
||||||
|
{
|
||||||
|
Logger.Error("Game Server {ServerName} ({ServerId}) Error: {Message}", server.Name, server.Id, e.Data);
|
||||||
|
});
|
||||||
|
|
||||||
process.Start();
|
process.Start();
|
||||||
|
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
process.BeginOutputReadLine();
|
||||||
|
|
||||||
Processes[server.Id] = process;
|
Processes[server.Id] = process;
|
||||||
|
|
||||||
await process.WaitForExitAsync();
|
await process.WaitForExitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void StopServer(Server server)
|
public void StopServer(Server server)
|
||||||
{
|
{
|
||||||
if (Processes.ContainsKey(server.Id))
|
if (Processes.ContainsKey(server.Id))
|
||||||
Processes[server.Id].Kill();
|
{
|
||||||
|
var process = Processes[server.Id];
|
||||||
|
|
||||||
|
process.Kill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
LANCommander/nlog.config
Normal file
33
LANCommander/nlog.config
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
autoReload="true"
|
||||||
|
internalLogFile="internal.log"
|
||||||
|
internalLogLevel="Info">
|
||||||
|
|
||||||
|
<!-- enable asp.net core layout renderers -->
|
||||||
|
<extensions>
|
||||||
|
<add assembly="NLog.Web.AspNetCore"/>
|
||||||
|
<add assembly="LANCommander"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<!-- the targets to write to -->
|
||||||
|
<targets>
|
||||||
|
<!-- File Target for all log messages with basic details -->
|
||||||
|
<target xsi:type="File" name="MainLogFile" fileName="${basedir}/Logs/log.txt" archiveEvery="Day" />
|
||||||
|
<target xsi:type="File" name="GameServerLogFile" fileName="${basedir}/Logs/GameServers/${event-properties:ServerName}.log" archiveEvery="Day" />
|
||||||
|
<target xsi:type="LoggingHub" name="GameServerHub" hubUrl="http://localhost:1337/hubs/logging" />
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<!-- rules to map from logger name to target -->
|
||||||
|
<rules>
|
||||||
|
<!--All logs, including from Microsoft-->
|
||||||
|
<logger name="*" minlevel="Trace" writeTo="MainLogFile,LoggingHub" />
|
||||||
|
<logger name="LANCommander.Services.ServerProcessService" minlevel="Info" writeTo="GameServerLogFile,GameServerHub" />
|
||||||
|
<!--Skip non-critical Microsoft logs and so log only own logs (BlackHole) -->
|
||||||
|
<!--<logger name="Microsoft.*" maxlevel="Info" final="true" />
|
||||||
|
<logger name="System.Net.Http.*" maxlevel="Info" final="true" />
|
||||||
|
|
||||||
|
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />-->
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
Loading…
Add table
Reference in a new issue