示例#1
0
 public override async Task ExtractSave(IIndelibleDirectory outputDirectory)
 {
     await foreach (var _ in outputDirectory.CopyFromDirectory(this.ContentDirectory, true))
     {
     }
     ;
 }
        public async override Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents)
        {
            var oldLatestFile = this.ProfileRoot.OpenFile("latest");

            // todo decide on some way to organize these saves.
            var newGuid          = Guid.NewGuid();
            var saveName         = $"{DateTimeOffset.UtcNow.ToString(DateFormat)}-{newGuid}";
            var saveDirectory    = this.ProfileRoot.OpenDirectory(saveName);
            var contentDirectory = saveDirectory.OpenDirectory("content");

            // Copy it twice, once for backup, once for head.
            await foreach (var _ in contentDirectory.CopyFromDirectory(saveContents, true))
            {
            }
            ;

            if (oldLatestFile.Created)
            {
                var oldLatestName = oldLatestFile.ReadAllText();
                var oldLatest     = this.ProfileRoot.OpenDirectory(oldLatestName);
                // Delete the old head
                oldLatest.Delete();
            }
            this.ProfileRoot.OpenFile("latest").WriteAllText(saveName, Encoding.UTF8);
            return(this.GetSave(saveDirectory));
        }
示例#3
0
 public SaveProfile(Guid profileGuid, string saveType, string profileName, IIndelibleDirectory profileRoot)
 {
     this.Guid        = profileGuid;
     this.ProfileName = profileName;
     this.ProfileRoot = profileRoot;
     this.SaveType    = saveType;
 }
示例#4
0
 public CopyingSaveGame(DateTimeOffset createdTime,
                        Guid saveGuid,
                        string saveType,
                        IIndelibleDirectory contentDirectory)
     : base(createdTime, saveGuid, saveType)
 {
     this.ContentDirectory = contentDirectory;
 }
示例#5
0
        private async Task CopyRecursiveNonDiffs(IIndelibleDirectory outputDirectory)
        {
            var baseDir = this.DiffDir.OpenDirectory("copy");

            await foreach (var _ in outputDirectory.CopyFromDirectory(baseDir, true))
            {
            }
            ;
        }
        private async Task CreateBaseSave(IIndelibleDirectory saveContents)
        {
            var contentDirectory = this.ProfileRoot.OpenDirectory("base/content");

            await foreach (var _ in contentDirectory.CopyFromDirectory(saveContents))
            {
            }
            ;
        }
        public ReplaceStrategySaveProfile(Guid profileGuid,
                                          string saveType, string profileName, IIndelibleDirectory profileRoot)
            : base(profileGuid, saveType, profileName, profileRoot)
        {
            var saveManifest = this.ProfileRoot.OpenFile("profile");

            if (!saveManifest.Created)
            {
                saveManifest.WriteAllText($"{profileName}{Environment.NewLine}{nameof(SaveManagementStrategy.Replace)}");
            }
        }
        public async IAsyncEnumerable <IFileRecord> GetFileRecordsAsync(IIndelibleDirectory directoryRoot)
        {
            await using var context = new DatabaseContext(this.Options.Options);
            var files   = directoryRoot.EnumerateFilesRecursive().ToList();
            var records = context.FileRecords
                          .Include(r => r.Metadata)
                          .Where(r => files.Select(f => f.FileGuid).Contains(r.RecordID));

            foreach (var r in records)
            {
                yield return(new FileRecord(files.First(f => f.FileGuid == r.RecordID),
                                            r.MimeType, r.Metadata.AsMetadataCollection(r.RecordID)));
            }
        }
        public async override Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents)
        {
            // todo decide on some way to organize these saves.
            var newGuid          = Guid.NewGuid();
            var saveName         = $"{DateTimeOffset.UtcNow.ToString(DateFormat)}-{newGuid}";
            var saveDirectory    = this.ProfileRoot.OpenDirectory(saveName);
            var contentDirectory = saveDirectory.OpenDirectory("content");

            await foreach (var _ in contentDirectory.CopyFromDirectory(saveContents, true))
            {
            }
            ;

            this.ProfileRoot.OpenFile("latest").WriteAllText(saveName, Encoding.UTF8);
            return(this.GetSave(saveDirectory) !);
        }
示例#10
0
        /// <summary>
        /// Copies all the files and directories from the source directory recursively into this directory.
        /// </summary>
        /// <param name="this">The destination directory.</param>
        /// <param name="source">The source directory.</param>
        /// <param name="overwrite">Whether or not to overwrite existing files.</param>
        /// <returns>An enumerable of copied files.</returns>
        public static async IAsyncEnumerable <IFile> CopyFromDirectory(this IIndelibleDirectory @this, IIndelibleDirectory source, bool overwrite)
        {
            if (@this == source)
            {
                yield break;
            }

            // Do the parent directory
            foreach (var f in source.EnumerateFiles())
            {
                yield return(await @this.CopyFromAsync(f, overwrite));
            }

            var queuedDirs =
                source.EnumerateDirectories()
                .Select(d => (@this, d)).ToList();

            // BFS over all the children.

            Queue <(IIndelibleDirectory, IDirectory)> dirsToProcess = new Queue <(IIndelibleDirectory, IDirectory)>(queuedDirs);

            while (dirsToProcess.Count > 0)
            {
                var(parent, src) = dirsToProcess.Dequeue();
                var dst = parent.OpenDirectory(src.Name);
                foreach (var f in src.EnumerateFiles())
                {
                    yield return(await dst.CopyFromAsync(f, overwrite));
                }

                var children = src.EnumerateDirectories()
                               .Select(d => (dst, d)).ToList();

                foreach (var childDirectory in children)
                {
                    dirsToProcess.Enqueue(childDirectory);
                }
            }
        }
        public async override Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents)
        {
            if (!this.ProfileRoot.ContainsDirectory("base"))
            {
                await this.CreateBaseSave(saveContents);
            }
            using var rollingHash = new RollingHash(32);

            // setup
            var newGuid          = Guid.NewGuid();
            var saveName         = $"{DateTimeOffset.UtcNow.ToString(DateFormat)}-{newGuid}";
            var saveDirectory    = this.ProfileRoot.OpenDirectory(saveName);
            var contentDirectory = saveDirectory.OpenDirectory("content");

            // diff is for anything that exists in the base directory
            var diffDir = contentDirectory.OpenDirectory("diff");

            // copy is for anything that does not and can not be diffed.
            var copyDir = contentDirectory.OpenDirectory("copy");

            // Traverse base directory in tandem with saveContents
            var baseDir = this.ProfileRoot.OpenDirectory("base/content").AsReadOnly();

            foreach (var f in saveContents.EnumerateFiles())
            {
                if (!baseDir.ContainsFile(f.Name))
                {
                    await copyDir.CopyFromAsync(f);

                    continue;
                }

                using var targetStream = f.OpenReadStream();
                using var baseStream   = baseDir.OpenFile(f.Name).OpenReadStream();

                using var outStream = diffDir.OpenFile(f.Name).OpenStream();
                using var decoder   = new VcEncoder(baseStream, targetStream, outStream,
                                                    rollingHash: rollingHash, blockSize: 32);
                VCDiffResult result = await decoder.EncodeAsync();

                if (result != VCDiffResult.SUCCESS)
                {
                    throw new IOException($"Failed to encode delta for {f.Name}");
                }
            }

            foreach (var d in saveContents.EnumerateDirectories().Where(d => !baseDir.ContainsDirectory(d.Name)))
            {
                // Copy all directories not in the base.
                await foreach (var _ in copyDir.OpenDirectory(d.Name).CopyFromDirectory(d))
                {
                }
                ;
            }

            var queuedDirs = (from targetDir in saveContents.EnumerateDirectories()
                              where baseDir.ContainsDirectory(targetDir.Name)
                              select(diffDir, baseDir.OpenDirectory(targetDir.Name), targetDir)).ToList();

            Queue <(IDirectory parentDir, IReadOnlyDirectory baseDir, IDirectory targetDir)> dirsToProcess =
                new Queue <(IDirectory, IReadOnlyDirectory, IDirectory)>(queuedDirs);

            while (dirsToProcess.Count > 0)
            {
                var(parent, src, diff) = dirsToProcess.Dequeue();
                var dst = parent.OpenDirectory(src.Name);
                foreach (var f in src.EnumerateFiles())
                {
                    if (!diff.ContainsFile(f.Name))
                    {
                        continue;
                    }
                    using var baseStream   = f.OpenReadStream();
                    using var targetStream = diff.OpenFile(f.Name).OpenReadStream();
                    using var outStream    = dst.OpenFile(f.Name).OpenStream();
                    using var decoder      = new VcEncoder(baseStream, targetStream, outStream,
                                                           rollingHash: rollingHash, blockSize: 32);
                    VCDiffResult result = await decoder.EncodeAsync();

                    if (result != VCDiffResult.SUCCESS)
                    {
                        throw new IOException($"Failed to decode delta for {f.Name}");
                    }
                }

                var children = from targetDir in diff.EnumerateDirectories()
                               where src.ContainsDirectory(targetDir.Name)
                               select(dst, src.OpenDirectory(targetDir.Name), targetDir);

                foreach (var childDirectory in children)
                {
                    dirsToProcess.Enqueue(childDirectory);
                }
            }

            this.ProfileRoot.OpenFile("latest").WriteAllText(saveName, Encoding.UTF8);
            return(this.GetSave(saveDirectory) !);
        }
