LANCommander/LANCommander.Server/UI/Pages/Servers/Edit/General.razor
2025-05-23 02:17:45 -05:00

214 lines
No EOL
8.3 KiB
Text

@page "/Servers/Add"
@page "/Servers/{id:guid}"
@page "/Servers/{id:guid}/General"
@attribute [Authorize(Roles = RoleService.AdministratorRoleName)]
@using System.Runtime.InteropServices
@using Docker.DotNet.Models
@using LANCommander.SDK.Enums
@using LANCommander.Server.Data.Enums
@using LANCommander.Server.Services.Abstractions
@using LANCommander.Server.Services.ServerEngines
@using LANCommander.Server.UI.Pages.Servers.Components
@inject ServerService ServerService
@inject GameService GameService
@inject DockerServerEngine DockerServerEngine
@inject NavigationManager NavigationManager
@inject IMessageService MessageService
@inject ILogger<General> Logger
<ServerEditView Id="Id">
<TitleTemplate>
@if (context.Id == Guid.Empty)
{
<Text>Add New Server</Text>
}
else
{
<Text>General</Text>
}
</TitleTemplate>
<TitleExtraTemplate>
@if (context != null && context.Id != Guid.Empty)
{
<Flex Align="FlexAlign.Center" Justify="FlexJustify.End" Wrap="FlexWrap.NoWrap" Gap="FlexGap.Small">
<ServerControl ServerId="context.Id" />
<Dropdown Trigger="@(new Trigger[] { Trigger.Click })">
<Overlay>
<Menu>
<MenuItem>
<a href="/Server/@(context.Id)/Export/Full" target="_blank">Full</a>
</MenuItem>
</Menu>
</Overlay>
<ChildContent>
<Button>Export</Button>
</ChildContent>
</Dropdown>
</Flex>
}
</TitleExtraTemplate>
<ChildContent>
<Form Model="@context" Layout="@FormLayout.Vertical" Context="formContext">
<FormItem Label="Name">
<Input @bind-Value="@context.Name" AutoFocus="context.Id == Guid.Empty" />
</FormItem>
<FormItem Label="Game">
<Select TItem="Game"
TItemValue="Guid?"
DataSource="@Games.OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle)"
@bind-Value="@context.GameId"
LabelName="Title"
ValueName="Id"
Placeholder="Select a Game"
DefaultActiveFirstOption="false"
EnableSearch>
<ItemTemplate Context="game">
@game.Title
</ItemTemplate>
</Select>
</FormItem>
<FormItem Label="Engine">
<EnumSelect TEnum="ServerEngine" @bind-Value="context.Engine" />
</FormItem>
@if (context.Engine == ServerEngine.Docker)
{
<FormItem Label="Docker Host">
<Select
TItem="ServerEngineConfiguration"
TItemValue="Guid?"
DataSource="Settings.Servers.ServerEngines"
LabelName="Name"
ValueName="Id"
@bind-Value="context.DockerHostId"
OnSelectedItemChanged="ChangeDockerHost"></Select>
</FormItem>
<FormItem Label="Container">
<Select
TItem="DockerContainer"
TItemValue="string"
DataSource="Containers"
Disabled="!Containers.Any()"
LabelName="Name"
ValueName="Id"
@bind-Value="context.ContainerId"></Select>
</FormItem>
}
<FormItem Label="Executable Path">
<FilePicker Root="@RootPath" EntrySelectable="x => x is FileManagerFile" @bind-Value="@context.Path" OnSelected="(path) => context.WorkingDirectory = Path.GetDirectoryName(path)" />
</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)">
<ServerPortInput @bind-Value="@context.Port" @bind-PortInUse="PortInUse" ServerId="context.Id" />
</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(context)" Icon="@IconType.Fill.Save">Save</Button>
</FormItem>
</Form>
</ChildContent>
</ServerEditView>
@code {
[Parameter] public Guid Id { get; set; }
IEnumerable<Game> Games = new List<Game>();
IEnumerable<DockerContainer> Containers = new List<DockerContainer>();
Settings Settings = SettingService.GetSettings();
Guid GameId;
string RootPath = Path.GetPathRoot(Directory.GetCurrentDirectory());
bool PortInUse = false;
IEnumerable<ProcessTerminationMethod> AllowedProcessTerminationMethods
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return new ProcessTerminationMethod[]
{
ProcessTerminationMethod.SIGHUP,
ProcessTerminationMethod.SIGINT,
ProcessTerminationMethod.SIGKILL,
ProcessTerminationMethod.SIGTERM
};
else
return new ProcessTerminationMethod[]
{
ProcessTerminationMethod.Close,
ProcessTerminationMethod.Kill
};
}
}
protected override async Task OnInitializedAsync()
{
Games = await GameService.Include(g => g.Media).GetAsync();
}
async Task ChangeDockerHost(ServerEngineConfiguration hostConfiguration)
{
Containers = await DockerServerEngine.GetContainersAsync(hostConfiguration.Id);
}
async Task Save(Server server)
{
try
{
if (server.Id != Guid.Empty)
{
server = await ServerService.UpdateAsync(server);
await MessageService.SuccessAsync("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!");
}
}
void NotifyServerAdded(object? sender, LocationChangedEventArgs e)
{
NavigationManager.LocationChanged -= NotifyServerAdded;
MessageService.Success("Server added!");
}
}