mirror of
https://github.com/ppy/osu.git
synced 2025-03-14 05:47:20 +08:00
Merge pull request #18688 from peppy/too-many-import-methods
Various clean-up on model managers / importer classes
This commit is contained in:
commit
cf2238f683
@ -225,10 +225,10 @@ namespace osu.Game.Tests.Online
|
||||
this.testBeatmapManager = testBeatmapManager;
|
||||
}
|
||||
|
||||
public override Live<BeatmapSetInfo> Import(BeatmapSetInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
public override Live<BeatmapSetInfo> Import(BeatmapSetInfo item, ArchiveReader archive = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
testBeatmapManager.AllowImport.Task.WaitSafely();
|
||||
return (testBeatmapManager.CurrentImport = base.Import(item, archive, lowPriority, cancellationToken));
|
||||
return (testBeatmapManager.CurrentImport = base.Import(item, archive, cancellationToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -347,35 +347,17 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
#region Implementation of ICanAcceptFiles
|
||||
|
||||
public Task Import(params string[] paths)
|
||||
{
|
||||
return beatmapModelManager.Import(paths);
|
||||
}
|
||||
public Task Import(params string[] paths) => beatmapModelManager.Import(paths);
|
||||
|
||||
public Task Import(params ImportTask[] tasks)
|
||||
{
|
||||
return beatmapModelManager.Import(tasks);
|
||||
}
|
||||
public Task Import(params ImportTask[] tasks) => beatmapModelManager.Import(tasks);
|
||||
|
||||
public Task<IEnumerable<Live<BeatmapSetInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks)
|
||||
{
|
||||
return beatmapModelManager.Import(notification, tasks);
|
||||
}
|
||||
public Task<IEnumerable<Live<BeatmapSetInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks) => beatmapModelManager.Import(notification, tasks);
|
||||
|
||||
public Task<Live<BeatmapSetInfo>?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return beatmapModelManager.Import(task, lowPriority, cancellationToken);
|
||||
}
|
||||
public Task<Live<BeatmapSetInfo>?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default) => beatmapModelManager.Import(task, lowPriority, cancellationToken);
|
||||
|
||||
public Task<Live<BeatmapSetInfo>?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return beatmapModelManager.Import(archive, lowPriority, cancellationToken);
|
||||
}
|
||||
public Task<Live<BeatmapSetInfo>?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default) => beatmapModelManager.Import(archive, lowPriority, cancellationToken);
|
||||
|
||||
public Live<BeatmapSetInfo>? Import(BeatmapSetInfo item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return beatmapModelManager.Import(item, archive, lowPriority, cancellationToken);
|
||||
}
|
||||
public Live<BeatmapSetInfo>? Import(BeatmapSetInfo item, ArchiveReader? archive = null, CancellationToken cancellationToken = default) => beatmapModelManager.Import(item, archive, cancellationToken);
|
||||
|
||||
public IEnumerable<string> HandledExtensions => beatmapModelManager.HandledExtensions;
|
||||
|
||||
|
@ -12,14 +12,22 @@ namespace osu.Game.Database
|
||||
public interface ICanAcceptFiles
|
||||
{
|
||||
/// <summary>
|
||||
/// Import the specified paths.
|
||||
/// Import one or more items from filesystem <paramref name="paths"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be treated as a low priority batch import if more than one path is specified.
|
||||
/// This will post notifications tracking progress.
|
||||
/// </remarks>
|
||||
/// <param name="paths">The files which should be imported.</param>
|
||||
Task Import(params string[] paths);
|
||||
|
||||
/// <summary>
|
||||
/// Import the specified files from the given import tasks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be treated as a low priority batch import if more than one path is specified.
|
||||
/// This will post notifications tracking progress.
|
||||
/// </remarks>
|
||||
/// <param name="tasks">The import tasks from which the files should be imported.</param>
|
||||
Task Import(params ImportTask[] tasks);
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
/// <summary>
|
||||
@ -18,35 +16,14 @@ namespace osu.Game.Database
|
||||
public interface IModelImporter<TModel> : IPostNotifications, IPostImports<TModel>, ICanAcceptFiles
|
||||
where TModel : class, IHasGuidPrimaryKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Process multiple import tasks, updating a tracking notification with progress.
|
||||
/// </summary>
|
||||
/// <param name="notification">The notification to update.</param>
|
||||
/// <param name="tasks">The import tasks.</param>
|
||||
/// <returns>The imported models.</returns>
|
||||
Task<IEnumerable<Live<TModel>>> Import(ProgressNotification notification, params ImportTask[] tasks);
|
||||
|
||||
/// <summary>
|
||||
/// Import one <typeparamref name="TModel"/> from the filesystem and delete the file on success.
|
||||
/// Note that this bypasses the UI flow and should only be used for special cases or testing.
|
||||
/// </summary>
|
||||
/// <param name="task">The <see cref="ImportTask"/> containing data about the <typeparamref name="TModel"/> to import.</param>
|
||||
/// <param name="lowPriority">Whether this is a low priority import.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>The imported model, if successful.</returns>
|
||||
Task<Live<TModel>?> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Silently import an item from an <see cref="ArchiveReader"/>.
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to be imported.</param>
|
||||
/// <param name="lowPriority">Whether this is a low priority import.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
Task<Live<TModel>?> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Silently import an item from a <typeparamref name="TModel"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The model to be imported.</param>
|
||||
/// <param name="archive">An optional archive to use for model population.</param>
|
||||
/// <param name="lowPriority">Whether this is a low priority import.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
Live<TModel>? Import(TModel item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// A user displayable name for the model type associated with this manager.
|
||||
/// </summary>
|
||||
|
@ -266,57 +266,23 @@ namespace osu.Game.Scoring
|
||||
});
|
||||
}
|
||||
|
||||
public void Delete(List<ScoreInfo> items, bool silent = false)
|
||||
{
|
||||
scoreModelManager.Delete(items, silent);
|
||||
}
|
||||
public void Delete(List<ScoreInfo> items, bool silent = false) => scoreModelManager.Delete(items, silent);
|
||||
|
||||
public void Undelete(List<ScoreInfo> items, bool silent = false)
|
||||
{
|
||||
scoreModelManager.Undelete(items, silent);
|
||||
}
|
||||
public void Undelete(List<ScoreInfo> items, bool silent = false) => scoreModelManager.Undelete(items, silent);
|
||||
|
||||
public void Undelete(ScoreInfo item)
|
||||
{
|
||||
scoreModelManager.Undelete(item);
|
||||
}
|
||||
public void Undelete(ScoreInfo item) => scoreModelManager.Undelete(item);
|
||||
|
||||
public Task Import(params string[] paths)
|
||||
{
|
||||
return scoreModelManager.Import(paths);
|
||||
}
|
||||
public Task Import(params string[] paths) => scoreModelManager.Import(paths);
|
||||
|
||||
public Task Import(params ImportTask[] tasks)
|
||||
{
|
||||
return scoreModelManager.Import(tasks);
|
||||
}
|
||||
public Task Import(params ImportTask[] tasks) => scoreModelManager.Import(tasks);
|
||||
|
||||
public IEnumerable<string> HandledExtensions => scoreModelManager.HandledExtensions;
|
||||
|
||||
public Task<IEnumerable<Live<ScoreInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks)
|
||||
{
|
||||
return scoreModelManager.Import(notification, tasks);
|
||||
}
|
||||
public Task<IEnumerable<Live<ScoreInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreModelManager.Import(notification, tasks);
|
||||
|
||||
public Task<Live<ScoreInfo>> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return scoreModelManager.Import(task, lowPriority, cancellationToken);
|
||||
}
|
||||
public Live<ScoreInfo> Import(ScoreInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default) => scoreModelManager.Import(item, archive, cancellationToken);
|
||||
|
||||
public Task<Live<ScoreInfo>> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return scoreModelManager.Import(archive, lowPriority, cancellationToken);
|
||||
}
|
||||
|
||||
public Live<ScoreInfo> Import(ScoreInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return scoreModelManager.Import(item, archive, lowPriority, cancellationToken);
|
||||
}
|
||||
|
||||
public bool IsAvailableLocally(ScoreInfo model)
|
||||
{
|
||||
return scoreModelManager.IsAvailableLocally(model);
|
||||
}
|
||||
public bool IsAvailableLocally(ScoreInfo model) => scoreModelManager.IsAvailableLocally(model);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -268,37 +268,21 @@ namespace osu.Game.Skinning
|
||||
set => skinModelManager.PostImport = value;
|
||||
}
|
||||
|
||||
public Task Import(params string[] paths)
|
||||
{
|
||||
return skinModelManager.Import(paths);
|
||||
}
|
||||
public Task Import(params string[] paths) => skinModelManager.Import(paths);
|
||||
|
||||
public Task Import(params ImportTask[] tasks)
|
||||
{
|
||||
return skinModelManager.Import(tasks);
|
||||
}
|
||||
public Task Import(params ImportTask[] tasks) => skinModelManager.Import(tasks);
|
||||
|
||||
public IEnumerable<string> HandledExtensions => skinModelManager.HandledExtensions;
|
||||
|
||||
public Task<IEnumerable<Live<SkinInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks)
|
||||
{
|
||||
return skinModelManager.Import(notification, tasks);
|
||||
}
|
||||
public Task<IEnumerable<Live<SkinInfo>>> Import(ProgressNotification notification, params ImportTask[] tasks) => skinModelManager.Import(notification, tasks);
|
||||
|
||||
public Task<Live<SkinInfo>> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return skinModelManager.Import(task, lowPriority, cancellationToken);
|
||||
}
|
||||
public Task<Live<SkinInfo>> Import(ImportTask task, bool lowPriority = false, CancellationToken cancellationToken = default) => skinModelManager.Import(task, lowPriority, cancellationToken);
|
||||
|
||||
public Task<Live<SkinInfo>> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return skinModelManager.Import(archive, lowPriority, cancellationToken);
|
||||
}
|
||||
public Task<Live<SkinInfo>> Import(ArchiveReader archive, bool lowPriority = false, CancellationToken cancellationToken = default) =>
|
||||
skinModelManager.Import(archive, lowPriority, cancellationToken);
|
||||
|
||||
public Live<SkinInfo> Import(SkinInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return skinModelManager.Import(item, archive, lowPriority, cancellationToken);
|
||||
}
|
||||
public Live<SkinInfo> Import(SkinInfo item, ArchiveReader archive = null, bool lowPriority = false, CancellationToken cancellationToken = default) =>
|
||||
skinModelManager.Import(item, archive, cancellationToken);
|
||||
|
||||
#endregion
|
||||
|
||||
@ -323,46 +307,22 @@ namespace osu.Game.Skinning
|
||||
});
|
||||
}
|
||||
|
||||
public bool Delete(SkinInfo item) => skinModelManager.Delete(item);
|
||||
|
||||
public void Delete(List<SkinInfo> items, bool silent = false) => skinModelManager.Delete(items, silent);
|
||||
|
||||
public void Undelete(List<SkinInfo> items, bool silent = false) => skinModelManager.Undelete(items, silent);
|
||||
|
||||
public void Undelete(SkinInfo item) => skinModelManager.Undelete(item);
|
||||
|
||||
public bool IsAvailableLocally(SkinInfo model) => skinModelManager.IsAvailableLocally(model);
|
||||
|
||||
public void ReplaceFile(SkinInfo model, RealmNamedFileUsage file, Stream contents) => skinModelManager.ReplaceFile(model, file, contents);
|
||||
|
||||
public void DeleteFile(SkinInfo model, RealmNamedFileUsage file) => skinModelManager.DeleteFile(model, file);
|
||||
|
||||
public void AddFile(SkinInfo model, Stream contents, string filename) => skinModelManager.AddFile(model, contents, filename);
|
||||
|
||||
#endregion
|
||||
|
||||
public bool Delete(SkinInfo item)
|
||||
{
|
||||
return skinModelManager.Delete(item);
|
||||
}
|
||||
|
||||
public void Delete(List<SkinInfo> items, bool silent = false)
|
||||
{
|
||||
skinModelManager.Delete(items, silent);
|
||||
}
|
||||
|
||||
public void Undelete(List<SkinInfo> items, bool silent = false)
|
||||
{
|
||||
skinModelManager.Undelete(items, silent);
|
||||
}
|
||||
|
||||
public void Undelete(SkinInfo item)
|
||||
{
|
||||
skinModelManager.Undelete(item);
|
||||
}
|
||||
|
||||
public bool IsAvailableLocally(SkinInfo model)
|
||||
{
|
||||
return skinModelManager.IsAvailableLocally(model);
|
||||
}
|
||||
|
||||
public void ReplaceFile(SkinInfo model, RealmNamedFileUsage file, Stream contents)
|
||||
{
|
||||
skinModelManager.ReplaceFile(model, file, contents);
|
||||
}
|
||||
|
||||
public void DeleteFile(SkinInfo model, RealmNamedFileUsage file)
|
||||
{
|
||||
skinModelManager.DeleteFile(model, file);
|
||||
}
|
||||
|
||||
public void AddFile(SkinInfo model, Stream contents, string filename)
|
||||
{
|
||||
skinModelManager.AddFile(model, contents, filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,9 +39,6 @@ namespace osu.Game.Stores
|
||||
|
||||
protected override string[] HashableFileTypes => new[] { ".osu" };
|
||||
|
||||
// protected override bool CheckLocalAvailability(RealmBeatmapSet model, System.Linq.IQueryable<RealmBeatmapSet> items)
|
||||
// => base.CheckLocalAvailability(model, items) || (model.OnlineID > -1));
|
||||
|
||||
private readonly BeatmapOnlineLookupQueue? onlineLookupQueue;
|
||||
|
||||
protected BeatmapImporter(RealmAccess realm, Storage storage, BeatmapOnlineLookupQueue? onlineLookupQueue = null)
|
||||
|
@ -78,22 +78,7 @@ namespace osu.Game.Stores
|
||||
Files = new RealmFileStore(realm, storage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import one or more <typeparamref name="TModel"/> items from filesystem <paramref name="paths"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be treated as a low priority import if more than one path is specified; use <see cref="Import(ImportTask[])"/> to always import at standard priority.
|
||||
/// This will post notifications tracking progress.
|
||||
/// </remarks>
|
||||
/// <param name="paths">One or more archive locations on disk.</param>
|
||||
public Task Import(params string[] paths)
|
||||
{
|
||||
var notification = new ProgressNotification { State = ProgressNotificationState.Active };
|
||||
|
||||
PostNotification?.Invoke(notification);
|
||||
|
||||
return Import(notification, paths.Select(p => new ImportTask(p)).ToArray());
|
||||
}
|
||||
public Task Import(params string[] paths) => Import(paths.Select(p => new ImportTask(p)).ToArray());
|
||||
|
||||
public Task Import(params ImportTask[] tasks)
|
||||
{
|
||||
@ -250,7 +235,7 @@ namespace osu.Game.Stores
|
||||
return null;
|
||||
}
|
||||
|
||||
var scheduledImport = Task.Factory.StartNew(() => Import(model, archive, lowPriority, cancellationToken),
|
||||
var scheduledImport = Task.Factory.StartNew(() => Import(model, archive, cancellationToken),
|
||||
cancellationToken,
|
||||
TaskCreationOptions.HideScheduler,
|
||||
lowPriority ? import_scheduler_low_priority : import_scheduler);
|
||||
@ -258,69 +243,13 @@ namespace osu.Game.Stores
|
||||
return await scheduledImport.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any file extensions which should be included in hash creation.
|
||||
/// Generally should include all file types which determine the file's uniqueness.
|
||||
/// Large files should be avoided if possible.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only used by the default hash implementation. If <see cref="ComputeHash"/> is overridden, it will not be used.
|
||||
/// </remarks>
|
||||
protected abstract string[] HashableFileTypes { get; }
|
||||
|
||||
internal static void LogForModel(TModel? model, string message, Exception? e = null)
|
||||
{
|
||||
string trimmedHash;
|
||||
if (model == null || !model.IsValid || string.IsNullOrEmpty(model.Hash))
|
||||
trimmedHash = "?????";
|
||||
else
|
||||
trimmedHash = model.Hash.Substring(0, 5);
|
||||
|
||||
string prefix = $"[{trimmedHash}]";
|
||||
|
||||
if (e != null)
|
||||
Logger.Error(e, $"{prefix} {message}", LoggingTarget.Database);
|
||||
else
|
||||
Logger.Log($"{prefix} {message}", LoggingTarget.Database);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the implementation overrides <see cref="ComputeHash"/> with a custom implementation.
|
||||
/// Custom hash implementations must bypass the early exit in the import flow (see <see cref="computeHashFast"/> usage).
|
||||
/// </summary>
|
||||
protected virtual bool HasCustomHashFunction => false;
|
||||
|
||||
/// <summary>
|
||||
/// Create a SHA-2 hash from the provided archive based on file content of all files matching <see cref="HashableFileTypes"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the case of no matching files, a hash will be generated from the passed archive's <see cref="ArchiveReader.Name"/>.
|
||||
/// </remarks>
|
||||
protected virtual string ComputeHash(TModel item)
|
||||
{
|
||||
// for now, concatenate all hashable files in the set to create a unique hash.
|
||||
MemoryStream hashable = new MemoryStream();
|
||||
|
||||
foreach (RealmNamedFileUsage file in item.Files.Where(f => HashableFileTypes.Any(ext => f.Filename.EndsWith(ext, StringComparison.OrdinalIgnoreCase))).OrderBy(f => f.Filename))
|
||||
{
|
||||
using (Stream s = Files.Store.GetStream(file.File.GetStoragePath()))
|
||||
s.CopyTo(hashable);
|
||||
}
|
||||
|
||||
if (hashable.Length > 0)
|
||||
return hashable.ComputeSHA2Hash();
|
||||
|
||||
return item.Hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Silently import an item from a <typeparamref name="TModel"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The model to be imported.</param>
|
||||
/// <param name="archive">An optional archive to use for model population.</param>
|
||||
/// <param name="lowPriority">Whether this is a low priority import.</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
public virtual Live<TModel>? Import(TModel item, ArchiveReader? archive = null, bool lowPriority = false, CancellationToken cancellationToken = default)
|
||||
public virtual Live<TModel>? Import(TModel item, ArchiveReader? archive = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Realm.Run(realm =>
|
||||
{
|
||||
@ -420,6 +349,61 @@ namespace osu.Game.Stores
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any file extensions which should be included in hash creation.
|
||||
/// Generally should include all file types which determine the file's uniqueness.
|
||||
/// Large files should be avoided if possible.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is only used by the default hash implementation. If <see cref="ComputeHash"/> is overridden, it will not be used.
|
||||
/// </remarks>
|
||||
protected abstract string[] HashableFileTypes { get; }
|
||||
|
||||
internal static void LogForModel(TModel? model, string message, Exception? e = null)
|
||||
{
|
||||
string trimmedHash;
|
||||
if (model == null || !model.IsValid || string.IsNullOrEmpty(model.Hash))
|
||||
trimmedHash = "?????";
|
||||
else
|
||||
trimmedHash = model.Hash.Substring(0, 5);
|
||||
|
||||
string prefix = $"[{trimmedHash}]";
|
||||
|
||||
if (e != null)
|
||||
Logger.Error(e, $"{prefix} {message}", LoggingTarget.Database);
|
||||
else
|
||||
Logger.Log($"{prefix} {message}", LoggingTarget.Database);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the implementation overrides <see cref="ComputeHash"/> with a custom implementation.
|
||||
/// Custom hash implementations must bypass the early exit in the import flow (see <see cref="computeHashFast"/> usage).
|
||||
/// </summary>
|
||||
protected virtual bool HasCustomHashFunction => false;
|
||||
|
||||
/// <summary>
|
||||
/// Create a SHA-2 hash from the provided archive based on file content of all files matching <see cref="HashableFileTypes"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the case of no matching files, a hash will be generated from the passed archive's <see cref="ArchiveReader.Name"/>.
|
||||
/// </remarks>
|
||||
protected virtual string ComputeHash(TModel item)
|
||||
{
|
||||
// for now, concatenate all hashable files in the set to create a unique hash.
|
||||
MemoryStream hashable = new MemoryStream();
|
||||
|
||||
foreach (RealmNamedFileUsage file in item.Files.Where(f => HashableFileTypes.Any(ext => f.Filename.EndsWith(ext, StringComparison.OrdinalIgnoreCase))).OrderBy(f => f.Filename))
|
||||
{
|
||||
using (Stream s = Files.Store.GetStream(file.File.GetStoragePath()))
|
||||
s.CopyTo(hashable);
|
||||
}
|
||||
|
||||
if (hashable.Length > 0)
|
||||
return hashable.ComputeSHA2Hash();
|
||||
|
||||
return item.Hash;
|
||||
}
|
||||
|
||||
private string computeHashFast(ArchiveReader reader)
|
||||
{
|
||||
MemoryStream hashable = new MemoryStream();
|
||||
|
Loading…
x
Reference in New Issue
Block a user