using System; using System.IO; using System.Reactive.Linq; using System.Text.RegularExpressions; using ReactiveUI; using Splat; using StarsAssistant.Helpers; namespace StarsAssistant.Services; public partial class CSVDataLoader : IEnableLogger { /// /// Reference to the game metadata, retrieved by DI /// protected Services.Game Game = Locator.Current.GetService()!; /// /// Regex to match fs watcher results to Stars file types. /// /// Precompiled RegEx [GeneratedRegex(@".*\.(?[pf])(?\d)+$")] private static partial Regex MyRegex(); /// /// RegEx Instance to match Stars file types. /// protected Regex FileTypeRegEx = MyRegex(); /// /// Instance of the FSWatcher, to which we subscribe. /// protected IObservable Watcher; /// /// Active subscription to FsWatcher. /// protected IDisposable? Subscription; /// /// Construct the instance and prepare our FS Watcher. /// public CSVDataLoader() { // string[] filters = { "*.p*", "*.f*", "*.map" }; Watcher = FsWatcher .ObserveFileSystem(Game.GamePath, [ Game.PlanetFileSearchPattern, Game.FleetFileSearchPattern ]) .ThrottleAndDistinct(2, RxApp.TaskpoolScheduler) .Log(this, $"{DateTime.Now.ToLongTimeString()} FsEvent", fsEvent => $"{fsEvent.FullPath} {fsEvent.ChangeType}") .ObserveOn(RxApp.TaskpoolScheduler); } /// /// Start the CSV watcher, and capture our disposable, so that we can shut /// down the watcher if needed. /// public void StartCSVWatcher() { if (Subscription != null) throw new InvalidOperationException("CSV Watcher is active, can't start it again."); Subscription = Watcher.Subscribe(fsEvent => this.LoadFile(fsEvent.FullPath)); } /// /// Subscription to File Processing, called by our subscription to the watcher. /// /// The File to process protected void LoadFile(string fileName) { Match m = FileTypeRegEx.Match(fileName); if (! m.Success) { this.Log().Error($"Failed to parse {fileName} to identify what we are looking at. Ignoring file."); return; } string type = m.Groups["type"].Value; string player = m.Groups["player"].Value; this.Log().Debug($"Got file type {type} for player {player}"); switch (type) { case "p": var planetLoader = new CSV.PlanetLoader(); planetLoader.ImportForRace(Services.Game.Player); PlanetManager planetManager = Locator.Current.GetService()!; planetManager.InitFromDatabase(); break; case "f": var fleetLoader = new CSV.FleetLoader(); fleetLoader.ImportForRace(Services.Game.Player); FleetManager fleetManager = Locator.Current.GetService()!; FleetManager.PostProcessImportedData(); fleetManager.InitFromDatabase(); break; default: this.Log().Warn($"Planet loader got unknown file type ${type}. Ignoring file."); break; } } }