using System.IO.Abstractions; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using Newtonsoft.Json; using Recyclarr.Common; namespace Recyclarr.TrashLib.Json; public record LoadedJsonObject(IFileInfo File, T Obj); public class BulkJsonLoader : IBulkJsonLoader { private readonly ILogger _log; private readonly JsonSerializerSettings _serializerSettings; public BulkJsonLoader(ILogger log, JsonSerializerSettings serializerSettings) { _log = log; _serializerSettings = serializerSettings; } public ICollection LoadAllFilesAtPaths( IEnumerable jsonPaths, Func>, IObservable>? extra = null) { var jsonFiles = JsonUtils.GetJsonFilesInDirectories(jsonPaths, _log); var observable = jsonFiles.ToObservable() .Select(x => Observable.Defer(() => LoadJsonFromFile(x))) .Merge(8); var convertedObservable = extra?.Invoke(observable) ?? observable.Select(x => x.Obj); return convertedObservable.ToEnumerable().ToList(); } private T ParseJson(string guideData, string fileName) { var obj = JsonConvert.DeserializeObject(guideData, _serializerSettings); if (obj is null) { throw new JsonSerializationException($"Unable to parse JSON at file {fileName}"); } return obj; } private IObservable> LoadJsonFromFile(IFileInfo file) { return Observable.Using(file.OpenText, x => x.ReadToEndAsync().ToObservable()) .Select(x => new LoadedJsonObject(file, ParseJson(x, file.Name))) .Catch((JsonException e) => { _log.Warning("Failed to parse JSON file: {File} ({Reason})", file.Name, e.Message); return Observable.Empty>(); }); } }