340 lines
No EOL
14 KiB
Text
340 lines
No EOL
14 KiB
Text
@page "/Servers/{id:guid}"
|
|
@page "/Servers/{id:guid}/{panel}"
|
|
@page "/Servers/{id:guid}/{panel}/{logId}"
|
|
@page "/Servers/Add"
|
|
@attribute [Authorize(Roles = RoleService.AdministratorRoleName)]
|
|
@using LANCommander.SDK.Enums
|
|
@using LANCommander.Server.UI.Pages.Servers.Components
|
|
@using LANCommander.Server.Extensions
|
|
@using Microsoft.EntityFrameworkCore
|
|
@using System.Runtime.InteropServices
|
|
@inject ServerProcessService ServerProcessService
|
|
@inject DatabaseServiceFactory DatabaseServiceFactory
|
|
@inject IMessageService MessageService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ILogger<Edit> Logger
|
|
|
|
<Layout Class="panel-layout" Style="padding: 24px 0;">
|
|
<Sider Width="200">
|
|
<Menu Mode="@MenuMode.Inline" Style="height: 100%;">
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/General")">General</MenuItem>
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/Actions")">Actions</MenuItem>
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/Autostart")">Autostart</MenuItem>
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/HTTP")">HTTP</MenuItem>
|
|
@if (Server != null && Server.Id != Guid.Empty)
|
|
{
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/Consoles")">Consoles</MenuItem>
|
|
<SubMenu Key="Monitor" Title="Monitor" Disabled="@(Server.ServerConsoles == null || Server.ServerConsoles.Count == 0)">
|
|
@if (!Server.UseShellExecute)
|
|
{
|
|
<MenuItem Key="Console" RouterLink="@($"/Servers/{Server.Id}/Monitor/Console")">Console</MenuItem>
|
|
}
|
|
|
|
@if (Server.ServerConsoles != null && Server.ServerConsoles.Any(c => c.Id != Guid.Empty))
|
|
{
|
|
foreach (var log in Server.ServerConsoles.Where(c => c.Id != Guid.Empty))
|
|
{
|
|
<MenuItem Key="@log.Id.ToString()" RouterLink="@($"/Servers/{Server.Id}/Monitor/{log.Id}")">@log.Name</MenuItem>
|
|
}
|
|
}
|
|
</SubMenu>
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/Scripts")">Scripts</MenuItem>
|
|
<MenuItem RouterLink="@($"/Servers/{Server.Id}/Files")">Files</MenuItem>
|
|
}
|
|
</Menu>
|
|
</Sider>
|
|
|
|
<Content>
|
|
<PageHeader>
|
|
<PageHeaderTitle>@Panel</PageHeaderTitle>
|
|
<PageHeaderExtra>
|
|
@if (Server.Id != Guid.Empty)
|
|
{
|
|
<ServerControl ServerId="Id" />
|
|
<Space Direction="DirectionVHType.Horizontal">
|
|
<SpaceItem>
|
|
<Dropdown Trigger="@(new Trigger[] { Trigger.Click })">
|
|
<Overlay>
|
|
<Menu>
|
|
<MenuItem>
|
|
<a href="/Server/@(Id)/Export/Full" target="_blank">Full</a>
|
|
</MenuItem>
|
|
</Menu>
|
|
</Overlay>
|
|
<ChildContent>
|
|
<Button>Export</Button>
|
|
</ChildContent>
|
|
</Dropdown>
|
|
</SpaceItem>
|
|
</Space>
|
|
}
|
|
</PageHeaderExtra>
|
|
</PageHeader>
|
|
|
|
|
|
<div class="panel-layout-content">
|
|
@if (Panel == "General" || String.IsNullOrWhiteSpace(Panel))
|
|
{
|
|
<Form Model="@Server" Layout="@FormLayout.Vertical">
|
|
<FormItem Label="Name">
|
|
<Input @bind-Value="@context.Name" />
|
|
</FormItem>
|
|
<FormItem Label="Game">
|
|
<Select TItem="Game"
|
|
TItemValue="Guid"
|
|
DataSource="@Games.OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle)"
|
|
@bind-Value="@GameId"
|
|
LabelName="Title"
|
|
ValueName="Id"
|
|
Placeholder="Select a Game"
|
|
DefaultActiveFirstOption="false"
|
|
EnableSearch>
|
|
<ItemTemplate Context="game">
|
|
@game.Title
|
|
</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
<FormItem Label="Executable Path">
|
|
<FilePicker Root="@RootPath" EntrySelectable="x => x is FileManagerFile" @bind-Value="@context.Path" OnSelected="OnPathSelected" />
|
|
</FormItem>
|
|
<FormItem Label="Arguments">
|
|
<Input @bind-Value="@context.Arguments" />
|
|
</FormItem>
|
|
<FormItem Label="Working Directory">
|
|
<FilePicker Root="@RootPath" Title="Choose Working Directory" OkText="Select Directory" EntrySelectable="x => x is FileManagerDirectory" @bind-Value="@context.WorkingDirectory" />
|
|
</FormItem>
|
|
<FormItem Label="Host">
|
|
<Input @bind-Value="@context.Host" />
|
|
</FormItem>
|
|
<FormItem Label="Port" HasFeedback="@PortInUse" Help="@(PortInUse ? "Another server may already be bound to this port" : "")" ValidateStatus="@(PortInUse ? FormValidateStatus.Warning : FormValidateStatus.Default)">
|
|
<AntDesign.InputNumber @bind-Value="@context.Port" TValue="int" OnChange="OnPortNumberChanged" Min="0" Max="65535" />
|
|
</FormItem>
|
|
<FormItem>
|
|
<LabelTemplate>
|
|
Use Shell Execute
|
|
<Tooltip Title="This option specifies whether you would like to run the server using the shell. Some servers may require this as they will have a UI or won't output logs to stdout">
|
|
<Icon Type="@IconType.Outline.QuestionCircle" Theme="@IconThemeType.Outline" />
|
|
</Tooltip>
|
|
</LabelTemplate>
|
|
<ChildContent>
|
|
<Switch @bind-Checked="context.UseShellExecute" />
|
|
</ChildContent>
|
|
</FormItem>
|
|
<FormItem Label="Termination Method">
|
|
<Select @bind-Value="context.ProcessTerminationMethod" TItem="ProcessTerminationMethod" TItemValue="ProcessTerminationMethod" DataSource="AllowedProcessTerminationMethods" />
|
|
</FormItem>
|
|
<FormItem>
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
</FormItem>
|
|
</Form>
|
|
}
|
|
|
|
@if (Panel == "Actions")
|
|
{
|
|
<ActionEditor @bind-Actions="Server.Actions" ServerId="Server.Id" ArchiveId="Server.Game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Id" />
|
|
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
}
|
|
|
|
@if (Panel == "Autostart")
|
|
{
|
|
<Form Model="@Server" Layout="@FormLayout.Vertical">
|
|
<FormItem Label="Enable">
|
|
<Switch @bind-Checked="context.Autostart" />
|
|
</FormItem>
|
|
|
|
<FormItem Label="Method">
|
|
<Select @bind-Value="context.AutostartMethod" TItem="ServerAutostartMethod" TItemValue="ServerAutostartMethod" DataSource="Enum.GetValues<ServerAutostartMethod>()">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
|
|
<FormItem Label="Delay">
|
|
<AntDesign.Input @bind-Value="context.AutostartDelay" Placeholder="0">
|
|
<Suffix>Seconds</Suffix>
|
|
</AntDesign.Input>
|
|
</FormItem>
|
|
|
|
<FormItem>
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
</FormItem>
|
|
</Form>
|
|
}
|
|
|
|
@if (Panel == "HTTP")
|
|
{
|
|
<Text>HTTP paths are a way to host static files such as maps and other assets. Engines such as Source, id Tech 3, and Unreal can utilize HTTP for faster downloads when connecting to a server.</Text>
|
|
<ServerHttpPathEditor @bind-Values="Server.HttpPaths" ServerId="Id" WorkingDirectory="@Server.WorkingDirectory" />
|
|
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
}
|
|
|
|
@if (Panel == "Consoles")
|
|
{
|
|
<ServerConsoleEditor @bind-Value="Server.ServerConsoles" ServerId="Id" />
|
|
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
}
|
|
|
|
@if (Panel == "Monitor")
|
|
{
|
|
@if (LogId == "Console") {
|
|
<Console ServerId="@Server.Id" />
|
|
}
|
|
else if (LogId != null && LogId != Guid.Empty.ToString())
|
|
{
|
|
<Console ServerId="@Server.Id" ServerConsoleId="@Guid.Parse(LogId)" />
|
|
}
|
|
else
|
|
{
|
|
<ServerConsoleEditor @bind-Value="Server.ServerConsoles" ServerId="Id" />
|
|
|
|
<Button Type="@ButtonType.Primary" OnClick="Save" Icon="@IconType.Fill.Save">Save</Button>
|
|
}
|
|
}
|
|
|
|
@if (Panel == "Scripts")
|
|
{
|
|
<ScriptEditor ServerId="@Server.Id" AllowedTypes="new ScriptType[] { ScriptType.BeforeStart, ScriptType.AfterStop }" />
|
|
}
|
|
|
|
@if (Panel == "Files")
|
|
{
|
|
<TextEditor WorkingDirectory="@Server.WorkingDirectory" />
|
|
}
|
|
</div>
|
|
</Content>
|
|
</Layout>
|
|
|
|
@code {
|
|
[Parameter] public Guid Id { get; set; }
|
|
[Parameter] public string Panel { get; set; }
|
|
[Parameter] public string LogId { get; set; }
|
|
|
|
IEnumerable<Game> Games = new List<Game>();
|
|
|
|
string RootPath = Path.GetPathRoot(Directory.GetCurrentDirectory());
|
|
|
|
bool PortInUse = false;
|
|
|
|
Server Server = new Server();
|
|
Guid GameId;
|
|
|
|
IEnumerable<ProcessTerminationMethod> AllowedProcessTerminationMethods
|
|
{
|
|
get
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
return new ProcessTerminationMethod[]
|
|
{
|
|
ProcessTerminationMethod.SIGHUP,
|
|
ProcessTerminationMethod.SIGINT,
|
|
ProcessTerminationMethod.SIGKILL,
|
|
ProcessTerminationMethod.SIGTERM
|
|
};
|
|
else
|
|
return new ProcessTerminationMethod[]
|
|
{
|
|
ProcessTerminationMethod.Close,
|
|
ProcessTerminationMethod.Kill
|
|
};
|
|
}
|
|
}
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
using (var serverService = DatabaseServiceFactory.Create<ServerService>())
|
|
{
|
|
if (Id != Guid.Empty && Panel == null)
|
|
NavigationManager.NavigateTo($"/Servers/{Id}/General", true);
|
|
else if (Id != Guid.Empty)
|
|
Server = await serverService.GetAsync(Id);
|
|
}
|
|
|
|
if (Server.GameId.HasValue)
|
|
GameId = Server.GameId.Value;
|
|
|
|
if (Server.HttpPaths == null)
|
|
Server.HttpPaths = new List<ServerHttpPath>();
|
|
|
|
using (var gameService = DatabaseServiceFactory.Create<GameService>())
|
|
{
|
|
Games = await gameService.Include(g => g.Media).GetAsync();
|
|
}
|
|
|
|
await OnPortNumberChanged(Server.Port);
|
|
}
|
|
|
|
async Task Save()
|
|
{
|
|
try
|
|
{
|
|
Server.GameId = GameId;
|
|
|
|
using (var serverService = DatabaseServiceFactory.Create<ServerService>())
|
|
{
|
|
if (Server.Id != Guid.Empty)
|
|
{
|
|
Server = await serverService.UpdateAsync(Server);
|
|
|
|
await MessageService.Success("Server updated!");
|
|
}
|
|
else
|
|
{
|
|
Server = await serverService.AddAsync(Server);
|
|
|
|
NavigationManager.LocationChanged += NotifyServerAdded;
|
|
|
|
NavigationManager.NavigateTo($"/Servers/{Server.Id}");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not save!");
|
|
Logger.LogError(ex, "Could not save!");
|
|
}
|
|
}
|
|
|
|
async Task AddPath()
|
|
{
|
|
Server.HttpPaths.Add(new ServerHttpPath()
|
|
{
|
|
ServerId = Server.Id
|
|
});
|
|
}
|
|
|
|
void OnPathSelected(string path)
|
|
{
|
|
Server.WorkingDirectory = Path.GetDirectoryName(path);
|
|
}
|
|
|
|
void NotifyServerAdded(object? sender, LocationChangedEventArgs e)
|
|
{
|
|
NavigationManager.LocationChanged -= NotifyServerAdded;
|
|
|
|
MessageService.Success("Server added!");
|
|
}
|
|
|
|
string GetIcon(Game game)
|
|
{
|
|
var media = game?.Media?.FirstOrDefault(m => m.Type == SDK.Enums.MediaType.Icon);
|
|
|
|
if (media != null)
|
|
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
|
|
else
|
|
return "/favicon.ico";
|
|
}
|
|
|
|
async Task OnPortNumberChanged(int value)
|
|
{
|
|
if (value > 0)
|
|
{
|
|
using (var serverService = DatabaseServiceFactory.Create<ServerService>())
|
|
{
|
|
PortInUse = await serverService.ExistsAsync(s => s.Port == value && s.Id != Id);
|
|
}
|
|
}
|
|
}
|
|
} |