Skip to content

Instantly share code, notes, and snippets.

@dwcullop
Created January 3, 2024 01:18
Show Gist options
  • Save dwcullop/8282abaf55282be7ca11b38d1878c7f9 to your computer and use it in GitHub Desktop.
Save dwcullop/8282abaf55282be7ca11b38d1878c7f9 to your computer and use it in GitHub Desktop.
Represent the file system as an Observable ChangeSet
using System.Reactive.Disposables;
using System.Reactive.Linq;
using DynamicData;
namespace DareWare.Utils;
public static class FileSystemObservable
{
public static IObservable<IChangeSet<FileSystemInfo, string>> Create(string path, string filter, bool includeSubDirectories, bool includeError = true) =>
Observable.Create<IChangeSet<FileSystemInfo, string>>(observer =>
{
var fsw = new FileSystemWatcher(path, filter)
{
IncludeSubdirectories = includeSubDirectories,
EnableRaisingEvents = true
};
var sub = fsw.AsObservableChangeSet().SubscribeSafe(observer);
var errorSub = includeError
? fsw.ObserveError().Subscribe(args => observer.OnError(args.GetException()))
: Disposable.Empty;
return new CompositeDisposable(sub, errorSub, fsw);
});
public static IObservable<IChangeSet<FileSystemInfo, string>> AsObservableChangeSet(this FileSystemWatcher fsw) =>
ObservableChangeSet.Create<FileSystemInfo, string>(cache =>
{
cache.Edit(updater =>
updater.AddOrUpdate(
Directory.EnumerateFileSystemEntries(fsw.Path, fsw.Filter, fsw.IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.Select(p => GetInfo(p))));
return Observable.Merge(
fsw.ObserveChanged().Select(OnChanged),
fsw.ObserveCreated().Select(OnCreated),
fsw.ObserveDeleted().Select(OnDeleted),
fsw.ObserveRenamed().Select(OnRenamed))
.Subscribe(cache.Edit);
},
fsi => fsi.FullName);
private static FileSystemInfo GetInfo(string fullPath) =>
Directory.Exists(fullPath) ? new DirectoryInfo(fullPath) : new FileInfo(fullPath);
private static Action<ISourceUpdater<FileSystemInfo, string>> OnChanged(FileSystemEventArgs args) =>
updater => updater.AddOrUpdate(GetInfo(args.FullPath));
private static Action<ISourceUpdater<FileSystemInfo, string>> OnCreated(FileSystemEventArgs args) =>
updater => updater.AddOrUpdate(GetInfo(args.FullPath));
private static Action<ISourceUpdater<FileSystemInfo, string>> OnDeleted(FileSystemEventArgs args) =>
updater => updater.RemoveKey(args.FullPath);
private static Action<ISourceUpdater<FileSystemInfo, string>> OnRenamed(RenamedEventArgs args) =>
updater =>
{
updater.RemoveKey(args.OldFullPath);
updater.AddOrUpdate(GetInfo(args.FullPath));
};
private static IObservable<FileSystemEventArgs> ObserveChanged(this FileSystemWatcher watcher) =>
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
o => watcher.Changed += o,
o => watcher.Changed -= o)
.Select(args => args.EventArgs);
private static IObservable<FileSystemEventArgs> ObserveCreated(this FileSystemWatcher watcher) =>
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
o => watcher.Created += o,
o => watcher.Created -= o)
.Select(args => args.EventArgs);
private static IObservable<FileSystemEventArgs> ObserveDeleted(this FileSystemWatcher watcher) =>
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
o => watcher.Deleted += o,
o => watcher.Deleted -= o)
.Select(args => args.EventArgs);
private static IObservable<RenamedEventArgs> ObserveRenamed(this FileSystemWatcher watcher) =>
Observable.FromEventPattern<RenamedEventHandler, RenamedEventArgs>(
o => watcher.Renamed += o,
o => watcher.Renamed -= o)
.Select(args => args.EventArgs);
private static IObservable<ErrorEventArgs> ObserveError(this FileSystemWatcher watcher) =>
Observable.FromEventPattern<ErrorEventHandler, ErrorEventArgs>(
o => watcher.Error += o,
o => watcher.Error -= o)
.Select(args => args.EventArgs);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment