using LANCommander.SDK; using LANCommander.SDK.Helpers; using LANCommander.SDK.Migrations; using Semver; namespace LANCommander.Server.Migrations; /// /// Moves the settings-based storage directories (Update, Launcher, Backups, Snippets, Modules) from /// their previously-written raw locations (resolved verbatim relative to the working directory) to the /// unified location produced by . /// This aligns runtime writes with the same resolution rule used everywhere else so relative paths land /// under the config directory instead of next to the binary. /// public class AlignSettingsStoragePathsMigration( SettingsProvider settingsProvider, ILogger logger) : FileSystemMigration(logger) { public override SemVersion Version => new(2, 1, 0); private IEnumerable GetConfiguredPaths() { var settings = settingsProvider.CurrentValue; yield return settings.Server.Update.StoragePath; yield return settings.Server.Launcher.StoragePath; yield return settings.Server.Backups.StoragePath; yield return settings.Server.Scripts.Snippets.StoragePath; yield return settings.Server.Scripts.Modules.StoragePath; } private static (string Source, string Destination)? GetMove(string configuredPath) { if (string.IsNullOrWhiteSpace(configuredPath)) return null; // Rooted paths already resolve verbatim, so there is nothing to move. if (Path.IsPathRooted(configuredPath)) return null; var source = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), configuredPath)); var destination = AppPaths.ResolveStorageLocationPath(configuredPath); if (string.Equals(source, destination, StringComparison.Ordinal)) return null; return (source, destination); } public override async Task ExecuteAsync() { foreach (var configuredPath in GetConfiguredPaths()) { var move = GetMove(configuredPath); if (move == null) continue; var (source, destination) = move.Value; try { if (!Directory.Exists(source)) continue; Logger.LogInformation("Moving storage directory from \"{Source}\" to \"{Destination}\"", source, destination); DirectoryHelper.MoveContents(source, destination); } catch (Exception ex) { Logger.LogError(ex, "Error while moving storage directory from \"{Source}\" to \"{Destination}\"", source, destination); } } } public override Task ShouldExecuteAsync() { foreach (var configuredPath in GetConfiguredPaths()) { var move = GetMove(configuredPath); if (move != null && Directory.Exists(move.Value.Source)) return Task.FromResult(true); } return Task.FromResult(false); } }