示例#12
0
 public override async Task ExtractSave(IIndelibleDirectory outputDirectory)
 {
     await CopyRecursiveDiffs(outputDirectory);
     await CopyRecursiveNonDiffs(outputDirectory);
 }
        private ISaveGame?GetSave(IIndelibleDirectory internalSaveDir)
        {
            string name = internalSaveDir.Name;

            if (!DateTimeOffset.TryParseExact(name[0..DateFormat.Length], DateFormat, CultureInfo.InvariantCulture,
 public override Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents)
 {
     return(Task.FromResult <ISaveGame>(new EmptySaveGame(DateTimeOffset.UtcNow, Guid.NewGuid(), this.SaveType)));
 }
示例#15
0
 public DiffingSaveGame(DateTimeOffset createdTime, Guid saveGuid, string saveType, IIndelibleDirectory baseDir, IIndelibleDirectory diffDir)
     : base(createdTime, saveGuid, saveType)
 {
     this.BaseDir = baseDir;
     this.DiffDir = diffDir;
 }
示例#16
0
        private async Task CopyRecursiveDiffs(IIndelibleDirectory outputDirectory)
        {
            var diffDir = this.DiffDir.OpenDirectory("diff");

            // Do the parent directory
            foreach (var f in this.BaseDir.EnumerateFiles())
            {
                if (!diffDir.ContainsFile(f.Name))
                {
                    continue;
                }
                using var baseStream         = f.OpenReadStream();
                using var diffStream         = diffDir.OpenFile(f.Name).OpenReadStream();
                using var outStream          = outputDirectory.OpenFile(f.Name).OpenStream();
                using var decoder            = new VcDecoder(baseStream, diffStream, outStream);
                (VCDiffResult result, var _) = await decoder.DecodeAsync();

                if (result != VCDiffResult.SUCCESS)
                {
                    throw new IOException($"Failed to decode delta for {f.Name}");
                }
            }

            var queuedDirs = (from baseDir in this.BaseDir.EnumerateDirectories()
                              where diffDir.ContainsDirectory(baseDir.Name)
                              select(outputDirectory, baseDir, diffDir.OpenDirectory(baseDir.Name))).ToList();

            // BFS over all the children.
            Queue <(IIndelibleDirectory parentDir, IDirectory baseDir, IDirectory diffDir)> dirsToProcess =
                new Queue <(IIndelibleDirectory, IDirectory, IDirectory)>(queuedDirs);

            while (dirsToProcess.Count > 0)
            {
                var(parent, src, diff) = dirsToProcess.Dequeue();
                var dst = parent.OpenDirectory(src.Name);
                foreach (var f in src.EnumerateFiles())
                {
                    if (!diff.ContainsFile(f.Name))
                    {
                        continue;
                    }
                    using var baseStream         = f.OpenReadStream();
                    using var diffStream         = diff.OpenFile(f.Name).OpenReadStream();
                    using var outStream          = dst.OpenFile(f.Name).OpenStream();
                    using var decoder            = new VcDecoder(baseStream, diffStream, outStream);
                    (VCDiffResult result, var _) = await decoder.DecodeAsync();

                    if (result != VCDiffResult.SUCCESS)
                    {
                        throw new IOException($"Failed to decode delta for {f.Name}");
                    }
                }

                var children = from baseDir in src.EnumerateDirectories()
                               where diff.ContainsDirectory(baseDir.Name)
                               select(dst, baseDir, diff.OpenDirectory(baseDir.Name));

                foreach (var childDirectory in children)
                {
                    dirsToProcess.Enqueue(childDirectory);
                }
            }
        }
示例#17
0
 /// <summary>
 /// Describe a file copy with the given source file and the target directory.
 /// The resultant file will have the same file name as the source.
 /// </summary>
 /// <param name="source">The source file.</param>
 /// <param name="destinationDirectory">The target directory.</param>
 public CopyFileTask(TaskResult <FileInfo> source, IIndelibleDirectory destinationDirectory)
 {
     this.Source      = source;
     this.Destination = destinationDirectory;
 }
示例#18
0
 public abstract Task ExtractSave(IIndelibleDirectory outputDirectory);
示例#19
0
 /// <summary>
 /// Copies all the files and directories from the source directory recursively into this directory.
 /// </summary>
 /// <param name="this">The destination directory.</param>
 /// <param name="source">The source directory.</param>
 /// <param name="overwrite"></param>
 /// <returns>An enumerable of copied files.</returns>
 public static IAsyncEnumerable <IFile> CopyFromDirectory(this IIndelibleDirectory @this, IIndelibleDirectory source) => CopyFromDirectory(@this, source, false);
示例#20
0
 public override Task ExtractSave(IIndelibleDirectory outputDirectory)
 {
     return(Task.CompletedTask);
 }
示例#21
0
 public abstract Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents);
 private ISaveGame GetSave(IIndelibleDirectory internalSaveDir)
 {
     string name = internalSaveDir.Name;
     var    date = DateTimeOffset.ParseExact(name[0..DateFormat.Length], DateFormat, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
示例#23
0
 public GameSaveManager(IIndelibleDirectory saveRoot)
 {
     this.SaveRoot = saveRoot;
 }