| File: Util\FSWGen.cs | Web Access |
| Project: src\runtime\src\tools\hotreload-delta-gen\Microsoft.DotNet.HotReload.Utils.Generator\Microsoft.DotNet.HotReload.Utils.Generator.csproj (Microsoft.DotNet.HotReload.Utils.Generator) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; namespace Microsoft.DotNet.HotReload.Utils.Generator.Util; public class FSWGen : IDisposable { Channel<System.IO.FileSystemEventArgs>? _channel; readonly System.IO.FileSystemWatcher _fsw; public FSWGen (string directoryPath, string filter) { _channel = Channel.CreateUnbounded<System.IO.FileSystemEventArgs> (new UnboundedChannelOptions { SingleReader = true, AllowSynchronousContinuations = true}); _fsw = new System.IO.FileSystemWatcher(directoryPath, filter) { NotifyFilter = System.IO.NotifyFilters.LastWrite /* FIXME: generalize */ }; _fsw.Changed += OnChanged; // _fsw.Created += OnChanged; // _fsw.Deleted += OnChanged; // FIXME: deletion is interesting, actually } private void OnChanged (object sender, System.IO.FileSystemEventArgs eventArgs) { _channel?.Writer.WriteAsync (eventArgs).AsTask().Wait(); } ~FSWGen () => Dispose (false); public void Dispose () { Dispose (true); GC.SuppressFinalize (this); } public virtual void Dispose (bool disposing) { if (disposing) { _fsw.EnableRaisingEvents = false; _fsw.Dispose(); _channel?.Writer.Complete(); _channel = null; } } enum WhenAnyResult { Completion, Read } public async IAsyncEnumerable<System.IO.FileSystemEventArgs> Watch ([EnumeratorCancellation] CancellationToken cancellationToken = default) { try { _fsw.EnableRaisingEvents = true; var completion = _channel!.Reader.Completion.ContinueWith((t) => WhenAnyResult.Completion); while (true) { var readOne = _channel!.Reader.ReadAsync(cancellationToken).AsTask(); Task<WhenAnyResult> t = await Task.WhenAny(completion, readOne.ContinueWith((t) => WhenAnyResult.Read)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); switch (t.Result) { case WhenAnyResult.Completion: yield break; case WhenAnyResult.Read: yield return readOne.Result; break; } } } finally { var fsw = _fsw; if (fsw != null) fsw.EnableRaisingEvents = false; } } }