Hook up fswatcher to csv parser, needs proper filename parsing.
This commit is contained in:
		| @@ -3,6 +3,7 @@ using Avalonia.Controls.ApplicationLifetimes; | |||||||
| using Avalonia.Markup.Xaml; | using Avalonia.Markup.Xaml; | ||||||
| using StarsAssistant.ViewModels; | using StarsAssistant.ViewModels; | ||||||
| using StarsAssistant.Views; | using StarsAssistant.Views; | ||||||
|  | using Splat; | ||||||
|  |  | ||||||
| namespace StarsAssistant; | namespace StarsAssistant; | ||||||
|  |  | ||||||
| @@ -23,6 +24,9 @@ public partial class App : Application | |||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         var csvloader = Locator.Current.GetService<Services.CSVDataLoader>()!; | ||||||
|  |         csvloader.StartPlanetCSVWatcher(); | ||||||
|  |  | ||||||
|         base.OnFrameworkInitializationCompleted(); |         base.OnFrameworkInitializationCompleted(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -66,19 +66,25 @@ public class PlanetLoader | |||||||
|                     r = db.Race.Find(owner.Key); |                     r = db.Race.Find(owner.Key); | ||||||
|                     if (r == null) |                     if (r == null) | ||||||
|                     { |                     { | ||||||
|                         r = new() |                         r = new() { Name = owner.Key }; | ||||||
|                         { |  | ||||||
|                             Name = owner.Key |  | ||||||
|                         }; |  | ||||||
|                         db.Add(r); |                         db.Add(r); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 foreach (Planet csvp in owner) |                 foreach (Planet csvp in owner) | ||||||
|                 { |                 { | ||||||
|                     Model.Planet p = new Model.Planet{ Name = csvp.Name }; |                     Model.Planet? p = db.Planet.Find(csvp.Name); | ||||||
|                     csvp.UpdateDbPlanet(p); |                     if (p == null) | ||||||
|                     db.Add(p); |                     { | ||||||
|  |                         p = new() { Name = csvp.Name }; | ||||||
|  |                         csvp.UpdateDbPlanet(p); | ||||||
|  |                         db.Add(p); | ||||||
|  |                     }  | ||||||
|  |                     else  | ||||||
|  |                     { | ||||||
|  |                         csvp.UpdateDbPlanet(p); | ||||||
|  |                         db.Update(p); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 db.SaveChanges(); |                 db.SaveChanges(); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -3,28 +3,8 @@ using System.Reactive.Concurrency; | |||||||
|  |  | ||||||
| namespace StarsAssistant.Helpers; | namespace StarsAssistant.Helpers; | ||||||
|  |  | ||||||
| public class FsWatcher | public static class FsWatcher | ||||||
| { | { | ||||||
|     /// <summary> |  | ||||||
|     /// Throttle a FileSystemObserver and eliminate all duplicates. |  | ||||||
|     /// </summary> |  | ||||||
|     /// <remarks> |  | ||||||
|     /// Curtesy of https://endjin.com/blog/2024/05/observe-file-system-changes-with-rx-dotnet |  | ||||||
|     /// </remarks> |  | ||||||
|     /// <param name="watcher">An observer created with <c>ObserveFileSystem</c></param> |  | ||||||
|     /// <param name="inactivitySeconds">Throttling window, defaults to 1 second.</param> |  | ||||||
|     /// <param name="scheduler">Scheduler to user for throttling, default is set by <c>Quiescent</c></param> |  | ||||||
|     /// <returns>A throttled observer with duplicate elimination.</returns> |  | ||||||
|     public static IObservable<IEnumerable<FileSystemEventArgs>> ThrottleAndDistinctObserver ( |  | ||||||
|         IObservable<FileSystemEventArgs> watcher,  |  | ||||||
|         int inactivitySeconds = 1, |  | ||||||
|         IScheduler? scheduler = null) |  | ||||||
|     { |  | ||||||
|         return watcher |  | ||||||
|                 .Quiescent(TimeSpan.FromSeconds(inactivitySeconds), scheduler) |  | ||||||
|                 .Select(changes => changes.DistinctBy(x => (x.ChangeType, x.FullPath))); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Helper to convert a FileSystemWatcher into an obervable stream. See FileSystemWatcher |     /// Helper to convert a FileSystemWatcher into an obervable stream. See FileSystemWatcher | ||||||
|     /// documentation for further details on the parameters. |     /// documentation for further details on the parameters. | ||||||
| @@ -52,6 +32,7 @@ public class FsWatcher | |||||||
|                     if (filters != null) |                     if (filters != null) | ||||||
|                         foreach (string filter in filters) |                         foreach (string filter in filters) | ||||||
|                             fsw.Filters.Add(filter); |                             fsw.Filters.Add(filter); | ||||||
|  |                              | ||||||
|                     if (notifyFilter != null) |                     if (notifyFilter != null) | ||||||
|                         fsw.NotifyFilter = (NotifyFilters) notifyFilter; |                         fsw.NotifyFilter = (NotifyFilters) notifyFilter; | ||||||
|                     fsw.EnableRaisingEvents = true; |                     fsw.EnableRaisingEvents = true; | ||||||
| @@ -90,4 +71,29 @@ public class FsWatcher | |||||||
|                 .RefCount(); |                 .RefCount(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Throttle a FileSystemObserver and eliminate all duplicates. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <remarks> | ||||||
|  |     /// Curtesy of https://endjin.com/blog/2024/05/observe-file-system-changes-with-rx-dotnet | ||||||
|  |     /// </remarks> | ||||||
|  |     /// <param name="watcher">An observer created with <c>ObserveFileSystem</c></param> | ||||||
|  |     /// <param name="inactivitySeconds">Throttling window, defaults to 1 second.</param> | ||||||
|  |     /// <param name="scheduler">Scheduler to user for throttling, default is set by <c>Quiescent</c></param> | ||||||
|  |     /// <returns>A throttled observer with duplicate elimination.</returns> | ||||||
|  |     public static IObservable<FileSystemEventArgs> ThrottleAndDistinct ( | ||||||
|  |         this IObservable<FileSystemEventArgs> watcher,  | ||||||
|  |         int inactivitySeconds = 1, | ||||||
|  |         IScheduler? scheduler = null) | ||||||
|  |     { | ||||||
|  |         return watcher | ||||||
|  |             .Quiescent(TimeSpan.FromSeconds(inactivitySeconds), scheduler) | ||||||
|  |             .SelectMany( | ||||||
|  |                 changes => changes | ||||||
|  |                     .DistinctBy(x => (x.ChangeType, x.FullPath)) | ||||||
|  |                     .ToObservable() | ||||||
|  |                 ) | ||||||
|  |         ; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,24 +34,4 @@ public static class RxExtensions | |||||||
|  |  | ||||||
|         return src.Buffer(zeroCrossings); |         return src.Buffer(zeroCrossings); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <summary> |  | ||||||
|     /// Throttle a FileSystemObserver and eliminate all duplicates. |  | ||||||
|     /// </summary> |  | ||||||
|     /// <remarks> |  | ||||||
|     /// Curtesy of https://endjin.com/blog/2024/05/observe-file-system-changes-with-rx-dotnet |  | ||||||
|     /// </remarks> |  | ||||||
|     /// <param name="watcher">An observer created with <c>ObserveFileSystem</c></param> |  | ||||||
|     /// <param name="inactivitySeconds">Throttling window, defaults to 1 second.</param> |  | ||||||
|     /// <param name="scheduler">Scheduler to user for throttling, default is set by <c>Quiescent</c></param> |  | ||||||
|     /// <returns>A throttled observer with duplicate elimination.</returns> |  | ||||||
|     public static IObservable<IEnumerable<FileSystemEventArgs>> ThrottleAndDistinct ( |  | ||||||
|         this IObservable<FileSystemEventArgs> watcher,  |  | ||||||
|         int inactivitySeconds = 1, |  | ||||||
|         IScheduler? scheduler = null) |  | ||||||
|     { |  | ||||||
|         return watcher |  | ||||||
|                 .Quiescent(TimeSpan.FromSeconds(inactivitySeconds), scheduler) |  | ||||||
|                 .Select(changes => changes.DistinctBy(x => (x.ChangeType, x.FullPath))); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ sealed class Program | |||||||
|     { |     { | ||||||
|         ModeDetector.OverrideModeDetector(Splat.ModeDetection.Mode.Run); |         ModeDetector.OverrideModeDetector(Splat.ModeDetection.Mode.Run); | ||||||
|  |  | ||||||
|  |         var logger = new ConsoleLogger() { Level = LogLevel.Debug }; | ||||||
|  |         Locator.CurrentMutable.RegisterConstant(logger, typeof(ILogger)); | ||||||
|  |  | ||||||
|         Services.Game g = new() |         Services.Game g = new() | ||||||
|         { |         { | ||||||
|             BaseName = "GOINGTH", |             BaseName = "GOINGTH", | ||||||
| @@ -31,6 +34,7 @@ sealed class Program | |||||||
|         Locator.CurrentMutable.RegisterConstant(g, typeof(Services.Game)); |         Locator.CurrentMutable.RegisterConstant(g, typeof(Services.Game)); | ||||||
|         Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader)); |         Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader)); | ||||||
|         Locator.CurrentMutable.Register(() => new StarsDatabase(g.DatabaseFileName), typeof(StarsDatabase)); |         Locator.CurrentMutable.Register(() => new StarsDatabase(g.DatabaseFileName), typeof(StarsDatabase)); | ||||||
|  |         Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader)); | ||||||
|  |  | ||||||
|         __createTestData(); |         __createTestData(); | ||||||
|          |          | ||||||
|   | |||||||
| @@ -1,41 +1,58 @@ | |||||||
| using System; | using System; | ||||||
| using System.IO; | using System.IO; | ||||||
| using System.Reactive.Linq; | using System.Reactive.Linq; | ||||||
|  | using System.Text.RegularExpressions; | ||||||
|  | using ReactiveUI; | ||||||
| using Splat; | using Splat; | ||||||
| using StarsAssistant.Helpers; | using StarsAssistant.Helpers; | ||||||
|  |  | ||||||
| namespace StarsAssistant.Services; | namespace StarsAssistant.Services; | ||||||
|  |  | ||||||
|  |  | ||||||
| public class CSVDataLoader  | public partial class CSVDataLoader : IEnableLogger | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Reference to the game metadata, retrieved by DI |     /// Reference to the game metadata, retrieved by DI | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     protected Services.Game Game = Locator.Current.GetService<Services.Game>()!; |     protected Services.Game Game = Locator.Current.GetService<Services.Game>()!; | ||||||
|  |  | ||||||
|     public void CSVDataLoader()  |     [GeneratedRegex(@".*\.(?<type>[pf])(?<player>\d)+$")] | ||||||
|  |     private static partial Regex MyRegex(); | ||||||
|  |  | ||||||
|  |     protected Regex FileTypeRegEx = MyRegex(); | ||||||
|  |  | ||||||
|  |     public CSVDataLoader()  | ||||||
|     { |     { | ||||||
|          |          | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void StartPlanetCSVWatcher()  |     public void StartPlanetCSVWatcher()  | ||||||
|     { |     { | ||||||
|         // TODO: which scheduler for Throttle? |         // string[] filters = { "*.p*", "*.f*", "*.map" }; | ||||||
|         var watcher = FsWatcher |  | ||||||
|             .ObserveFileSystem(Game.GamePath, new string[] { Game.PlanetFileSearchPattern }); |  | ||||||
|             .ThrottleAndDistinct(2); |  | ||||||
|          |  | ||||||
|         /* |  | ||||||
|         watcher.Subscribe(x =>  |  | ||||||
|         { |  | ||||||
|             Console.WriteLine($"{DateTime.Now.ToLongTimeString()} got {x.Count()} events:"); |  | ||||||
|  |  | ||||||
|             foreach (var fsEvent in x) |         var watcher = FsWatcher | ||||||
|             { |             .ObserveFileSystem(Game.GamePath, [ Game.PlanetFileSearchPattern ]) | ||||||
|                 Console.WriteLine($"{DateTime.Now.ToLongTimeString()} {i++} {fsEvent.FullPath} - {fsEvent.ChangeType}"); |             .ThrottleAndDistinct(2, RxApp.TaskpoolScheduler) | ||||||
|             } |             .Log(this, $"{DateTime.Now.ToLongTimeString()} FsEvent", fsEvent => $"{fsEvent.FullPath} {fsEvent.ChangeType}") | ||||||
|         }); |             .ObserveOn(RxApp.TaskpoolScheduler); | ||||||
|         */ |          | ||||||
|  |         watcher.Subscribe(fsEvent => this.LoadPlanetFile(fsEvent.FullPath)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected void LoadPlanetFile(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}"); | ||||||
|  |         var loader = new CSV.PlanetLoader(); | ||||||
|  |         loader.ImportForRace(Model.Race.Player); | ||||||
|     } |     } | ||||||
| }    | }    | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user