feat(panel): basic server control panel page

This commit is contained in:
CyberL1 2024-05-29 21:19:32 +02:00
parent 6ff9faf741
commit 51251ee5a1
5 changed files with 149 additions and 0 deletions

View File

@ -57,5 +57,29 @@ namespace Minecraft_Realms_Emulator.Controllers.Admin
return new EmptyResult(); return new EmptyResult();
} }
[HttpPut("{wId}/open")]
public ActionResult<bool> OpenServer(int wId)
{
var world = _context.Worlds.ToList().Find(w => w.Id == wId);
if (world == null) return BadRequest("World not found");
new DockerHelper(world).StartServer();
return Ok(true);
}
[HttpPut("{wId}/close")]
public ActionResult<bool> CloseServer(int wId)
{
var world = _context.Worlds.ToList().Find(w => w.Id == wId);
if (world == null) return BadRequest("World not found");
new DockerHelper(world).StopServer();
return Ok(true);
}
} }
} }

View File

@ -15,6 +15,7 @@
<body> <body>
<Routes /> <Routes />
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
<script src="js/serverLogsStream.js"></script>
</body> </body>
</html> </html>

View File

@ -0,0 +1,88 @@
@page "/servers/{wId:int}"
@inject IJSRuntime JS
@rendermode InteractiveServer
<PageTitle>Server #@wId</PageTitle>
@if (server == null)
{
<p><em>Loading...</em></p>
}
else
{
<div class="panel">
<div class="header">
<div class="status">
@server.Name
@server.State
</div>
<div class="buttons">
<button class="btn btn-success" @onclick="StartServer">
<i class="bi-caret-right-fill"></i>
Start
</button>
<button class="btn btn-danger" @onclick="StopServer">
<i class="bi-stop-circle-fill"></i>
Stop
</button>
</div>
</div>
<div class="console">
<pre class="output">
@foreach (var log in logs)
{
@log<br />
}
</pre>
</div>
</div>
}
@code {
[Parameter]
public int wId { get; set; }
private World? server;
private List<string> logs = [];
protected override async Task OnInitializedAsync()
{
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(Environment.GetEnvironmentVariable("ADMIN_KEY"));
server = await httpClient.GetFromJsonAsync<World>($"http://localhost:8080/api/admin/servers/{wId}");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("serverLogsStream.start", DotNetObjectReference.Create(this), wId);
}
}
[JSInvokable]
public Task ReceiveLog(string log)
{
logs.Add(log);
InvokeAsync(StateHasChanged);
return Task.CompletedTask;
}
public async Task StartServer()
{
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(Environment.GetEnvironmentVariable("ADMIN_KEY"));
await httpClient.PutAsync($"http://localhost:8080/api/admin/servers/{wId}/open", new StringContent(""));
}
public async Task StopServer()
{
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(Environment.GetEnvironmentVariable("ADMIN_KEY"));
await httpClient.PutAsync($"http://localhost:8080/api/admin/servers/{wId}/close", new StringContent(""));
}
}

View File

@ -1,3 +1,5 @@
@import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css");
html, body { html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
} }
@ -56,4 +58,29 @@ h1:focus {
.table.clickable tbody tr:hover { .table.clickable tbody tr:hover {
background-color: #e8e8e8; background-color: #e8e8e8;
}
.panel {
display: flex;
flex-direction: column;
}
.panel .header {
display: flex;
}
.panel .header .status {
flex-grow: 1;
}
.panel .header .buttons {}
.panel .console {
background-color: #000000;
color: #ffffff;
width: 80%;
margin: auto;
height: 800px;
overflow: auto;
padding: 5px;
} }

View File

@ -0,0 +1,9 @@
window.serverLogsStream = {
start: (dotNetObject, serverId) => {
const logs = new EventSource(`http://localhost:8080/api/admin/servers/${serverId}/logs`, { withCredentials: true });
logs.onmessage = event => {
dotNetObject.invokeMethodAsync("ReceiveLog", event.data);
}
}
}