using System; using System.Collections.Generic; using System.IO; using System.Linq; using Dinah.Core.Collections.Immutable; using Newtonsoft.Json; namespace FileManager { public static class FilePathCache { internal class CacheEntry { public string Id { get; set; } public FileType FileType { get; set; } public string Path { get; set; } } static Cache cache { get; } = new Cache(); public static string JsonFile => Path.Combine(Configuration.Instance.LibationFiles, "FilePaths.json"); static FilePathCache() { // load json into memory. if file doesn't exist, nothing to do. save() will create if needed if (FileUtility.FileExists(JsonFile)) { var list = JsonConvert.DeserializeObject>(File.ReadAllText(JsonFile)); cache = new Cache(list); } } public static bool Exists(string id, FileType type) => GetPath(id, type) != null; public static string GetPath(string id, FileType type) { var entry = cache.SingleOrDefault(i => i.Id == id && i.FileType == type); if (entry == null) return null; if (!FileUtility.FileExists(entry.Path)) { remove(entry); return null; } return entry.Path; } private static void remove(CacheEntry entry) { cache.Remove(entry); save(); } public static void Upsert(string id, FileType type, string path) { if (!FileUtility.FileExists(path)) throw new FileNotFoundException("Cannot add path to cache. File not found"); var entry = cache.SingleOrDefault(i => i.Id == id && i.FileType == type); if (entry is null) cache.Add(new CacheEntry { Id = id, FileType = type, Path = path }); else entry.Path = path; save(); } // cache is thread-safe and lock free. but file saving is not private static object locker { get; } = new object(); private static void save() { // create json if not exists static void resave() => File.WriteAllText(JsonFile, JsonConvert.SerializeObject(cache.ToList(), Formatting.Indented)); lock (locker) { try { resave(); } catch (IOException) { try { resave(); } catch (IOException ex) { Serilog.Log.Logger.Error(ex, "Error saving FilePaths.json"); throw; } } } } } }