diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1252530 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.cs] +indent_style = space +indent_size = 4 diff --git a/BedrockService/BackupFile.cs b/BedrockService/BackupFile.cs new file mode 100644 index 0000000..bed95da --- /dev/null +++ b/BedrockService/BackupFile.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BedrockService +{ + internal class BackupFile + { + public long Length { get; } + + public string Path { get; } + + private BackupFile(string path, long length) + { + Path = path; + Length = length; + } + + public static bool IsBackupSpecification(string input) + { + return input?.Contains(".ldb:") ?? false; + } + + public static List ParseBackupSpecification(string input) + { + return input + .Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries) + .Select(ParseFileSpec) + .ToList(); + } + + private static BackupFile ParseFileSpec(string fileSpec) + { + var chunks = fileSpec.Split(':'); + + // bedrock server returns paths with forward slashes, + // but since we're on windows we need to convert them to backslashes + var path = chunks[0].Replace('/', '\\'); + return new BackupFile(path, long.Parse(chunks[1])); + } + } +} \ No newline at end of file diff --git a/BedrockService/BedrockServerWrapper.cs b/BedrockService/BedrockServerWrapper.cs index ad0a21d..044cd1c 100644 --- a/BedrockService/BedrockServerWrapper.cs +++ b/BedrockService/BedrockServerWrapper.cs @@ -241,34 +241,51 @@ public static Stream GenerateStreamFromString(string s) public void Backup() { + if (string.IsNullOrEmpty(this.ServerConfig.BackupFolderName)) + { + return; + } + try { BackingUp = true; - FileInfo exe = new FileInfo(ServerConfig.BedrockServerExeLocation); - - if (ServerConfig.BackupFolderName.Length > 0) + + process.StandardInput.WriteLine("save hold"); + Thread.Sleep(100); + + List backupFiles; + while (true) { - DirectoryInfo backupTo; - if (Directory.Exists(ServerConfig.BackupFolderName)) - { - backupTo = new DirectoryInfo(ServerConfig.BackupFolderName); - } - else if (exe.Directory.GetDirectories().Count(t => t.Name == ServerConfig.BackupFolderName) == 1) - { - backupTo = exe.Directory.GetDirectories().Single(t => t.Name == ServerConfig.BackupFolderName); - } - else + process.StandardInput.WriteLine("save query"); + Thread.Sleep(100); + var lastLine = GetLastConsoleLine(); + if (BackupFile.IsBackupSpecification(lastLine)) { - backupTo = exe.Directory.CreateSubdirectory(ServerConfig.BackupFolderName); + backupFiles = BackupFile.ParseBackupSpecification(lastLine); + break; } - - var sourceDirectory = exe.Directory.GetDirectories().Single(t => t.Name == worldsFolder); - var targetDirectory = backupTo.CreateSubdirectory($"{worldsFolder}{DateTime.Now.ToString("yyyyMMddhhmmss")}"); - CopyFilesRecursively(sourceDirectory, targetDirectory); - - } + + FileInfo exe = new FileInfo(ServerConfig.BedrockServerExeLocation); + + DirectoryInfo backupTo; + if (Directory.Exists(ServerConfig.BackupFolderName)) + { + backupTo = new DirectoryInfo(ServerConfig.BackupFolderName); + } + else if (exe.Directory.GetDirectories().Count(t => t.Name == ServerConfig.BackupFolderName) == 1) + { + backupTo = exe.Directory.GetDirectories().Single(t => t.Name == ServerConfig.BackupFolderName); + } + else + { + backupTo = exe.Directory.CreateSubdirectory(ServerConfig.BackupFolderName); + } + + var sourceDirectory = exe.Directory.GetDirectories().Single(t => t.Name == worldsFolder); + var targetDirectory = backupTo.CreateSubdirectory($"{worldsFolder}{DateTime.Now.ToString("yyyyMMddhhmmss")}"); + CopyBackupFiles(sourceDirectory, targetDirectory, backupFiles); } catch (Exception e) { @@ -276,17 +293,28 @@ public void Backup() } finally { + process.StandardInput.WriteLine("save resume"); BackingUp = false; } } - private static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) + private static void CopyBackupFiles(DirectoryInfo source, DirectoryInfo target, List backupFiles) { _log.Info("Starting Backup"); - foreach (DirectoryInfo dir in source.GetDirectories()) - CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name)); - foreach (FileInfo file in source.GetFiles()) - file.CopyTo(Path.Combine(target.FullName, file.Name)); + + foreach (var file in backupFiles) + { + var destFileName = Path.Combine(target.FullName, file.Path); + + // Make sure that target directory exists + new FileInfo(destFileName).Directory.Create(); + + File.Copy(Path.Combine(source.FullName, file.Path), destFileName); + + // This trims file to specified length + new FileStream(destFileName, FileMode.Open).SetLength(file.Length); + } + _log.Info("Finished Backup"); } @@ -308,5 +336,12 @@ public string GetCurrentConsole() return sendConsole; } + + private string GetLastConsoleLine() + { + return GetCurrentConsole() + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .LastOrDefault(); + } } } diff --git a/BedrockService/BedrockService.csproj b/BedrockService/BedrockService.csproj index e5a90c3..a5c68fd 100644 --- a/BedrockService/BedrockService.csproj +++ b/BedrockService/BedrockService.csproj @@ -65,8 +65,8 @@ packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll - - packages\log4net.2.0.8\lib\net45-full\log4net.dll + + packages\log4net.2.0.10\lib\net45\log4net.dll packages\NCrontab.Signed.3.3.2\lib\net35\NCrontab.Signed.dll @@ -93,6 +93,7 @@ + diff --git a/BedrockService/BedrockServiceWrapper.cs b/BedrockService/BedrockServiceWrapper.cs index d700a9d..ebeb20c 100644 --- a/BedrockService/BedrockServiceWrapper.cs +++ b/BedrockService/BedrockServiceWrapper.cs @@ -133,24 +133,9 @@ private void CronTimer_Elapsed(object sender, ElapsedEventArgs e) private void Backup() { - foreach (var brs in bedrockServers.OrderByDescending(t => t.ServerConfig.Primary).ToList()) - { - brs.Stopping = true; - if (!stopping) brs.StopControl(); - Thread.Sleep(1000); - } - foreach (var brs in bedrockServers.OrderByDescending(t => t.ServerConfig.Primary).ToList()) { if (!stopping) brs.Backup(); - - } - foreach (var brs in bedrockServers.OrderByDescending(t => t.ServerConfig.Primary).ToList()) - { - brs.Stopping = false; - if (!stopping) brs.StartControl(_hostControl); - Thread.Sleep(2000); - } }