// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable enable using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using osu.Framework.Extensions; using osu.Framework.IO.Stores; using osu.Game.Database; using osu.Game.Extensions; using Realms; namespace osu.Game.Skinning { public class RealmBackedResourceStore : ResourceStore where T : RealmObject, IHasRealmFiles, IHasGuidPrimaryKey { private Lazy> fileToStoragePathMapping; private readonly Live liveSource; private readonly IDisposable? realmSubscription; public RealmBackedResourceStore(Live source, IResourceStore underlyingStore, RealmAccess? realm) : base(underlyingStore) { liveSource = source; invalidateCache(); Debug.Assert(fileToStoragePathMapping != null); realmSubscription = realm?.RegisterForNotifications(r => r.All().Where(s => s.ID == source.ID), skinChanged); } protected override void Dispose(bool disposing) { base.Dispose(disposing); realmSubscription?.Dispose(); } private void skinChanged(IRealmCollection sender, ChangeSet changes, Exception error) => invalidateCache(); protected override IEnumerable GetFilenames(string name) { foreach (string filename in base.GetFilenames(name)) { string? path = getPathForFile(filename.ToStandardisedPath()); if (path != null) yield return path; } } private string? getPathForFile(string filename) { if (fileToStoragePathMapping.Value.TryGetValue(filename.ToLowerInvariant(), out string path)) return path; return null; } private void invalidateCache() => fileToStoragePathMapping = new Lazy>(initialiseFileCache, LazyThreadSafetyMode.ExecutionAndPublication); private Dictionary initialiseFileCache() => liveSource.PerformRead(source => { var dictionary = new Dictionary(); dictionary.Clear(); foreach (var f in source.Files) dictionary[f.Filename.ToLowerInvariant()] = f.File.GetStoragePath(); return dictionary; }); public override IEnumerable GetAvailableResources() => fileToStoragePathMapping.Value.Keys; } }