255 lines
8.7 KiB
C#
255 lines
8.7 KiB
C#
using System.Text.Json;
|
|
using MoonlightServers.Api.Infrastructure.Database;
|
|
using MoonlightServers.Api.Infrastructure.Database.Entities;
|
|
using MoonlightServers.Api.Infrastructure.Database.Json;
|
|
|
|
namespace MoonlightServers.Api.Admin.Templates;
|
|
|
|
public class PterodactylEggImportService
|
|
{
|
|
private readonly DatabaseRepository<Template> TemplateRepository;
|
|
private readonly DatabaseRepository<TemplateDockerImage> DockerImageRepository;
|
|
|
|
public PterodactylEggImportService(
|
|
DatabaseRepository<Template> templateRepository,
|
|
DatabaseRepository<TemplateDockerImage> dockerImageRepository
|
|
)
|
|
{
|
|
TemplateRepository = templateRepository;
|
|
DockerImageRepository = dockerImageRepository;
|
|
}
|
|
|
|
public async Task<Template> ImportAsync(string json)
|
|
{
|
|
using var doc = JsonDocument.Parse(json);
|
|
var root = doc.RootElement;
|
|
|
|
var template = new Template
|
|
{
|
|
Name = Truncate(root.GetStringOrDefault("name") ?? "Unknown", 30),
|
|
Description = Truncate(root.GetStringOrDefault("description") ?? "", 255),
|
|
Author = Truncate(root.GetStringOrDefault("author") ?? "", 30),
|
|
Version = "1.0.0",
|
|
UpdateUrl = root.TryGetProperty("meta", out var meta)
|
|
? meta.GetStringOrDefault("update_url")
|
|
: null,
|
|
DonateUrl = null,
|
|
|
|
FilesConfig = ParseFilesConfig(root),
|
|
LifecycleConfig = ParseLifecycleConfig(root),
|
|
InstallationConfig = ParseInstallationConfig(root),
|
|
MiscellaneousConfig = new MiscellaneousConfig { UseLegacyStartup = true },
|
|
|
|
AllowUserDockerImageChange = true,
|
|
Variables = ParseVariables(root)
|
|
};
|
|
|
|
var finalTemplate = await TemplateRepository.AddAsync(template);
|
|
|
|
var dockerImages = ParseDockerImageModels(root);
|
|
TemplateDockerImage? defaultDockerImage = null;
|
|
|
|
var isFirst = true;
|
|
|
|
foreach (var (displayName, imageName) in dockerImages)
|
|
{
|
|
var entity = new TemplateDockerImage
|
|
{
|
|
DisplayName = displayName,
|
|
ImageName = imageName,
|
|
SkipPulling = false,
|
|
Template = finalTemplate
|
|
};
|
|
|
|
var finalEntity = await DockerImageRepository.AddAsync(entity);
|
|
|
|
if (isFirst)
|
|
{
|
|
isFirst = false;
|
|
defaultDockerImage = finalEntity;
|
|
}
|
|
}
|
|
|
|
finalTemplate.DefaultDockerImage = defaultDockerImage;
|
|
await TemplateRepository.UpdateAsync(finalTemplate);
|
|
|
|
return finalTemplate;
|
|
}
|
|
|
|
private static FilesConfig ParseFilesConfig(JsonElement root)
|
|
{
|
|
var configFiles = new List<ConfigurationFile>();
|
|
|
|
if (!root.TryGetProperty("config", out var config))
|
|
return new FilesConfig { ConfigurationFiles = configFiles };
|
|
|
|
if (!config.TryGetProperty("files", out var filesElement))
|
|
return new FilesConfig { ConfigurationFiles = configFiles };
|
|
|
|
var filesJson = filesElement.ValueKind == JsonValueKind.String
|
|
? filesElement.GetString()
|
|
: filesElement.GetRawText();
|
|
|
|
if (string.IsNullOrWhiteSpace(filesJson) || filesJson == "{}" || filesJson == "[]")
|
|
return new FilesConfig { ConfigurationFiles = configFiles };
|
|
|
|
try
|
|
{
|
|
using var filesDoc = JsonDocument.Parse(filesJson);
|
|
|
|
foreach (var fileProperty in filesDoc.RootElement.EnumerateObject())
|
|
{
|
|
var parser = fileProperty.Value.GetStringOrDefault("parser") ?? "json";
|
|
var mappings = new List<ConfigurationFileMapping>();
|
|
|
|
if (fileProperty.Value.TryGetProperty("find", out var find))
|
|
{
|
|
foreach (var mapping in find.EnumerateObject())
|
|
{
|
|
mappings.Add(new ConfigurationFileMapping
|
|
{
|
|
Key = mapping.Name,
|
|
Value = mapping.Value.ValueKind == JsonValueKind.String
|
|
? mapping.Value.GetString() ?? ""
|
|
: mapping.Value.GetRawText()
|
|
});
|
|
}
|
|
}
|
|
|
|
configFiles.Add(new ConfigurationFile
|
|
{
|
|
Path = fileProperty.Name,
|
|
Parser = parser,
|
|
Mappings = mappings
|
|
});
|
|
}
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
}
|
|
|
|
return new FilesConfig { ConfigurationFiles = configFiles };
|
|
}
|
|
|
|
private static LifecycleConfig ParseLifecycleConfig(JsonElement root)
|
|
{
|
|
var stopCommand = "";
|
|
var onlinePatterns = new List<string>();
|
|
|
|
if (root.TryGetProperty("config", out var config))
|
|
{
|
|
stopCommand = config.GetStringOrDefault("stop") ?? "";
|
|
|
|
if (config.TryGetProperty("startup", out var startupElement))
|
|
{
|
|
var startupJson = startupElement.ValueKind == JsonValueKind.String
|
|
? startupElement.GetString()
|
|
: startupElement.GetRawText();
|
|
|
|
if (!string.IsNullOrWhiteSpace(startupJson))
|
|
{
|
|
try
|
|
{
|
|
using var startupDoc = JsonDocument.Parse(startupJson);
|
|
|
|
if (startupDoc.RootElement.TryGetProperty("done", out var done))
|
|
{
|
|
var doneValue = done.ValueKind == JsonValueKind.String
|
|
? done.GetString()
|
|
: done.GetRawText();
|
|
|
|
if (!string.IsNullOrWhiteSpace(doneValue))
|
|
onlinePatterns.Add(doneValue);
|
|
}
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new LifecycleConfig
|
|
{
|
|
StartupCommands =
|
|
[
|
|
new StartupCommand
|
|
{
|
|
DisplayName = "Startup",
|
|
Command = root.GetStringOrDefault("startup") ?? ""
|
|
}
|
|
],
|
|
StopCommand = stopCommand,
|
|
OnlineLogPatterns = onlinePatterns
|
|
};
|
|
}
|
|
|
|
private static InstallationConfig ParseInstallationConfig(JsonElement root)
|
|
{
|
|
if (!root.TryGetProperty("scripts", out var scripts))
|
|
return new InstallationConfig();
|
|
|
|
if (!scripts.TryGetProperty("installation", out var installation))
|
|
return new InstallationConfig();
|
|
|
|
return new InstallationConfig
|
|
{
|
|
DockerImage = installation.GetStringOrDefault("container") ?? "",
|
|
Shell = installation.GetStringOrDefault("entrypoint") ?? "bash",
|
|
Script = installation.GetStringOrDefault("script") ?? ""
|
|
};
|
|
}
|
|
|
|
// Returns (DisplayName, ImageName, IsFirst) tuples to avoid a temporary model
|
|
private static List<(string DisplayName, string ImageName)> ParseDockerImageModels(JsonElement root)
|
|
{
|
|
var result = new List<(string, string)>();
|
|
|
|
if (!root.TryGetProperty("docker_images", out var dockerImages))
|
|
return result;
|
|
|
|
foreach (var img in dockerImages.EnumerateObject())
|
|
{
|
|
result.Add((
|
|
Truncate(img.Name, 30),
|
|
Truncate(img.Value.GetString() ?? img.Name, 255)
|
|
));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static List<TemplateVariable> ParseVariables(JsonElement root)
|
|
{
|
|
var variables = new List<TemplateVariable>();
|
|
|
|
if (!root.TryGetProperty("variables", out var vars))
|
|
return variables;
|
|
|
|
foreach (var v in vars.EnumerateArray())
|
|
{
|
|
variables.Add(new TemplateVariable
|
|
{
|
|
DisplayName = Truncate(v.GetStringOrDefault("name") ?? "Variable", 30),
|
|
Description = Truncate(v.GetStringOrDefault("description") ?? "", 255),
|
|
EnvName = Truncate(v.GetStringOrDefault("env_variable") ?? "", 60),
|
|
DefaultValue = Truncate(v.GetStringOrDefault("default_value") ?? "", 1024)
|
|
});
|
|
}
|
|
|
|
return variables;
|
|
}
|
|
|
|
private static string Truncate(string value, int maxLength) =>
|
|
value.Length <= maxLength ? value : value[..maxLength];
|
|
}
|
|
|
|
internal static class JsonElementExtensions
|
|
{
|
|
public static string? GetStringOrDefault(this JsonElement element, string propertyName)
|
|
{
|
|
return element.TryGetProperty(propertyName, out var prop) && prop.ValueKind == JsonValueKind.String
|
|
? prop.GetString()
|
|
: null;
|
|
}
|
|
} |