From 24f9a56770082052c4b138386b52edd66a03d675 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 23 Jun 2021 20:44:26 +0100 Subject: [PATCH 01/39] WIP FileSystemWatcher factory --- .../WatchDirectory/WatchDirectory.cs | 26 ++++++++++++++ .../Bookmarks/WatchDirectoryBookmark.cs | 34 +++++++++++++++++++ .../Extensions/ServiceCollectionExtensions.cs | 3 +- .../Services/FileSystemWatcherFactory.cs | 12 +++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs create mode 100644 src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs create mode 100644 src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs new file mode 100644 index 000000000..ea8bd9e18 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs @@ -0,0 +1,26 @@ +using Elsa.ActivityResults; +using Elsa.Attributes; +using Elsa.Services; +using Elsa.Services.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Activities.File +{ + [Trigger(Category = "File", + Description = "Triggers when files are created/modified in the given folder", + Outcomes = new[] { OutcomeNames.Done })] + public class WatchDirectory : Activity + { + [ActivityInput(Hint = "The path of the directory to watch")] + public string Path { get; set; } + + protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) + { + return base.OnExecute(context); + } + } +} diff --git a/src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs new file mode 100644 index 000000000..67843f9e8 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs @@ -0,0 +1,34 @@ +using Elsa.Services.Bookmarks; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Activities.File.Bookmarks +{ + public class WatchDirectoryBookmark : IBookmark + { + public WatchDirectoryBookmark() + { } + + public WatchDirectoryBookmark(string path) + { + Path = path; + } + + public string Path { get; set; } + } + + public class WatchDirectoryBookmarkProvider : BookmarkProvider + { + public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) => + new[] + { + Result(new WatchDirectoryBookmark() + { + Path = (await context.ReadActivityPropertyAsync(a => a.Path)) + }) + }; + } +} diff --git a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs index a3f32f523..a1ddbd50c 100644 --- a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs @@ -24,7 +24,8 @@ namespace Microsoft.Extensions.DependencyInjection .AddActivity() .AddActivity() .AddActivity() - .AddActivity(); + .AddActivity() + .AddActivity(); return builder; } diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs new file mode 100644 index 000000000..6b707e2c9 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Elsa.Activities.File.Services +{ + public class FileSystemWatcherFactory + { + private readonly IDictionary _watchers = new Dictionary(); + } +} From bd546068e587277618f487b8a7286f9ba0c33d79 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 21:30:48 +0100 Subject: [PATCH 02/39] Added pattern to watchdirectory --- .../Activities/WatchDirectory/WatchDirectory.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs index ea8bd9e18..7a498965a 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs @@ -18,6 +18,9 @@ namespace Elsa.Activities.File [ActivityInput(Hint = "The path of the directory to watch")] public string Path { get; set; } + [ActivityInput(Hint = "The file pattern for interested files")] + public string Pattern { get; set; } + protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) { return base.OnExecute(context); From d1cc26fd0fca28987e8971046e92303ca8d00292 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 21:31:02 +0100 Subject: [PATCH 03/39] Added pattern extensions --- .../WatchDirectoryExtensions.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs new file mode 100644 index 000000000..9c4818013 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs @@ -0,0 +1,24 @@ +using Elsa.Builders; +using Elsa.Services.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Activities.File +{ + public static class WatchDirectoryExtensions + { + public static ISetupActivity WithPath(this ISetupActivity setup, Func> path) => setup.Set(x => x.Path, path); + public static ISetupActivity WithPath(this ISetupActivity setup, Func path) => setup.Set(x => x.Path, path); + public static ISetupActivity WithPath(this ISetupActivity setup, Func> path) => setup.Set(x => x.Path, path); + public static ISetupActivity WithPath(this ISetupActivity setup, Func path) => setup.Set(x => x.Path, path); + public static ISetupActivity WithPath(this ISetupActivity setup, string? path) => setup.Set(x => x.Path, path); + + public static ISetupActivity WithPattern(this ISetupActivity setup, Func> pattern) => setup.Set(x => x.Pattern, pattern); + public static ISetupActivity WithPattern(this ISetupActivity setup, Func pattern) => setup.Set(x => x.Pattern, pattern); + public static ISetupActivity WithPattern(this ISetupActivity setup, Func> pattern) => setup.Set(x => x.Pattern, pattern); + public static ISetupActivity WithPattern(this ISetupActivity setup, Func pattern) => setup.Set(x => x.Pattern, pattern); + public static ISetupActivity WithPattern(this ISetupActivity setup, string? pattern) => setup.Set(x => x.Pattern, pattern); + } +} From 0346658f6b52e8b7c7642a7d2efe5ed92041cc26 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 21:32:02 +0100 Subject: [PATCH 04/39] Added regions --- .../Activities/WatchDirectory/WatchDirectoryExtensions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs index 9c4818013..e0a79e4f9 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs @@ -9,16 +9,20 @@ namespace Elsa.Activities.File { public static class WatchDirectoryExtensions { + #region Path public static ISetupActivity WithPath(this ISetupActivity setup, Func> path) => setup.Set(x => x.Path, path); public static ISetupActivity WithPath(this ISetupActivity setup, Func path) => setup.Set(x => x.Path, path); public static ISetupActivity WithPath(this ISetupActivity setup, Func> path) => setup.Set(x => x.Path, path); public static ISetupActivity WithPath(this ISetupActivity setup, Func path) => setup.Set(x => x.Path, path); public static ISetupActivity WithPath(this ISetupActivity setup, string? path) => setup.Set(x => x.Path, path); + #endregion + #region Pattern public static ISetupActivity WithPattern(this ISetupActivity setup, Func> pattern) => setup.Set(x => x.Pattern, pattern); public static ISetupActivity WithPattern(this ISetupActivity setup, Func pattern) => setup.Set(x => x.Pattern, pattern); public static ISetupActivity WithPattern(this ISetupActivity setup, Func> pattern) => setup.Set(x => x.Pattern, pattern); public static ISetupActivity WithPattern(this ISetupActivity setup, Func pattern) => setup.Set(x => x.Pattern, pattern); public static ISetupActivity WithPattern(this ISetupActivity setup, string? pattern) => setup.Set(x => x.Pattern, pattern); + #endregion } } From 4247ff96b1ef0cb648a7c602fa6544fb043da496 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 21:51:53 +0100 Subject: [PATCH 05/39] Initial WatchDirectory builder extensions --- .../WatchDirectoryBuilderExtensions.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryBuilderExtensions.cs diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryBuilderExtensions.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryBuilderExtensions.cs new file mode 100644 index 000000000..aad122344 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryBuilderExtensions.cs @@ -0,0 +1,13 @@ +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Elsa.Activities.File +{ + public static class WatchDirectoryBuilderExtensions + { + public static IActivityBuilder WatchDirectory(this IActivityBuilder builder, Action> setup, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => builder.Then(setup, null, lineNumber, sourceFile); + } +} From ac511378ecf7f957d44369f8ab80ec1b5c28f3ce Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 22:33:38 +0100 Subject: [PATCH 06/39] Added initial file watcher sample project --- Elsa.sln | 7 ++++++ .../Elsa.Samples.WatchDirectoryWorker.csproj | 17 +++++++++++++ .../Program.cs | 25 +++++++++++++++++++ .../Workflows/WatchDirectoryWorkflow.cs | 16 ++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs diff --git a/Elsa.sln b/Elsa.sln index f12ececaf..9e9efc6db 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -336,6 +336,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ElsaDashboard.Samples.Blazo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.HttpEndpointSecurity", "src\samples\aspnet\Elsa.Samples.HttpEndpointSecurity\Elsa.Samples.HttpEndpointSecurity.csproj", "{82B115DA-E3D0-49D7-AD08-DE9387656756}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.WatchDirectoryWorker", "src\samples\worker\Elsa.Samples.WatchDirectoryWorker\Elsa.Samples.WatchDirectoryWorker.csproj", "{8EC3CF51-EBC1-4B45-881E-4B1B8190D579}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -786,6 +788,10 @@ Global {82B115DA-E3D0-49D7-AD08-DE9387656756}.Debug|Any CPU.Build.0 = Debug|Any CPU {82B115DA-E3D0-49D7-AD08-DE9387656756}.Release|Any CPU.ActiveCfg = Release|Any CPU {82B115DA-E3D0-49D7-AD08-DE9387656756}.Release|Any CPU.Build.0 = Release|Any CPU + {8EC3CF51-EBC1-4B45-881E-4B1B8190D579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EC3CF51-EBC1-4B45-881E-4B1B8190D579}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EC3CF51-EBC1-4B45-881E-4B1B8190D579}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EC3CF51-EBC1-4B45-881E-4B1B8190D579}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -934,6 +940,7 @@ Global {DCB3C4DD-2B7D-44E9-A366-F36F4ABFF488} = {D86B94DC-A53C-4A67-A820-828DD359C49B} {9A4B1C48-16FB-4A65-AE98-5CDE7BCB506C} = {D86B94DC-A53C-4A67-A820-828DD359C49B} {82B115DA-E3D0-49D7-AD08-DE9387656756} = {22E75696-6FE9-436A-9097-EE21C603F818} + {8EC3CF51-EBC1-4B45-881E-4B1B8190D579} = {E42743A0-FBDD-4150-9D53-6000496D9B87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj new file mode 100644 index 000000000..44621cbd8 --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj @@ -0,0 +1,17 @@ + + + + Exe + net5.0 + + + + + + + + + + + + diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs new file mode 100644 index 000000000..9c7cbf63b --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs @@ -0,0 +1,25 @@ +using Elsa.Samples.WatchDirectoryWorker.Workflows; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; + +namespace Elsa.Samples.WatchDirectoryWorker +{ + class Program + { + static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureServices((hostContext, services) => + { + services + .AddElsa(options => options + .AddFileActivities() + .AddWorkflow()); + }); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs new file mode 100644 index 000000000..85bec305b --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs @@ -0,0 +1,16 @@ +using Elsa.Activities.File; +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class WatchDirectoryWorkflow : IWorkflow + { + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath("C:\\Temp") + .WithPattern("*.txt")); + } +} From d6ba8c15fb02f717080d50a6cafc704b311e7520 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:02:17 +0100 Subject: [PATCH 07/39] Removed unused factory --- .../Services/FileSystemWatcherFactory.cs | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs deleted file mode 100644 index 6b707e2c9..000000000 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Elsa.Activities.File.Services -{ - public class FileSystemWatcherFactory - { - private readonly IDictionary _watchers = new Dictionary(); - } -} From 45a704f1caded2ab4fbe747dd0ce868d28b1ebb4 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:08:32 +0100 Subject: [PATCH 08/39] Renamed bookmark --- ...rectoryBookmark.cs => FileCreatedBookmark.cs} | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) rename src/activities/Elsa.Activities.File/Bookmarks/{WatchDirectoryBookmark.cs => FileCreatedBookmark.cs} (53%) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs similarity index 53% rename from src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs rename to src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs index 67843f9e8..9306ae950 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/WatchDirectoryBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs @@ -1,3 +1,4 @@ +using Elsa.Services; using Elsa.Services.Bookmarks; using System; using System.Collections.Generic; @@ -7,27 +8,30 @@ using System.Threading.Tasks; namespace Elsa.Activities.File.Bookmarks { - public class WatchDirectoryBookmark : IBookmark + public class FileCreatedBookmark : IBookmark { - public WatchDirectoryBookmark() + public FileCreatedBookmark() { } - public WatchDirectoryBookmark(string path) + public FileCreatedBookmark(string path) { Path = path; } public string Path { get; set; } + + public string Pattern { get; set; } } - public class WatchDirectoryBookmarkProvider : BookmarkProvider + public class FileCreatedBookmarkProvider : BookmarkProvider { public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) => new[] { - Result(new WatchDirectoryBookmark() + Result(new FileCreatedBookmark() { - Path = (await context.ReadActivityPropertyAsync(a => a.Path)) + Path = await context.ReadActivityPropertyAsync(a => a.Path), + Pattern = await context.ReadActivityPropertyAsync(a => a.Pattern) }) }; } From dc3b7d62e0e1876075780812192b7eea6a43e8fc Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:10:41 +0100 Subject: [PATCH 09/39] Added initial FS worker to manage System.IO watcher and hold path and filter --- .../Services/FileSystemWatcherWorker.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs new file mode 100644 index 000000000..d2f3ccc02 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Elsa.Activities.File.Services +{ + public class FileSystemWatcherWorker + { + private readonly ILogger _logger; + private readonly FileSystemWatcher _watcher; + + public FileSystemWatcherWorker(string path, string pattern, ILogger logger) + { + Path = path; + Pattern = pattern; + _watcher = new FileSystemWatcher() + { + Path = path, + Filter = pattern + }; + _watcher.Created += FileCreated; + _watcher.Changed += FileChanged; + _watcher.EnableRaisingEvents = true; + } + + public string Path { get; private set; } + + public string Pattern { get; private set; } + + private void FileChanged(object sender, FileSystemEventArgs e) + { + } + + private void FileCreated(object sender, FileSystemEventArgs e) + { + } + } +} From eba4d96653f6c06ae9019b5f5e7b724823358fa7 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:12:17 +0100 Subject: [PATCH 10/39] Added singleton service to manage workers --- .../Services/FileSystemWatchersStarter.cs | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs new file mode 100644 index 000000000..0b94cb5c7 --- /dev/null +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -0,0 +1,83 @@ +using Elsa.Services; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Activities.File.Services +{ + public class FileSystemWatchersStarter + { + private readonly ILogger _logger; + private readonly IServiceScopeFactory _scopeactory; + private readonly SemaphoreSlim _semaphore = new(1); + private readonly IServiceProvider _serviceProvider; + private readonly ICollection _workers; + + public FileSystemWatchersStarter(ILogger logger, + IServiceScopeFactory scopeFactory, + IServiceProvider serviceProvider) + { + _logger = logger; + _scopeactory = scopeFactory; + _serviceProvider = serviceProvider; + _workers = new List(); + } + + public async Task CreateWatchersAsync(CancellationToken cancellationToken = default) + { + await _semaphore.WaitAsync(); + + try + { + using (var scope = _scopeactory.CreateScope()) + { + var workflowRegistry = scope.ServiceProvider.GetRequiredService(); + var workflowBlueprintReflector = scope.ServiceProvider.GetRequiredService(); + var workflows = await workflowRegistry.ListActiveAsync(cancellationToken); + + var query = from workflow in workflows + from activity in workflow.Activities + where activity.Type == nameof(WatchDirectory) + select workflow; + + foreach (var workflow in query) + { + var workflowBlueprintWrapper = await workflowBlueprintReflector.ReflectAsync(scope.ServiceProvider, workflow, cancellationToken); + + foreach (var activity in workflowBlueprintWrapper.Filter()) + { + var path = await activity.EvaluatePropertyValueAsync(x => x.Path, cancellationToken); + var pattern = await activity.EvaluatePropertyValueAsync(x => x.Pattern, cancellationToken); + CreateAndAddWatcher(path, pattern); + } + } + } + } + finally + { + _semaphore.Release(); + } + } + + private void CreateAndAddWatcher(string path, string pattern) + { + try + { + var worker = ActivatorUtilities.CreateInstance(_serviceProvider, path, pattern); + _workers.Add(worker); + } + finally + { + + } + } + } +} From eadec5289cd6ef5496ccf1a928d86344f199e7c7 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:12:33 +0100 Subject: [PATCH 11/39] set logger in constructor --- .../Elsa.Activities.File/Services/FileSystemWatcherWorker.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs index d2f3ccc02..d93f50236 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs @@ -15,6 +15,7 @@ namespace Elsa.Activities.File.Services { Path = path; Pattern = pattern; + _logger = logger; _watcher = new FileSystemWatcher() { Path = path, From 63d1355c148ec97501babbf6453469247e36e034 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:12:48 +0100 Subject: [PATCH 12/39] Added startup task for watchers --- .../StartupTasks/StartFileSystemWatchers.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs diff --git a/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs b/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs new file mode 100644 index 000000000..33ab6e439 --- /dev/null +++ b/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs @@ -0,0 +1,21 @@ +using Elsa.Activities.File.Services; +using Elsa.Services; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Activities.File.StartupTasks +{ + public class StartFileSystemWatchers : IStartupTask + { + private readonly FileSystemWatchersStarter _starter; + + public StartFileSystemWatchers(FileSystemWatchersStarter starter) => _starter = starter; + + public int Order => 2000; + + public Task ExecuteAsync(CancellationToken cancellationToken = default) => _starter.CreateWatchersAsync(cancellationToken); + } +} From 42d38a80418421238ff3083e6a054a17a7d6df4d Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Thu, 2 Sep 2021 23:13:28 +0100 Subject: [PATCH 13/39] Added services, startup and bookmark to file sc extensions --- .../Extensions/ServiceCollectionExtensions.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs index 72c4e0002..4ec03f895 100644 --- a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs @@ -1,5 +1,9 @@ using Elsa; using Elsa.Activities.File; +using Elsa.Activities.File.Bookmarks; +using Elsa.Activities.File.Services; +using Elsa.Activities.File.StartupTasks; +using Elsa.Runtime; using System; // ReSharper disable once CheckNamespace @@ -25,6 +29,10 @@ namespace Microsoft.Extensions.DependencyInjection .AddActivity() .AddActivity(); + builder.Services.AddSingleton() + .AddBookmarkProvider() + .AddStartupTask(); + return builder; } } From 106a431216374b38386dfa399165f0e049e445ba Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 3 Sep 2021 22:12:10 +0100 Subject: [PATCH 14/39] Added FileSystemEvent mapper profile --- .../Extensions/ServiceCollectionExtensions.cs | 6 +++-- .../MapperProfiles/FileSystemEventProfile.cs | 27 +++++++++++++++++++ ...ileSystemChanged.cs => FileSystemEvent.cs} | 6 ++--- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs rename src/activities/Elsa.Activities.File/Models/{FileSystemChanged.cs => FileSystemEvent.cs} (76%) diff --git a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs index a860abfba..ab4ec046d 100644 --- a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs @@ -6,6 +6,7 @@ using Elsa.Activities.File.StartupTasks; using Elsa.Runtime; using System; using Elsa.Options; +using Elsa.Activities.File.MapperProfiles; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -30,8 +31,9 @@ namespace Microsoft.Extensions.DependencyInjection .AddActivity() .AddActivity(); - builder.Services.AddSingleton() - .AddBookmarkProvider() + builder.Services.AddBookmarkProvider() + .AddAutoMapperProfile() + .AddSingleton() .AddStartupTask(); return builder; diff --git a/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs b/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs new file mode 100644 index 000000000..41c3ba037 --- /dev/null +++ b/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs @@ -0,0 +1,27 @@ +using AutoMapper; +using Elsa.Activities.File.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Elsa.Activities.File.MapperProfiles +{ + public class FileSystemEventProfile : Profile + { + public FileSystemEventProfile() + { + CreateMap() + .ForMember(d => d.ChangeType, + o => o.MapFrom(s => s.ChangeType)) + .ForMember(d => d.Directory, + o => o.MapFrom(s => Path.GetDirectoryName(s.FullPath))) + .ForMember(d => d.FileName, + o => o.MapFrom(s => s.Name)) + .ForMember(d => d.FullPath, + o => o.MapFrom(s => s.FullPath)) + .ForMember(d => d.TimeStamp, + o => o.MapFrom(s => DateTime.Now)); + } + } +} diff --git a/src/activities/Elsa.Activities.File/Models/FileSystemChanged.cs b/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs similarity index 76% rename from src/activities/Elsa.Activities.File/Models/FileSystemChanged.cs rename to src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs index 37d1ab4c9..09f763b90 100644 --- a/src/activities/Elsa.Activities.File/Models/FileSystemChanged.cs +++ b/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs @@ -3,13 +3,13 @@ using System.IO; namespace Elsa.Activities.File.Models { - public class FileSystemChanged + public class FileSystemEvent { - public FileSystemChanged() + public FileSystemEvent() { } - public FileSystemChanged(WatcherChangeTypes changeType, string directory, string fileName, string fullPath) + public FileSystemEvent(WatcherChangeTypes changeType, string directory, string fileName, string fullPath) { ChangeType = changeType; Directory = directory; From a2f2b9d9b304d1fcbada80c925228b2866e017b0 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 3 Sep 2021 22:15:44 +0100 Subject: [PATCH 15/39] Added mapping system io event model to custom model --- .../Services/FileSystemWatcherWorker.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs index d93f50236..bb3381dc2 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs @@ -1,3 +1,5 @@ +using AutoMapper; +using Elsa.Activities.File.Models; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -9,13 +11,15 @@ namespace Elsa.Activities.File.Services public class FileSystemWatcherWorker { private readonly ILogger _logger; + private readonly IMapper _mapper; private readonly FileSystemWatcher _watcher; - public FileSystemWatcherWorker(string path, string pattern, ILogger logger) + public FileSystemWatcherWorker(string path, string pattern, ILogger logger, IMapper mapper) { Path = path; Pattern = pattern; _logger = logger; + _mapper = mapper; _watcher = new FileSystemWatcher() { Path = path, @@ -32,10 +36,12 @@ namespace Elsa.Activities.File.Services private void FileChanged(object sender, FileSystemEventArgs e) { + var model = _mapper.Map(e); } private void FileCreated(object sender, FileSystemEventArgs e) { + var model = _mapper.Map(e); } } } From 4b4491b559237edd8ed27a2c6b89ffb222be68d2 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 3 Sep 2021 22:18:38 +0100 Subject: [PATCH 16/39] Added IWorkflowLaunchpad to FS watcher worker --- .../Extensions/ServiceCollectionExtensions.cs | 2 ++ .../Services/FileSystemWatcherWorker.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs index ab4ec046d..f588bdb6b 100644 --- a/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs +++ b/src/activities/Elsa.Activities.File/Extensions/ServiceCollectionExtensions.cs @@ -7,6 +7,7 @@ using Elsa.Runtime; using System; using Elsa.Options; using Elsa.Activities.File.MapperProfiles; +using Elsa.Services; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -34,6 +35,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.AddBookmarkProvider() .AddAutoMapperProfile() .AddSingleton() + .AddSingleton>() .AddStartupTask(); return builder; diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs index bb3381dc2..449f61306 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs @@ -1,5 +1,6 @@ using AutoMapper; using Elsa.Activities.File.Models; +using Elsa.Services; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -13,13 +14,19 @@ namespace Elsa.Activities.File.Services private readonly ILogger _logger; private readonly IMapper _mapper; private readonly FileSystemWatcher _watcher; + private readonly Scoped _workflowLaunchpad; - public FileSystemWatcherWorker(string path, string pattern, ILogger logger, IMapper mapper) + public FileSystemWatcherWorker(string path, + string pattern, + ILogger logger, + IMapper mapper, + Scoped workflowLaunchpad) { Path = path; Pattern = pattern; _logger = logger; _mapper = mapper; + _workflowLaunchpad = workflowLaunchpad; _watcher = new FileSystemWatcher() { Path = path, From 1d2801f3e04e18c089e6f6dea347b50dfd79671d Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 3 Sep 2021 22:46:14 +0100 Subject: [PATCH 17/39] Added pattern to FS bookment --- .../Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs index 9306ae950..4636f46ca 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs @@ -13,9 +13,10 @@ namespace Elsa.Activities.File.Bookmarks public FileCreatedBookmark() { } - public FileCreatedBookmark(string path) + public FileCreatedBookmark(string path, string pattern) { Path = path; + Pattern = pattern; } public string Path { get; set; } From 5900cc9fd8b55950cc9e14529cf60773b91bca1d Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 3 Sep 2021 22:47:11 +0100 Subject: [PATCH 18/39] Added launching workflow from fs event handler --- .../Services/FileSystemWatcherWorker.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs index 449f61306..4d8e8bc33 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs @@ -1,6 +1,9 @@ using AutoMapper; +using Elsa.Activities.File.Bookmarks; using Elsa.Activities.File.Models; +using Elsa.Models; using Elsa.Services; +using Elsa.Services.Models; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -33,7 +36,6 @@ namespace Elsa.Activities.File.Services Filter = pattern }; _watcher.Created += FileCreated; - _watcher.Changed += FileChanged; _watcher.EnableRaisingEvents = true; } @@ -41,14 +43,12 @@ namespace Elsa.Activities.File.Services public string Pattern { get; private set; } - private void FileChanged(object sender, FileSystemEventArgs e) - { - var model = _mapper.Map(e); - } - private void FileCreated(object sender, FileSystemEventArgs e) { var model = _mapper.Map(e); + var bookmark = new FileCreatedBookmark(Path, Pattern); + var launchContext = new WorkflowsQuery(nameof(WatchDirectory), bookmark); + _workflowLaunchpad.UseService(s => s.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model))); } } } From beddedae29ee95c70f38a81157595a7cbbf22332 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 21:00:22 +0100 Subject: [PATCH 19/39] Added output to activity --- .../Activities/WatchDirectory/WatchDirectory.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs index 7a498965a..50937fd3b 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs @@ -1,3 +1,4 @@ +using Elsa.Activities.File.Models; using Elsa.ActivityResults; using Elsa.Attributes; using Elsa.Services; @@ -21,9 +22,14 @@ namespace Elsa.Activities.File [ActivityInput(Hint = "The file pattern for interested files")] public string Pattern { get; set; } + [ActivityOutput] + public FileSystemEvent? Output { get; set; } + protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) { - return base.OnExecute(context); + var model = (FileSystemEvent)context.Input!; + Output = model; + return Done(); } } } From 0e736e7099ebf430986ef528356e3856a94c1408 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 22:16:05 +0100 Subject: [PATCH 20/39] Created separate helper to return blueprint instances of an activity --- .../Services/FileSystemWatchersStarter.cs | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index 0b94cb5c7..dc37d92ba 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -1,4 +1,5 @@ using Elsa.Services; +using Elsa.Services.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -16,7 +17,7 @@ namespace Elsa.Activities.File.Services public class FileSystemWatchersStarter { private readonly ILogger _logger; - private readonly IServiceScopeFactory _scopeactory; + private readonly IServiceScopeFactory _scopeFactory; private readonly SemaphoreSlim _semaphore = new(1); private readonly IServiceProvider _serviceProvider; private readonly ICollection _workers; @@ -26,7 +27,7 @@ namespace Elsa.Activities.File.Services IServiceProvider serviceProvider) { _logger = logger; - _scopeactory = scopeFactory; + _scopeFactory = scopeFactory; _serviceProvider = serviceProvider; _workers = new List(); } @@ -37,28 +38,12 @@ namespace Elsa.Activities.File.Services try { - using (var scope = _scopeactory.CreateScope()) + var activities = GetActivityInstancesAsync(cancellationToken); + await foreach (var a in activities) { - var workflowRegistry = scope.ServiceProvider.GetRequiredService(); - var workflowBlueprintReflector = scope.ServiceProvider.GetRequiredService(); - var workflows = await workflowRegistry.ListActiveAsync(cancellationToken); - - var query = from workflow in workflows - from activity in workflow.Activities - where activity.Type == nameof(WatchDirectory) - select workflow; - - foreach (var workflow in query) - { - var workflowBlueprintWrapper = await workflowBlueprintReflector.ReflectAsync(scope.ServiceProvider, workflow, cancellationToken); - - foreach (var activity in workflowBlueprintWrapper.Filter()) - { - var path = await activity.EvaluatePropertyValueAsync(x => x.Path, cancellationToken); - var pattern = await activity.EvaluatePropertyValueAsync(x => x.Pattern, cancellationToken); - CreateAndAddWatcher(path, pattern); - } - } + var path = await a.EvaluatePropertyValueAsync(x => x.Path, cancellationToken); + var pattern = await a.EvaluatePropertyValueAsync(x => x.Pattern, cancellationToken); + CreateAndAddWatcher(path, pattern); } } finally @@ -79,5 +64,30 @@ namespace Elsa.Activities.File.Services } } + + private async IAsyncEnumerable> GetActivityInstancesAsync([EnumeratorCancellation] CancellationToken cancellationToken) where TActivity : IActivity + { + using (var scope = _scopeFactory.CreateScope()) + { + var workflowRegistry = scope.ServiceProvider.GetRequiredService(); + var workflowBlueprintReflector = scope.ServiceProvider.GetRequiredService(); + var workflows = await workflowRegistry.ListActiveAsync(cancellationToken); + + var query = from workflow in workflows + from activity in workflow.Activities + where activity.Type == nameof(WatchDirectory) + select workflow; + + foreach (var workflow in query) + { + var workflowBlueprintWrapper = await workflowBlueprintReflector.ReflectAsync(scope.ServiceProvider, workflow, cancellationToken); + + foreach (var activity in workflowBlueprintWrapper.Filter()) + { + yield return activity; + } + } + } + } } } From 1d6549f13271fefa1b87c9e800e1e5b2a821576d Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 22:26:37 +0100 Subject: [PATCH 21/39] Rename startup method --- .../Elsa.Activities.File/Services/FileSystemWatchersStarter.cs | 2 +- .../StartupTasks/StartFileSystemWatchers.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index dc37d92ba..e0961feb4 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -32,7 +32,7 @@ namespace Elsa.Activities.File.Services _workers = new List(); } - public async Task CreateWatchersAsync(CancellationToken cancellationToken = default) + public async Task CreateAndAddWatchersAsync(CancellationToken cancellationToken = default) { await _semaphore.WaitAsync(); diff --git a/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs b/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs index 33ab6e439..190c73a5a 100644 --- a/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs +++ b/src/activities/Elsa.Activities.File/StartupTasks/StartFileSystemWatchers.cs @@ -16,6 +16,6 @@ namespace Elsa.Activities.File.StartupTasks public int Order => 2000; - public Task ExecuteAsync(CancellationToken cancellationToken = default) => _starter.CreateWatchersAsync(cancellationToken); + public Task ExecuteAsync(CancellationToken cancellationToken = default) => _starter.CreateAndAddWatchersAsync(cancellationToken); } } From 5b3e999430597246e24f65810c02ba149553f4d8 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 23:01:01 +0100 Subject: [PATCH 22/39] Removed need for worker by using sender to build watch directory bookmark --- .../Services/FileSystemWatcherWorker.cs | 54 ------------------- .../Services/FileSystemWatchersStarter.cs | 45 +++++++++++++--- 2 files changed, 38 insertions(+), 61 deletions(-) delete mode 100644 src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs deleted file mode 100644 index 4d8e8bc33..000000000 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatcherWorker.cs +++ /dev/null @@ -1,54 +0,0 @@ -using AutoMapper; -using Elsa.Activities.File.Bookmarks; -using Elsa.Activities.File.Models; -using Elsa.Models; -using Elsa.Services; -using Elsa.Services.Models; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Elsa.Activities.File.Services -{ - public class FileSystemWatcherWorker - { - private readonly ILogger _logger; - private readonly IMapper _mapper; - private readonly FileSystemWatcher _watcher; - private readonly Scoped _workflowLaunchpad; - - public FileSystemWatcherWorker(string path, - string pattern, - ILogger logger, - IMapper mapper, - Scoped workflowLaunchpad) - { - Path = path; - Pattern = pattern; - _logger = logger; - _mapper = mapper; - _workflowLaunchpad = workflowLaunchpad; - _watcher = new FileSystemWatcher() - { - Path = path, - Filter = pattern - }; - _watcher.Created += FileCreated; - _watcher.EnableRaisingEvents = true; - } - - public string Path { get; private set; } - - public string Pattern { get; private set; } - - private void FileCreated(object sender, FileSystemEventArgs e) - { - var model = _mapper.Map(e); - var bookmark = new FileCreatedBookmark(Path, Pattern); - var launchContext = new WorkflowsQuery(nameof(WatchDirectory), bookmark); - _workflowLaunchpad.UseService(s => s.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model))); - } - } -} diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index e0961feb4..c09d9058d 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -1,3 +1,7 @@ +using AutoMapper; +using Elsa.Activities.File.Bookmarks; +using Elsa.Activities.File.Models; +using Elsa.Models; using Elsa.Services; using Elsa.Services.Models; using Microsoft.Extensions.DependencyInjection; @@ -17,19 +21,25 @@ namespace Elsa.Activities.File.Services public class FileSystemWatchersStarter { private readonly ILogger _logger; + private readonly IMapper _mapper; private readonly IServiceScopeFactory _scopeFactory; private readonly SemaphoreSlim _semaphore = new(1); private readonly IServiceProvider _serviceProvider; - private readonly ICollection _workers; + private readonly ICollection _watchers; + private readonly Scoped _workflowLaunchpad; public FileSystemWatchersStarter(ILogger logger, + IMapper mapper, IServiceScopeFactory scopeFactory, - IServiceProvider serviceProvider) + IServiceProvider serviceProvider, + Scoped workflowLaunchpad) { _logger = logger; + _mapper = mapper; _scopeFactory = scopeFactory; _serviceProvider = serviceProvider; - _workers = new List(); + _watchers = new List(); + _workflowLaunchpad = workflowLaunchpad; } public async Task CreateAndAddWatchersAsync(CancellationToken cancellationToken = default) @@ -41,9 +51,10 @@ namespace Elsa.Activities.File.Services var activities = GetActivityInstancesAsync(cancellationToken); await foreach (var a in activities) { + var changeTypes = await a.EvaluatePropertyValueAsync(x => x.ChangeTypes, cancellationToken); var path = await a.EvaluatePropertyValueAsync(x => x.Path, cancellationToken); var pattern = await a.EvaluatePropertyValueAsync(x => x.Pattern, cancellationToken); - CreateAndAddWatcher(path, pattern); + CreateAndAddWatcher(path, pattern, changeTypes); } } finally @@ -52,12 +63,18 @@ namespace Elsa.Activities.File.Services } } - private void CreateAndAddWatcher(string path, string pattern) + private void CreateAndAddWatcher(string path, string pattern, WatcherChangeTypes changeTypes) { try { - var worker = ActivatorUtilities.CreateInstance(_serviceProvider, path, pattern); - _workers.Add(worker); + var watcher = new FileSystemWatcher() + { + Path = path, + Filter = pattern, + }; + watcher.Created += FileCreated; + watcher.EnableRaisingEvents = true; + _watchers.Add(watcher); } finally { @@ -89,5 +106,19 @@ namespace Elsa.Activities.File.Services } } } + + #region Watcher delegates + private void FileCreated(object sender, FileSystemEventArgs e) + { + var watcher = (FileSystemWatcher)sender; + var path = watcher.Path; + var pattern = watcher.Filter; + + var model = _mapper.Map(e); + var bookmark = new FileCreatedBookmark(path, pattern); + var launchContext = new WorkflowsQuery(nameof(WatchDirectory), bookmark); + _workflowLaunchpad.UseService(s => s.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model))); + } + #endregion } } From 33741fa32113d9ce7d48e57cf6ce083754439d83 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 23:25:12 +0100 Subject: [PATCH 23/39] Fixes to watchdirectory sample workflow --- .../Elsa.Samples.WatchDirectoryWorker.csproj | 3 ++- .../worker/Elsa.Samples.WatchDirectoryWorker/Program.cs | 1 + .../Workflows/WatchDirectoryWorkflow.cs | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj index 44621cbd8..7045612b5 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj @@ -1,4 +1,4 @@ - + Exe @@ -10,6 +10,7 @@ + diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs index 9c7cbf63b..2ced8d505 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs @@ -18,6 +18,7 @@ namespace Elsa.Samples.WatchDirectoryWorker { services .AddElsa(options => options + .AddConsoleActivities() .AddFileActivities() .AddWorkflow()); }); diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs index 85bec305b..a12d0fb34 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs @@ -1,4 +1,6 @@ +using Elsa.Activities.Console; using Elsa.Activities.File; +using Elsa.Activities.File.Models; using Elsa.Builders; using System; using System.Collections.Generic; @@ -11,6 +13,7 @@ namespace Elsa.Samples.WatchDirectoryWorker.Workflows public class WatchDirectoryWorkflow : IWorkflow { public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath("C:\\Temp") - .WithPattern("*.txt")); + .WithPattern("*.txt")) + .WriteLine(setup => setup.WithText(async context => context.GetInput().FullPath)); } } From 7cac3b106f0f447a55e03f066a91a53ef74a56b5 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 23:44:09 +0100 Subject: [PATCH 24/39] Make bookmark more readable --- .../Bookmarks/FileCreatedBookmark.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs index 4636f46ca..2538f6bda 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs @@ -2,6 +2,7 @@ using Elsa.Services; using Elsa.Services.Bookmarks; using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -26,14 +27,12 @@ namespace Elsa.Activities.File.Bookmarks public class FileCreatedBookmarkProvider : BookmarkProvider { - public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) => - new[] - { - Result(new FileCreatedBookmark() - { - Path = await context.ReadActivityPropertyAsync(a => a.Path), - Pattern = await context.ReadActivityPropertyAsync(a => a.Pattern) - }) - }; + public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) + { + var path = await context.ReadActivityPropertyAsync(a => a.Path); + var pattern = await context.ReadActivityPropertyAsync(a => a.Pattern); + var result = Result(new FileCreatedBookmark(path, pattern)); + return new[] { result }; + } } } From 96c0897265f27580833ac4948c3b5b6d4863d12a Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sun, 5 Sep 2021 23:46:20 +0100 Subject: [PATCH 25/39] Tidy up --- .../Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs index 2538f6bda..d3311f33d 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs @@ -1,9 +1,5 @@ using Elsa.Services; -using Elsa.Services.Bookmarks; -using System; using System.Collections.Generic; -using System.IO; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -35,4 +31,4 @@ namespace Elsa.Activities.File.Bookmarks return new[] { result }; } } -} +} \ No newline at end of file From 1eeaf87c571193a3214701a6c909b321d4805180 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Tue, 7 Sep 2021 15:38:31 +0100 Subject: [PATCH 26/39] Added helper to start watchdirectory workflow --- .../Services/FileSystemWatchersStarter.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index c09d9058d..3265760a0 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -110,7 +110,26 @@ namespace Elsa.Activities.File.Services #region Watcher delegates private void FileCreated(object sender, FileSystemEventArgs e) { - var watcher = (FileSystemWatcher)sender; + StartWorkflow((FileSystemWatcher)sender, e); + } + + private void FileChanged(object sender, FileSystemEventArgs e) + { + if (e.ChangeType != WatcherChangeTypes.Changed) + { + return; + } + + StartWorkflow((FileSystemWatcher)sender, e); + } + + private void FileDeleted(object sender, FileSystemEventArgs e) + { + StartWorkflow((FileSystemWatcher)sender, e); + } + + private void StartWorkflow(FileSystemWatcher watcher, FileSystemEventArgs e) + { var path = watcher.Path; var pattern = watcher.Filter; From f3b10e4f30140f437ddeb7858d06e796e3d7a61f Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Tue, 7 Sep 2021 23:55:51 +0100 Subject: [PATCH 27/39] Added logging appsettings --- .../Elsa.Samples.WatchDirectoryWorker.csproj | 22 ++++++++++++++++++- .../appsettings.json | 15 +++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj index 7045612b5..fdaa1a714 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj @@ -1,10 +1,20 @@ - + Exe net5.0 + + + + + + + PreserveNewest + + + @@ -15,4 +25,14 @@ + + + + + + + PreserveNewest + + + diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json new file mode 100644 index 000000000..8a6b79589 --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Information", + "Microsoft.Hosting.Lifetime": "Information" + }, + "Console": { + "FormatterName": "simple", + "FormatterOptions": { + "TimestampFormat": "yyyy-MM-ddTHH:mm:ss " + } + } + } +} \ No newline at end of file From eae364114a52a454840458e50bd4997cfc13fad6 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:20:23 +0100 Subject: [PATCH 28/39] Added notifyfilters to watchdiretory --- .../WatchDirectory/WatchDirectory.cs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs index 50937fd3b..646794775 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs @@ -1,10 +1,13 @@ using Elsa.Activities.File.Models; using Elsa.ActivityResults; using Elsa.Attributes; +using Elsa.Design; using Elsa.Services; using Elsa.Services.Models; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -16,11 +19,25 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class WatchDirectory : Activity { + [Required] [ActivityInput(Hint = "The path of the directory to watch")] - public string Path { get; set; } + public string? Path { get; set; } [ActivityInput(Hint = "The file pattern for interested files")] - public string Pattern { get; set; } + public string? Pattern { get; set; } + + [ActivityInput(Label = "Change Types", Hint = "The types of file system events to subscribe to", UIHint = ActivityInputUIHints.CheckList, DefaultValue = WatcherChangeTypes.All)] + public WatcherChangeTypes ChangeTypes { get; set; } + + [ActivityInput(Label = "Notify Filters", UIHint = ActivityInputUIHints.CheckList, DefaultValue = NotifyFilters.Attributes | + NotifyFilters.CreationTime | + NotifyFilters.DirectoryName | + NotifyFilters.FileName | + NotifyFilters.LastAccess | + NotifyFilters.LastWrite | + NotifyFilters.Security | + NotifyFilters.Size)] + public NotifyFilters NotifyFilters { get; set; } [ActivityOutput] public FileSystemEvent? Output { get; set; } @@ -29,7 +46,7 @@ namespace Elsa.Activities.File { var model = (FileSystemEvent)context.Input!; Output = model; - return Done(); + return Done(model); } } } From d441fc4c171828ce94dcaa46475f023f77c01268 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:20:46 +0100 Subject: [PATCH 29/39] WatchDirectory additions for changetypes and notifyfilters --- .../WatchDirectory/WatchDirectoryExtensions.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs index e0a79e4f9..f5339b141 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectoryExtensions.cs @@ -2,6 +2,7 @@ using Elsa.Builders; using Elsa.Services.Models; using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Threading.Tasks; @@ -9,6 +10,22 @@ namespace Elsa.Activities.File { public static class WatchDirectoryExtensions { + #region ChangeTypes + public static ISetupActivity WithChangeTypes(this ISetupActivity setup, Func> changeTypes) => setup.Set(x => x.ChangeTypes, changeTypes); + public static ISetupActivity WithChangeTypes(this ISetupActivity setup, Func changeTypes) => setup.Set(x => x.ChangeTypes, changeTypes); + public static ISetupActivity WithChangeTypes(this ISetupActivity setup, Func> changeTypes) => setup.Set(x => x.ChangeTypes, changeTypes); + public static ISetupActivity WithChangeTypes(this ISetupActivity setup, Func changeTypes) => setup.Set(x => x.ChangeTypes, changeTypes); + public static ISetupActivity WithChangeTypes(this ISetupActivity setup, WatcherChangeTypes changeTypes) => setup.Set(x => x.ChangeTypes, changeTypes); + #endregion + + #region NotifyFilters + public static ISetupActivity WithNotifyFilters(this ISetupActivity setup, Func> notifyFilters) => setup.Set(x => x.NotifyFilters, notifyFilters); + public static ISetupActivity WithNotifyFilters(this ISetupActivity setup, Func notifyFilters) => setup.Set(x => x.NotifyFilters, notifyFilters); + public static ISetupActivity WithNotifyFilters(this ISetupActivity setup, Func> notifyFilters) => setup.Set(x => x.NotifyFilters, notifyFilters); + public static ISetupActivity WithNotifyFilters(this ISetupActivity setup, Func notifyFilters) => setup.Set(x => x.NotifyFilters, notifyFilters); + public static ISetupActivity WithNotifyFilters(this ISetupActivity setup, NotifyFilters notifyFilters) => setup.Set(x => x.NotifyFilters, notifyFilters); + #endregion + #region Path public static ISetupActivity WithPath(this ISetupActivity setup, Func> path) => setup.Set(x => x.Path, path); public static ISetupActivity WithPath(this ISetupActivity setup, Func path) => setup.Set(x => x.Path, path); From bf7e4aab2d9f92947eb2ecdde3f5e2475db80756 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:21:37 +0100 Subject: [PATCH 30/39] Added map from RenameEventArgs to FileSystemEvent class --- .../MapperProfiles/FileSystemEventProfile.cs | 7 +++++++ .../Models/FileSystemEvent.cs | 17 ++++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs b/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs index 41c3ba037..c28bcc647 100644 --- a/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs +++ b/src/activities/Elsa.Activities.File/MapperProfiles/FileSystemEventProfile.cs @@ -22,6 +22,13 @@ namespace Elsa.Activities.File.MapperProfiles o => o.MapFrom(s => s.FullPath)) .ForMember(d => d.TimeStamp, o => o.MapFrom(s => DateTime.Now)); + + CreateMap() + .IncludeBase() + .ForMember(d => d.OldFileName, + o => o.MapFrom(s => s.OldName)) + .ForMember(d => d.OldFullPath, + o => o.MapFrom(s => Path.GetDirectoryName(s.OldFullPath))); } } } diff --git a/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs b/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs index 09f763b90..4f99e5d6a 100644 --- a/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs +++ b/src/activities/Elsa.Activities.File/Models/FileSystemEvent.cs @@ -5,19 +5,6 @@ namespace Elsa.Activities.File.Models { public class FileSystemEvent { - public FileSystemEvent() - { - } - - public FileSystemEvent(WatcherChangeTypes changeType, string directory, string fileName, string fullPath) - { - ChangeType = changeType; - Directory = directory; - FileName = fileName; - FullPath = fullPath; - TimeStamp = DateTime.Now; - } - public WatcherChangeTypes ChangeType { get; set; } public string Directory { get; set; } = default!; @@ -26,6 +13,10 @@ namespace Elsa.Activities.File.Models public string FullPath { get; set; } = default!; + public string OldFileName { get; set; } = default!; + + public string OldFullPath { get; set; } = default!; + public DateTime TimeStamp { get; set; } = default!; } } \ No newline at end of file From b5524d29a1f88318b427d31b4d4236db5616ba1e Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:25:57 +0100 Subject: [PATCH 31/39] Renamed bookmark to be more generic --- ...Bookmark.cs => FileSystemEventBookmark.cs} | 19 ++++++++++++------- .../Services/FileSystemWatchersStarter.cs | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) rename src/activities/Elsa.Activities.File/Bookmarks/{FileCreatedBookmark.cs => FileSystemEventBookmark.cs} (53%) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs similarity index 53% rename from src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs rename to src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs index d3311f33d..367e2e4f3 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/FileCreatedBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs @@ -1,33 +1,38 @@ using Elsa.Services; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; namespace Elsa.Activities.File.Bookmarks { - public class FileCreatedBookmark : IBookmark + public class FileSystemEventBookmark : IBookmark { - public FileCreatedBookmark() + public FileSystemEventBookmark() { } - public FileCreatedBookmark(string path, string pattern) + public FileSystemEventBookmark(string? path, string? pattern, NotifyFilters notifyFilters) { + NotifyFilters = notifyFilters; Path = path; Pattern = pattern; } - public string Path { get; set; } + public NotifyFilters NotifyFilters { get; set; } - public string Pattern { get; set; } + public string? Path { get; set; } + + public string? Pattern { get; set; } } - public class FileCreatedBookmarkProvider : BookmarkProvider + public class FileCreatedBookmarkProvider : BookmarkProvider { public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) { + var notifyFilters = await context.ReadActivityPropertyAsync(a => a.NotifyFilters); var path = await context.ReadActivityPropertyAsync(a => a.Path); var pattern = await context.ReadActivityPropertyAsync(a => a.Pattern); - var result = Result(new FileCreatedBookmark(path, pattern)); + var result = Result(new FileSystemEventBookmark(path, pattern, notifyFilters)); return new[] { result }; } } diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index 3265760a0..238be3615 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -130,11 +130,12 @@ namespace Elsa.Activities.File.Services private void StartWorkflow(FileSystemWatcher watcher, FileSystemEventArgs e) { + var notifyFilter = watcher.NotifyFilter; var path = watcher.Path; var pattern = watcher.Filter; var model = _mapper.Map(e); - var bookmark = new FileCreatedBookmark(path, pattern); + var bookmark = new FileSystemEventBookmark(path, pattern, notifyFilter); var launchContext = new WorkflowsQuery(nameof(WatchDirectory), bookmark); _workflowLaunchpad.UseService(s => s.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model))); } From 85f3326c209ee06210e84fa5ac9241d25ebbab60 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:27:38 +0100 Subject: [PATCH 32/39] Ensure file watcher paths exist and added logic to only add requested event handlers --- .../Services/FileSystemWatchersStarter.cs | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index 238be3615..231c7e2c3 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -52,9 +52,10 @@ namespace Elsa.Activities.File.Services await foreach (var a in activities) { var changeTypes = await a.EvaluatePropertyValueAsync(x => x.ChangeTypes, cancellationToken); + var notifyFilters = await a.EvaluatePropertyValueAsync(x => x.NotifyFilters, cancellationToken); var path = await a.EvaluatePropertyValueAsync(x => x.Path, cancellationToken); var pattern = await a.EvaluatePropertyValueAsync(x => x.Pattern, cancellationToken); - CreateAndAddWatcher(path, pattern, changeTypes); + CreateAndAddWatcher(path, pattern, changeTypes, notifyFilters); } } finally @@ -63,23 +64,34 @@ namespace Elsa.Activities.File.Services } } - private void CreateAndAddWatcher(string path, string pattern, WatcherChangeTypes changeTypes) + private void CreateAndAddWatcher(string? path, string? pattern, WatcherChangeTypes changeTypes, NotifyFilters notifyFilters) { - try - { - var watcher = new FileSystemWatcher() - { - Path = path, - Filter = pattern, - }; - watcher.Created += FileCreated; - watcher.EnableRaisingEvents = true; - _watchers.Add(watcher); - } - finally - { + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentException("File watcher path must not be null or empty"); - } + EnsurePathExists(path); + + var watcher = new FileSystemWatcher() + { + Path = path, + Filter = pattern, + NotifyFilter = notifyFilters + }; + + if (changeTypes == WatcherChangeTypes.Created || changeTypes == WatcherChangeTypes.All) + watcher.Created += FileCreated; + + if (changeTypes == WatcherChangeTypes.Changed || changeTypes == WatcherChangeTypes.All) + watcher.Changed += FileChanged; + + if (changeTypes == WatcherChangeTypes.Deleted || changeTypes == WatcherChangeTypes.All) + watcher.Deleted += FileDeleted; + + if (changeTypes == WatcherChangeTypes.Renamed || changeTypes == WatcherChangeTypes.All) + watcher.Renamed += FileRenamed; + + watcher.EnableRaisingEvents = true; + _watchers.Add(watcher); } private async IAsyncEnumerable> GetActivityInstancesAsync([EnumeratorCancellation] CancellationToken cancellationToken) where TActivity : IActivity @@ -107,6 +119,17 @@ namespace Elsa.Activities.File.Services } } + private void EnsurePathExists(string? path) + { + _logger.LogDebug($"Checking ${path} exists"); + + if (!Directory.Exists(path)) + { + _logger.LogInformation($"Creating directory {path}"); + Directory.CreateDirectory(path); + } + } + #region Watcher delegates private void FileCreated(object sender, FileSystemEventArgs e) { @@ -128,6 +151,11 @@ namespace Elsa.Activities.File.Services StartWorkflow((FileSystemWatcher)sender, e); } + private void FileRenamed(object sender, RenamedEventArgs e) + { + StartWorkflow((FileSystemWatcher)sender, e); + } + private void StartWorkflow(FileSystemWatcher watcher, FileSystemEventArgs e) { var notifyFilter = watcher.NotifyFilter; From dded9bc884910ef2ea245970c7b05f8ca20eef07 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 00:55:48 +0100 Subject: [PATCH 33/39] Additional test wotkflow scenarios --- .../Program.cs | 5 +++- .../WatchDirectoryChangedWorkflow.cs | 23 +++++++++++++++++++ .../WatchDirectoryCreatedWorkflow.cs | 23 +++++++++++++++++++ .../Workflows/WatchDirectoryDatWorkflow.cs | 22 ++++++++++++++++++ .../WatchDirectoryDeletedWorkflow.cs | 23 +++++++++++++++++++ .../Workflows/WatchDirectoryWorkflow.cs | 19 --------------- .../appsettings.json | 4 ++-- 7 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs delete mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs index 2ced8d505..13b6b0aec 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs @@ -20,7 +20,10 @@ namespace Elsa.Samples.WatchDirectoryWorker .AddElsa(options => options .AddConsoleActivities() .AddFileActivities() - .AddWorkflow()); + .AddWorkflow() + .AddWorkflow() + .AddWorkflow() + .AddWorkflow()); }); } } diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs new file mode 100644 index 000000000..e12c719db --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs @@ -0,0 +1,23 @@ +using Elsa.Activities.Console; +using Elsa.Activities.File; +using Elsa.Activities.File.Models; +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class WatchDirectoryChangedWorkflow : IWorkflow + { + private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); + + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot, "Temp\\FileWatchers")) + .WithPattern("*.txt") + .WithChangeTypes(WatcherChangeTypes.Changed)) + .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs new file mode 100644 index 000000000..59fac0af7 --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs @@ -0,0 +1,23 @@ +using Elsa.Activities.Console; +using Elsa.Activities.File; +using Elsa.Activities.File.Models; +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class WatchDirectoryCreatedWorkflow : IWorkflow + { + private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); + + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) + .WithPattern("*.txt") + .WithChangeTypes(WatcherChangeTypes.Created)) + .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs new file mode 100644 index 000000000..73757b51e --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs @@ -0,0 +1,22 @@ +using Elsa.Activities.Console; +using Elsa.Activities.File; +using Elsa.Activities.File.Models; +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class WatchDirectoryDatWorkflow : IWorkflow + { + private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); + + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) + .WithPattern("*.dat")) + .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs new file mode 100644 index 000000000..76e1bc8aa --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs @@ -0,0 +1,23 @@ +using Elsa.Activities.Console; +using Elsa.Activities.File; +using Elsa.Activities.File.Models; +using Elsa.Builders; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class WatchDirectoryDeletedWorkflow : IWorkflow + { + private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); + + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) + .WithPattern("*.txt") + .WithChangeTypes(WatcherChangeTypes.Deleted)) + .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs deleted file mode 100644 index a12d0fb34..000000000 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryWorkflow.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Elsa.Activities.Console; -using Elsa.Activities.File; -using Elsa.Activities.File.Models; -using Elsa.Builders; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Elsa.Samples.WatchDirectoryWorker.Workflows -{ - public class WatchDirectoryWorkflow : IWorkflow - { - public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath("C:\\Temp") - .WithPattern("*.txt")) - .WriteLine(setup => setup.WithText(async context => context.GetInput().FullPath)); - } -} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json index 8a6b79589..89bdcb790 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/appsettings.json @@ -1,8 +1,8 @@ { "Logging": { "LogLevel": { - "Default": "Information", - "Microsoft": "Information", + "Default": "Warning", + "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "Console": { From 3c46fcc08c6dd5f90356d5e5445a4d6b381cec64 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Wed, 8 Sep 2021 11:40:31 +0100 Subject: [PATCH 34/39] Added changetypes to bookmark --- .../Bookmarks/FileSystemEventBookmark.cs | 8 ++++++-- .../Services/FileSystemWatchersStarter.cs | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs b/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs index 367e2e4f3..3f716e483 100644 --- a/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs +++ b/src/activities/Elsa.Activities.File/Bookmarks/FileSystemEventBookmark.cs @@ -11,13 +11,16 @@ namespace Elsa.Activities.File.Bookmarks public FileSystemEventBookmark() { } - public FileSystemEventBookmark(string? path, string? pattern, NotifyFilters notifyFilters) + public FileSystemEventBookmark(string? path, string? pattern, WatcherChangeTypes changeTypes, NotifyFilters notifyFilters) { + ChangeTypes = changeTypes; NotifyFilters = notifyFilters; Path = path; Pattern = pattern; } + public WatcherChangeTypes ChangeTypes { get; set; } + public NotifyFilters NotifyFilters { get; set; } public string? Path { get; set; } @@ -29,10 +32,11 @@ namespace Elsa.Activities.File.Bookmarks { public override async ValueTask> GetBookmarksAsync(BookmarkProviderContext context, CancellationToken cancellationToken) { + var changeTypes = await context.ReadActivityPropertyAsync(a => a.ChangeTypes); var notifyFilters = await context.ReadActivityPropertyAsync(a => a.NotifyFilters); var path = await context.ReadActivityPropertyAsync(a => a.Path); var pattern = await context.ReadActivityPropertyAsync(a => a.Pattern); - var result = Result(new FileSystemEventBookmark(path, pattern, notifyFilters)); + var result = Result(new FileSystemEventBookmark(path, pattern, changeTypes, notifyFilters)); return new[] { result }; } } diff --git a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs index 231c7e2c3..ac84035a9 100644 --- a/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs +++ b/src/activities/Elsa.Activities.File/Services/FileSystemWatchersStarter.cs @@ -158,12 +158,13 @@ namespace Elsa.Activities.File.Services private void StartWorkflow(FileSystemWatcher watcher, FileSystemEventArgs e) { + var changeTypes = e.ChangeType; var notifyFilter = watcher.NotifyFilter; var path = watcher.Path; var pattern = watcher.Filter; var model = _mapper.Map(e); - var bookmark = new FileSystemEventBookmark(path, pattern, notifyFilter); + var bookmark = new FileSystemEventBookmark(path, pattern, changeTypes, notifyFilter); var launchContext = new WorkflowsQuery(nameof(WatchDirectory), bookmark); _workflowLaunchpad.UseService(s => s.CollectAndDispatchWorkflowsAsync(launchContext, new WorkflowInput(model))); } From 7b4c1d8a5d699f71a5f84736d570834938b66b44 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 10 Sep 2021 21:40:37 +0100 Subject: [PATCH 35/39] Updated activity parameters (made some required and updated use of default values) --- .../Activities/DeleteFile/DeleteFile.cs | 4 +++- .../Activities/EnumeratreFiles/EnumerateFiles.cs | 14 ++++++++------ .../Activities/FileExists/FileExists.cs | 5 ++++- .../Activities/OutFile/OutFile.cs | 11 +++++++---- .../Activities/ReadFile/ReadFile.cs | 4 +++- .../Activities/TempFile/TempFile.cs | 2 ++ 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Activities/DeleteFile/DeleteFile.cs b/src/activities/Elsa.Activities.File/Activities/DeleteFile/DeleteFile.cs index 5858d71dd..f5d67cb2f 100644 --- a/src/activities/Elsa.Activities.File/Activities/DeleteFile/DeleteFile.cs +++ b/src/activities/Elsa.Activities.File/Activities/DeleteFile/DeleteFile.cs @@ -2,6 +2,7 @@ using Elsa.ActivityResults; using Elsa.Attributes; using Elsa.Services; using Elsa.Services.Models; +using System.ComponentModel.DataAnnotations; // ReSharper disable once CheckNamespace namespace Elsa.Activities.File @@ -11,8 +12,9 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class DeleteFile : Activity { + [Required] [ActivityInput(Hint = "Path of the file to delete.")] - public string Path { get; set; } = default!; + public string? Path { get; set; } protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) { diff --git a/src/activities/Elsa.Activities.File/Activities/EnumeratreFiles/EnumerateFiles.cs b/src/activities/Elsa.Activities.File/Activities/EnumeratreFiles/EnumerateFiles.cs index 414ae1748..4ebb5292b 100644 --- a/src/activities/Elsa.Activities.File/Activities/EnumeratreFiles/EnumerateFiles.cs +++ b/src/activities/Elsa.Activities.File/Activities/EnumeratreFiles/EnumerateFiles.cs @@ -3,6 +3,7 @@ using Elsa.Attributes; using Elsa.Services; using Elsa.Services.Models; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.IO; // ReSharper disable once CheckNamespace @@ -13,20 +14,21 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class EnumerateFiles : Activity { + [Required] [ActivityInput(Hint = "Path of the folder to enumerate files.")] public string Path { get; set; } = default!; [ActivityInput(Hint = "Pattern for files to return.")] public string? Pattern { get; set; } - [ActivityInput(Hint = "Ignore inaccessible files.", Label = "Ignore Inaccessible")] - public bool IgnoreInaccessible { get; set; } = true; + [ActivityInput(Hint = "Ignore inaccessible files.", Label = "Ignore Inaccessible", DefaultValue = true)] + public bool IgnoreInaccessible { get; set; } - [ActivityInput(Hint = "Set case sensitivity.", Label = "Match Casing")] - public MatchCasing MatchCasing { get; set; } = MatchCasing.CaseInsensitive; + [ActivityInput(Hint = "Set case sensitivity.", Label = "Match Casing", DefaultValue = MatchCasing.CaseInsensitive)] + public MatchCasing MatchCasing { get; set; } - [ActivityInput(Hint = "Return files from sub directories", Label = "Sub Directories")] - public bool SubDirectories { get; set; } = false; + [ActivityInput(Hint = "Return files from sub directories", Label = "Sub Directories", DefaultValue = false)] + public bool SubDirectories { get; set; } [ActivityOutput(Hint = "List of files.")] public IEnumerable? Files { get; set; } diff --git a/src/activities/Elsa.Activities.File/Activities/FileExists/FileExists.cs b/src/activities/Elsa.Activities.File/Activities/FileExists/FileExists.cs index f9ccc880d..c16e94515 100644 --- a/src/activities/Elsa.Activities.File/Activities/FileExists/FileExists.cs +++ b/src/activities/Elsa.Activities.File/Activities/FileExists/FileExists.cs @@ -1,7 +1,9 @@ using Elsa.ActivityResults; using Elsa.Attributes; +using Elsa.Design; using Elsa.Services; using Elsa.Services.Models; +using System.ComponentModel.DataAnnotations; // ReSharper disable once CheckNamespace namespace Elsa.Activities.File @@ -11,8 +13,9 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.True, OutcomeNames.False })] public class FileExists : Activity { + [Required] [ActivityInput(Hint = "Path of the file to delete.")] - public string Path { get; set; } = default!; + public string? Path { get; set; } protected override IActivityExecutionResult OnExecute(ActivityExecutionContext context) { diff --git a/src/activities/Elsa.Activities.File/Activities/OutFile/OutFile.cs b/src/activities/Elsa.Activities.File/Activities/OutFile/OutFile.cs index 66987e3b2..2b6beb822 100644 --- a/src/activities/Elsa.Activities.File/Activities/OutFile/OutFile.cs +++ b/src/activities/Elsa.Activities.File/Activities/OutFile/OutFile.cs @@ -5,6 +5,7 @@ using Elsa.Expressions; using Elsa.Services; using Elsa.Services.Models; using System; +using System.ComponentModel.DataAnnotations; using System.IO; using System.Threading.Tasks; @@ -16,14 +17,16 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class OutFile : Activity { + [Required] [ActivityInput(Hint = "Bytes to write to file.", SupportedSyntaxes = new[] { SyntaxNames.JavaScript }, DefaultSyntax = SyntaxNames.JavaScript)] - public byte[] Bytes { get; set; } = default!; + public byte[]? Bytes { get; set; } + [Required] [ActivityInput(Hint = "Path to create file at.", UIHint = ActivityInputUIHints.SingleLine, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })] - public string Path { get; set; } = default!; + public string? Path { get; set; } - [ActivityInput(Hint = "How the output file should be written to.", UIHint = ActivityInputUIHints.Dropdown)] - public CopyMode Mode { get; set; } = CopyMode.CreateNew; + [ActivityInput(Hint = "How the output file should be written to.", UIHint = ActivityInputUIHints.Dropdown, DefaultValue = CopyMode.CreateNew)] + public CopyMode Mode { get; set; } protected override async ValueTask OnExecuteAsync(ActivityExecutionContext context) { diff --git a/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFile.cs b/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFile.cs index 3a7a145bf..ec653f5cf 100644 --- a/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFile.cs +++ b/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFile.cs @@ -4,6 +4,7 @@ using Elsa.Design; using Elsa.Expressions; using Elsa.Services; using Elsa.Services.Models; +using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; // ReSharper disable once CheckNamespace @@ -14,6 +15,7 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class ReadFile : Activity { + [Required] [ActivityInput(Hint = "Path to read content from.", UIHint = ActivityInputUIHints.SingleLine, SupportedSyntaxes = new[] { SyntaxNames.JavaScript, SyntaxNames.Liquid })] public string Path { get; set; } = default!; @@ -23,7 +25,7 @@ namespace Elsa.Activities.File public override async ValueTask ExecuteAsync(ActivityExecutionContext context) { Bytes = await System.IO.File.ReadAllBytesAsync(Path); - return Done(); + return Done(Bytes); } } } diff --git a/src/activities/Elsa.Activities.File/Activities/TempFile/TempFile.cs b/src/activities/Elsa.Activities.File/Activities/TempFile/TempFile.cs index 00c2bbd3c..95fb27e0a 100644 --- a/src/activities/Elsa.Activities.File/Activities/TempFile/TempFile.cs +++ b/src/activities/Elsa.Activities.File/Activities/TempFile/TempFile.cs @@ -1,6 +1,7 @@ using Elsa.ActivityResults; using Elsa.Attributes; using Elsa.Services; +using System.ComponentModel.DataAnnotations; // ReSharper disable once CheckNamespace namespace Elsa.Activities.File @@ -10,6 +11,7 @@ namespace Elsa.Activities.File Outcomes = new[] { OutcomeNames.Done })] public class TempFile : Activity { + [Required] [ActivityOutput(Hint = "Path of the created temporary file.")] public string Path { get; set; } = default!; From b9d475697f607929028372063f8b933accda28f6 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 10 Sep 2021 23:29:26 +0100 Subject: [PATCH 36/39] Fixed readfile extensions using wrong activity --- .../Activities/ReadFile/ReadFileBuilderExtensions.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFileBuilderExtensions.cs b/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFileBuilderExtensions.cs index c6f7bfc40..600169471 100644 --- a/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFileBuilderExtensions.cs +++ b/src/activities/Elsa.Activities.File/Activities/ReadFile/ReadFileBuilderExtensions.cs @@ -10,34 +10,34 @@ namespace Elsa.Activities.File { public static class ReadFileBuilderExtensions { - public static IActivityBuilder ReadFile(this IBuilder builder, Action> setup, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => builder.Then(setup, null, lineNumber, sourceFile); + public static IActivityBuilder ReadFile(this IBuilder builder, Action> setup, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => builder.Then(setup, null, lineNumber, sourceFile); public static IActivityBuilder ReadFile(this IBuilder builder, Func path, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => - builder.OutFile(activity => activity + builder.ReadFile(activity => activity .Set(x => x.Path, path), lineNumber, sourceFile); public static IActivityBuilder ReadFile(this IBuilder builder, Func> path, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => - builder.OutFile(activity => activity + builder.ReadFile(activity => activity .Set(x => x.Path, path), lineNumber, sourceFile); public static IActivityBuilder ReadFile(this IBuilder builder, Func path, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => - builder.OutFile(activity => activity + builder.ReadFile(activity => activity .Set(x => x.Path, path), lineNumber, sourceFile); public static IActivityBuilder ReadFile(this IBuilder builder, Func> path, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => - builder.OutFile(activity => activity + builder.ReadFile(activity => activity .Set(x => x.Path, path), lineNumber, sourceFile); public static IActivityBuilder ReadFile(this IBuilder builder, string? path, [CallerLineNumber] int lineNumber = default, [CallerFilePath] string? sourceFile = default) => - builder.OutFile(activity => activity + builder.ReadFile(activity => activity .Set(x => x.Path, path), lineNumber, sourceFile); From 1be0aff462ae764f2d37dda60eabade01e4bf335 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Fri, 10 Sep 2021 23:29:46 +0100 Subject: [PATCH 37/39] Minor tweak --- .../Activities/WatchDirectory/WatchDirectory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs index 646794775..51ba5542f 100644 --- a/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs +++ b/src/activities/Elsa.Activities.File/Activities/WatchDirectory/WatchDirectory.cs @@ -46,7 +46,7 @@ namespace Elsa.Activities.File { var model = (FileSystemEvent)context.Input!; Output = model; - return Done(model); + return Done(Output); } } } From b9de6fcbd77a0c3c2f2083c47022b553871caf74 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sat, 11 Sep 2021 00:27:48 +0100 Subject: [PATCH 38/39] Removed unused workflows --- .../WatchDirectoryChangedWorkflow.cs | 23 ------------------- .../Workflows/WatchDirectoryDatWorkflow.cs | 22 ------------------ .../WatchDirectoryDeletedWorkflow.cs | 23 ------------------- 3 files changed, 68 deletions(-) delete mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs delete mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs delete mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs deleted file mode 100644 index e12c719db..000000000 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryChangedWorkflow.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Elsa.Activities.Console; -using Elsa.Activities.File; -using Elsa.Activities.File.Models; -using Elsa.Builders; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Elsa.Samples.WatchDirectoryWorker.Workflows -{ - public class WatchDirectoryChangedWorkflow : IWorkflow - { - private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); - - public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot, "Temp\\FileWatchers")) - .WithPattern("*.txt") - .WithChangeTypes(WatcherChangeTypes.Changed)) - .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); - } -} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs deleted file mode 100644 index 73757b51e..000000000 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDatWorkflow.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Elsa.Activities.Console; -using Elsa.Activities.File; -using Elsa.Activities.File.Models; -using Elsa.Builders; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Elsa.Samples.WatchDirectoryWorker.Workflows -{ - public class WatchDirectoryDatWorkflow : IWorkflow - { - private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); - - public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) - .WithPattern("*.dat")) - .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); - } -} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs deleted file mode 100644 index 76e1bc8aa..000000000 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryDeletedWorkflow.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Elsa.Activities.Console; -using Elsa.Activities.File; -using Elsa.Activities.File.Models; -using Elsa.Builders; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Elsa.Samples.WatchDirectoryWorker.Workflows -{ - public class WatchDirectoryDeletedWorkflow : IWorkflow - { - private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); - - public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) - .WithPattern("*.txt") - .WithChangeTypes(WatcherChangeTypes.Deleted)) - .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); - } -} From fd3b5ad388233e2ef67c32c5439392c4b1a63b44 Mon Sep 17 00:00:00 2001 From: Cameron Cowen Date: Sat, 11 Sep 2021 00:29:06 +0100 Subject: [PATCH 39/39] Added workflow to create files to auto kick off file watcher --- .../Elsa.Samples.WatchDirectoryWorker.csproj | 3 +- .../Program.cs | 17 +++++++-- .../Workflows/TimerCreateFile.cs | 37 +++++++++++++++++++ .../WatchDirectoryCreatedWorkflow.cs | 32 ++++++++++++++-- 4 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/TimerCreateFile.cs diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj index fdaa1a714..f1891d124 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Elsa.Samples.WatchDirectoryWorker.csproj @@ -1,4 +1,4 @@ - + Exe @@ -22,6 +22,7 @@ + diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs index 13b6b0aec..650766a4e 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Program.cs @@ -2,11 +2,21 @@ using Elsa.Samples.WatchDirectoryWorker.Workflows; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; +using System.IO; namespace Elsa.Samples.WatchDirectoryWorker { class Program { + private static readonly string _directory; + private static readonly string _systemRoot; + + static Program() + { + _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); + _directory = Path.Combine(_systemRoot, "Temp\\FileWatchers"); + } + static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); @@ -20,10 +30,9 @@ namespace Elsa.Samples.WatchDirectoryWorker .AddElsa(options => options .AddConsoleActivities() .AddFileActivities() - .AddWorkflow() - .AddWorkflow() - .AddWorkflow() - .AddWorkflow()); + .AddQuartzTemporalActivities() + .AddWorkflow(sp => ActivatorUtilities.CreateInstance(services.BuildServiceProvider(), _directory)) + .AddWorkflow(sp => new WatchDirectoryCreatedWorkflow(_directory))); }); } } diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/TimerCreateFile.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/TimerCreateFile.cs new file mode 100644 index 000000000..5e40b7555 --- /dev/null +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/TimerCreateFile.cs @@ -0,0 +1,37 @@ +using Elsa.Activities.File; +using Elsa.Activities.Temporal; +using Elsa.Builders; +using NodaTime; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Elsa.Samples.WatchDirectoryWorker.Workflows +{ + public class TimerCreateFile : IWorkflow + { + private IClock _clock; + private string _directory; + + public TimerCreateFile(IClock clock, string directory) + { + _clock = clock; + _directory = directory; + } + + public void Build(IWorkflowBuilder builder) => builder + .Timer(Duration.FromSeconds(10)) + .OutFile(setup => + { + var guid = Guid.NewGuid().ToString(); + var filename = Path.Combine(_directory, $"{guid}.txt"); + + setup.WithPath(filename); + setup.WithBytes(Encoding.UTF8.GetBytes("Hello World")); + }); + } +} diff --git a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs index 59fac0af7..dfcd36411 100644 --- a/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs +++ b/src/samples/worker/Elsa.Samples.WatchDirectoryWorker/Workflows/WatchDirectoryCreatedWorkflow.cs @@ -7,17 +7,41 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using System.Text.Unicode; using System.Threading.Tasks; namespace Elsa.Samples.WatchDirectoryWorker.Workflows { public class WatchDirectoryCreatedWorkflow : IWorkflow { + private readonly string _directory; private readonly string _systemRoot = Path.GetPathRoot(Environment.SystemDirectory); - public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => setup.WithPath(Path.Combine(_systemRoot,"Temp\\FileWatchers")) - .WithPattern("*.txt") - .WithChangeTypes(WatcherChangeTypes.Created)) - .WriteLine(setup => setup.WithText(context => $"{GetType().Name}-{context.GetInput().FullPath}-{context.GetInput().ChangeType}")); + public WatchDirectoryCreatedWorkflow(string directory) + { + _directory = directory; + } + + public void Build(IWorkflowBuilder builder) => builder.WatchDirectory(setup => + { + setup.WithPath(Path.Combine(_systemRoot, "Temp\\FileWatchers")) + .WithPattern("*.txt") + .WithChangeTypes(WatcherChangeTypes.Created); + }) + .ReadFile(setup => + { + setup.WithPath(context => context.GetInput().FullPath); + }) + .WriteLine(setup => + { + setup.WithText(async context => + { + var fsEvent = await context.WorkflowExecutionContext.GetActivityPropertyAsync("activity-1", a => a.Output); + var data = await context.WorkflowExecutionContext.GetActivityPropertyAsync("activity-2", a => a.Bytes); + var line = $"{GetType().Name}-{fsEvent.FullPath}-{fsEvent.ChangeType}-{Encoding.UTF8.GetString(data)}"; + return line; + }); + }) + .DeleteFile(context => context.GetInput().FullPath); } }