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 StarsAssistant.ViewModels;
 | 
			
		||||
using StarsAssistant.Views;
 | 
			
		||||
using Splat;
 | 
			
		||||
 | 
			
		||||
namespace StarsAssistant;
 | 
			
		||||
 | 
			
		||||
@@ -23,6 +24,9 @@ public partial class App : Application
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var csvloader = Locator.Current.GetService<Services.CSVDataLoader>()!;
 | 
			
		||||
        csvloader.StartPlanetCSVWatcher();
 | 
			
		||||
 | 
			
		||||
        base.OnFrameworkInitializationCompleted();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -66,19 +66,25 @@ public class PlanetLoader
 | 
			
		||||
                    r = db.Race.Find(owner.Key);
 | 
			
		||||
                    if (r == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        r = new()
 | 
			
		||||
                        {
 | 
			
		||||
                            Name = owner.Key
 | 
			
		||||
                        };
 | 
			
		||||
                        r = new() { Name = owner.Key };
 | 
			
		||||
                        db.Add(r);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                foreach (Planet csvp in owner)
 | 
			
		||||
                {
 | 
			
		||||
                    Model.Planet p = new Model.Planet{ Name = csvp.Name };
 | 
			
		||||
                    csvp.UpdateDbPlanet(p);
 | 
			
		||||
                    db.Add(p);
 | 
			
		||||
                    Model.Planet? p = db.Planet.Find(csvp.Name);
 | 
			
		||||
                    if (p == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        p = new() { Name = csvp.Name };
 | 
			
		||||
                        csvp.UpdateDbPlanet(p);
 | 
			
		||||
                        db.Add(p);
 | 
			
		||||
                    } 
 | 
			
		||||
                    else 
 | 
			
		||||
                    {
 | 
			
		||||
                        csvp.UpdateDbPlanet(p);
 | 
			
		||||
                        db.Update(p);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                db.SaveChanges();
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,28 +3,8 @@ using System.Reactive.Concurrency;
 | 
			
		||||
 | 
			
		||||
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>
 | 
			
		||||
    /// Helper to convert a FileSystemWatcher into an obervable stream. See FileSystemWatcher
 | 
			
		||||
    /// documentation for further details on the parameters.
 | 
			
		||||
@@ -52,6 +32,7 @@ public class FsWatcher
 | 
			
		||||
                    if (filters != null)
 | 
			
		||||
                        foreach (string filter in filters)
 | 
			
		||||
                            fsw.Filters.Add(filter);
 | 
			
		||||
                            
 | 
			
		||||
                    if (notifyFilter != null)
 | 
			
		||||
                        fsw.NotifyFilter = (NotifyFilters) notifyFilter;
 | 
			
		||||
                    fsw.EnableRaisingEvents = true;
 | 
			
		||||
@@ -90,4 +71,29 @@ public class FsWatcher
 | 
			
		||||
                .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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <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);
 | 
			
		||||
 | 
			
		||||
        var logger = new ConsoleLogger() { Level = LogLevel.Debug };
 | 
			
		||||
        Locator.CurrentMutable.RegisterConstant(logger, typeof(ILogger));
 | 
			
		||||
 | 
			
		||||
        Services.Game g = new()
 | 
			
		||||
        {
 | 
			
		||||
            BaseName = "GOINGTH",
 | 
			
		||||
@@ -31,6 +34,7 @@ sealed class Program
 | 
			
		||||
        Locator.CurrentMutable.RegisterConstant(g, typeof(Services.Game));
 | 
			
		||||
        Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader));
 | 
			
		||||
        Locator.CurrentMutable.Register(() => new StarsDatabase(g.DatabaseFileName), typeof(StarsDatabase));
 | 
			
		||||
        Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader));
 | 
			
		||||
 | 
			
		||||
        __createTestData();
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +1,58 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Reactive.Linq;
 | 
			
		||||
using System.Text.RegularExpressions;
 | 
			
		||||
using ReactiveUI;
 | 
			
		||||
using Splat;
 | 
			
		||||
using StarsAssistant.Helpers;
 | 
			
		||||
 | 
			
		||||
namespace StarsAssistant.Services;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class CSVDataLoader 
 | 
			
		||||
public partial class CSVDataLoader : IEnableLogger
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Reference to the game metadata, retrieved by DI
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    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() 
 | 
			
		||||
    {
 | 
			
		||||
        // TODO: which scheduler for Throttle?
 | 
			
		||||
        var watcher = FsWatcher
 | 
			
		||||
            .ObserveFileSystem(Game.GamePath, new string[] { Game.PlanetFileSearchPattern });
 | 
			
		||||
            .ThrottleAndDistinct(2);
 | 
			
		||||
        
 | 
			
		||||
        /*
 | 
			
		||||
        watcher.Subscribe(x => 
 | 
			
		||||
        {
 | 
			
		||||
            Console.WriteLine($"{DateTime.Now.ToLongTimeString()} got {x.Count()} events:");
 | 
			
		||||
        // string[] filters = { "*.p*", "*.f*", "*.map" };
 | 
			
		||||
 | 
			
		||||
            foreach (var fsEvent in x)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"{DateTime.Now.ToLongTimeString()} {i++} {fsEvent.FullPath} - {fsEvent.ChangeType}");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        */
 | 
			
		||||
        var watcher = FsWatcher
 | 
			
		||||
            .ObserveFileSystem(Game.GamePath, [ Game.PlanetFileSearchPattern ])
 | 
			
		||||
            .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