diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cdf0b61 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing + +Not all contributions are code! We welcome contributions from everyone. Please see our [contributing guide](#guide) for more information. + +## Guide + +All contributions to this repository should follow a few simple rules: + +1. All contributions must be licensed under the [MIT License](LICENSE) +2. All contributions are subject to the [Code of Conduct](#code-of-conduct) +3. All contributions must be made via pull request +4. All contributions are subject to review by a maintainer of the repository, and may be rejected for any reason at any time, even after being merged to `main` +5. Feature requests and bug reports should be made via [GitHub Issues](https://github.com/frankhaugen/Frank.PulseFlow/issues) +6. No contribution is too small, but they can be too large. If you're not sure if your contribution is too large, split it into multiple pull requests, or ask a maintainer for guidance, (You can find a list of maintainers in the [MAINTAINERS](MAINTAINERS.md) file) + 6.1. You can have multiple pull requests open at the same time, and reference each other in the description of the pull request and the same issue, (this is called a "pull request chain" and please use X of Y in the title of the pull request to indicate that it is part of a chain) +7. All contributions must be made in English (this includes comments, commit messages, pull request descriptions, etc.) +8. All contributions must be made in a way that is consistent with the existing codebase, (e.g. use the same coding style, naming conventions, etc.), see [Coding Style](STYLE.md) for more information + + +## Getting Started + +1. Fork the repository on GitHub +2. Install the latest version of [.NET (Core)](https://dotnet.microsoft.com/download) +3. Install the latest version of [Visual Studio](https://visualstudio.microsoft.com/downloads/) or [Visual Studio Code](https://code.visualstudio.com/download) (or your preferred editor) +4. Clone the forked repository to your local machine +5. Open the solution in Visual Studio or Visual Studio Code +6. Create a branch for your changes +7. Make your changes +8. Build and test your changes +9. Commit and push your changes to your forked repository +10. Create a pull request to the `main` branch of the repository, and mention the issue number that you're addressing, (e.g. `#1234`) in the description of the pull request. Create a new issue if one does not already exist, describing the problem and how you solved it. +11. Wait for a maintainer to review your pull request and either merge it or request changes + +## Building and Testing + +### Using command line + +1. Navigate to the root directory of the repository +2. Run `dotnet build` to build the solution or `./build.ps1` on Windows or `pwsh ./build.ps1` on Linux/macOS +3. Run `dotnet test` to run the tests or `./test.ps1` on Windows or `pwsh ./test.ps1` on Linux/macOS +4. Run `dotnet pack` to create NuGet packages or `./pack.ps1` on Windows or `pwsh ./pack.ps1` on Linux/macOS +5. Use the packages in the `artifacts/packages` directory in your application to test that they work as expected + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact the maintainers of this project (see below). + +## Maintainers + +Repository owners and maintainers are listed in the [MAINTAINERS](MAINTAINERS.md) file. \ No newline at end of file diff --git a/Frank.PulseFlow.Sample/.gitignore b/Frank.PulseFlow.Sample/.gitignore new file mode 100644 index 0000000..8afdcb6 --- /dev/null +++ b/Frank.PulseFlow.Sample/.gitignore @@ -0,0 +1,454 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +## +## Visual Studio Code +## +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json diff --git a/Frank.PulseFlow.Sample/Directory.Build.props b/Frank.PulseFlow.Sample/Directory.Build.props new file mode 100644 index 0000000..b7d1f09 --- /dev/null +++ b/Frank.PulseFlow.Sample/Directory.Build.props @@ -0,0 +1,6 @@ + + + enable + 11.0.6 + + diff --git a/Frank.PulseFlow.Sample/Frank.PulseFlow.Sample.sln b/Frank.PulseFlow.Sample/Frank.PulseFlow.Sample.sln new file mode 100644 index 0000000..b96b9e6 --- /dev/null +++ b/Frank.PulseFlow.Sample/Frank.PulseFlow.Sample.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frank.PulseFlow.Sample", "Frank.PulseFlow.Sample\Frank.PulseFlow.Sample.csproj", "{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frank.PulseFlow.Sample.Desktop", "Frank.PulseFlow.Sample.Desktop\Frank.PulseFlow.Sample.Desktop.csproj", "{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frank.PulseFlow.Sample.Browser", "Frank.PulseFlow.Sample.Browser\Frank.PulseFlow.Sample.Browser.csproj", "{1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frank.PulseFlow.Sample.iOS", "Frank.PulseFlow.Sample.iOS\Frank.PulseFlow.Sample.iOS.csproj", "{EBD9022F-BC83-4846-9A11-6F7F3772DC64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Frank.PulseFlow.Sample.Android", "Frank.PulseFlow.Sample.Android\Frank.PulseFlow.Sample.Android.csproj", "{7AD1DAC8-7FBE-49D5-8614-7321233DB82E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DA99C4E-89E3-4049-9C22-0A7EC60D83D8}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.Build.0 = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.Build.0 = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C1A049E-235C-4CD0-B6FA-D53AC418F4DA}.Release|Any CPU.Build.0 = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBD9022F-BC83-4846-9A11-6F7F3772DC64}.Release|Any CPU.Build.0 = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AD1DAC8-7FBE-49D5-8614-7321233DB82E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E} + EndGlobalSection +EndGlobal diff --git a/Frank.PulseFlow.Tests.Cli/Program.cs b/Frank.PulseFlow.Tests.Cli/Program.cs index cbb6caa..8c26639 100644 --- a/Frank.PulseFlow.Tests.Cli/Program.cs +++ b/Frank.PulseFlow.Tests.Cli/Program.cs @@ -1,6 +1,4 @@ -// See https://aka.ms/new-console-template for more information - -using Frank.PulseFlow; +using Frank.PulseFlow; using Frank.PulseFlow.Tests.Cli; IHostBuilder builder = Host.CreateDefaultBuilder(); @@ -9,15 +7,11 @@ { services.AddPulseFlow(messagingBuilder => { - messagingBuilder.AddFlow(); + messagingBuilder.AddFlow(); }); services.AddHostedService(); }); IHost app = builder.Build(); - -await app.RunAsync(); - - -//Extension Method \ No newline at end of file +await app.RunAsync(); \ No newline at end of file diff --git a/Frank.PulseFlow.Tests.Cli/TestingService.cs b/Frank.PulseFlow.Tests.Cli/TestingService.cs index 136343b..6dd79b7 100644 --- a/Frank.PulseFlow.Tests.Cli/TestingService.cs +++ b/Frank.PulseFlow.Tests.Cli/TestingService.cs @@ -4,10 +4,7 @@ public class TestingService : BackgroundService { private readonly IConduit _messenger; - public TestingService(IConduit messenger) - { - _messenger = messenger; - } + public TestingService(IConduit messenger) => _messenger = messenger; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/Frank.PulseFlow.Tests.Cli/TextPulseFlow.cs b/Frank.PulseFlow.Tests.Cli/TextFlow.cs similarity index 68% rename from Frank.PulseFlow.Tests.Cli/TextPulseFlow.cs rename to Frank.PulseFlow.Tests.Cli/TextFlow.cs index a0c8f5f..3737858 100644 --- a/Frank.PulseFlow.Tests.Cli/TextPulseFlow.cs +++ b/Frank.PulseFlow.Tests.Cli/TextFlow.cs @@ -1,13 +1,10 @@ namespace Frank.PulseFlow.Tests.Cli; -public class TextPulseFlow : IFlow +public class TextFlow : IFlow { - private readonly ILogger _logger; + private readonly ILogger _logger; - public TextPulseFlow(ILogger logger) - { - _logger = logger; - } + public TextFlow(ILogger logger) => _logger = logger; public async Task HandleAsync(IPulse message, CancellationToken cancellationToken) { diff --git a/Frank.PulseFlow.sln b/Frank.PulseFlow.sln index c91ccc6..38cc877 100644 --- a/Frank.PulseFlow.sln +++ b/Frank.PulseFlow.sln @@ -22,6 +22,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution restore.ps1 = restore.ps1 test.ps1 = test.ps1 pack.ps1 = pack.ps1 + CONTRIBUTING.md = CONTRIBUTING.md + icon.png = icon.png + README.md = README.md + .github\workflows\main.yml = .github\workflows\main.yml + MAINTAINERS.md = MAINTAINERS.md + STYLE.md = STYLE.md EndProjectSection EndProject Global diff --git a/Frank.PulseFlow/Frank.PulseFlow.csproj b/Frank.PulseFlow/Frank.PulseFlow.csproj index bb88563..0fc69b8 100644 --- a/Frank.PulseFlow/Frank.PulseFlow.csproj +++ b/Frank.PulseFlow/Frank.PulseFlow.csproj @@ -7,12 +7,6 @@ PulseFlow uses Channel -mechanism for internal messaging Pulse,Flow,PulseFlow,Frank,Frank Haugen,Messaging,In-Memory - - 2023-12-14: - 1.0 Initial release of PulseFlow - 1.1 Added support for .NET 7.0 and .NET 8.0 - - true $(NoWarn);1591 @@ -23,7 +17,7 @@ Frank R. Haugen Frank R. Haugen Copyright (c) 2023 Frank R. Haugen - readme.md + README.md icon.png true MIT @@ -39,8 +33,8 @@ - - + + diff --git a/Frank.PulseFlow/IFlowBuilder.cs b/Frank.PulseFlow/IFlowBuilder.cs index 53cb316..10b766a 100644 --- a/Frank.PulseFlow/IFlowBuilder.cs +++ b/Frank.PulseFlow/IFlowBuilder.cs @@ -1,5 +1,8 @@ namespace Frank.PulseFlow; +/// +/// Represents a pulse flow builder that is used to simplify the registration of flows. +/// public interface IFlowBuilder { /// diff --git a/Frank.PulseFlow/Internal/Channel.cs b/Frank.PulseFlow/Internal/Channel.cs index 6e878b5..4278e74 100644 --- a/Frank.PulseFlow/Internal/Channel.cs +++ b/Frank.PulseFlow/Internal/Channel.cs @@ -2,6 +2,9 @@ namespace Frank.PulseFlow.Internal; +/// +/// A wrapper around a that sends and receives objects. +/// internal class Channel : IChannel { private readonly Channel _channel = System.Threading.Channels.Channel.CreateUnbounded(); diff --git a/Frank.PulseFlow/Internal/Conduit.cs b/Frank.PulseFlow/Internal/Conduit.cs index 005a23f..1ecce12 100644 --- a/Frank.PulseFlow/Internal/Conduit.cs +++ b/Frank.PulseFlow/Internal/Conduit.cs @@ -1,5 +1,8 @@ namespace Frank.PulseFlow.Internal; +/// +/// A wrapper around a that sends and receives objects. +/// internal class Conduit : IConduit { private readonly IChannel _messageChannel; diff --git a/Frank.PulseFlow/FlowBuilder.cs b/Frank.PulseFlow/Internal/FlowBuilder.cs similarity index 74% rename from Frank.PulseFlow/FlowBuilder.cs rename to Frank.PulseFlow/Internal/FlowBuilder.cs index 0980fcc..6d2c56e 100644 --- a/Frank.PulseFlow/FlowBuilder.cs +++ b/Frank.PulseFlow/Internal/FlowBuilder.cs @@ -1,15 +1,12 @@ using Microsoft.Extensions.DependencyInjection; -namespace Frank.PulseFlow; +namespace Frank.PulseFlow.Internal; -public class FlowBuilder : IFlowBuilder +internal class FlowBuilder : IFlowBuilder { private readonly IServiceCollection _services; - public FlowBuilder(IServiceCollection services) - { - _services = services; - } + public FlowBuilder(IServiceCollection services) => _services = services; /// /// Adds a flow of type T to the pulse flow builder. diff --git a/Frank.PulseFlow/Internal/IChannel.cs b/Frank.PulseFlow/Internal/IChannel.cs index c15b0b9..f7fb445 100644 --- a/Frank.PulseFlow/Internal/IChannel.cs +++ b/Frank.PulseFlow/Internal/IChannel.cs @@ -1,5 +1,8 @@ namespace Frank.PulseFlow.Internal; +/// +/// Represents a channel for sending and receiving pulses. +/// internal interface IChannel { Task SendAsync(IPulse message); diff --git a/Frank.PulseFlow/README.md b/Frank.PulseFlow/README.md deleted file mode 100644 index 4deef0b..0000000 --- a/Frank.PulseFlow/README.md +++ /dev/null @@ -1,125 +0,0 @@ -# PulseFlow Local Messaging - -PulseFlow Local Messaging is a lightweight, high-performance messaging system that enables seamless communication - -## Table of Contents - -- [Overview](#overview) - - [Key Features](#key-features) - - [Illustration](#illustration) - - [Use Cases](#use-cases) -- [Getting Started](#getting-started) - - [Installation](#installation) -- [Concepts](#concepts) - - [Nexus](#nexus) - - [Conduit](#conduit) - - [Pulse](#pulse) - - [PulseFlow](#pulseflow) - -## Overview - -PulseFlow Local Messaging is a lightweight, high-performance messaging system that enables seamless communication -between different parts of an application. It's designed to be simple, flexible, and scalable, allowing for easy -integration into any system architecture. - -### Key Features - -- **Lightweight**: PulseFlow is a lightweight messaging system, with a small footprint and minimal resource - requirements. -- **High Performance**: It's designed for high performance and scalability, capable of handling a vast volume of - messages simultaneously. -- **Asynchronous Communication**: PulseFlow supports asynchronous data flow, allowing for non-blocking and concurrent - message transmissions. -- **Flexible and Adaptable**: It's flexible and adaptable, capable of handling various types of messages and adapting - its processing logic based on the nature and requirements of each message. -- **Simple and Easy to Use**: PulseFlow is simple and easy to use, with a straightforward API and minimal configuration - requirements. - -### Illustration - -```mermaid -graph TD - Pulse[Pulse: Data/Messages] -->|transmitted via| Conduit[Conduit: Message Pathway] - Conduit -->|delivered to| Nexus[Nexus: Processing Service] - Nexus -->|processed by| PulseFlow[PulseFlow: Message Handler] - PulseFlow -->|manipulates| Pulse -``` - -In this Mermaid diagram: -- **Pulse** is shown as the starting point for data/messages. -- **Conduit** is represented as the pathway for transmitting messages. -- **Nexus** is the central processing service. -- **PulseFlow** is depicted as handling and manipulating the messages. - -When you include this in a GitHub Markdown file, GitHub will render the Mermaid diagram as a visual graph. Remember to remove the extra backticks (```) in the beginning and end when adding this to your README. - -### Use Cases - -PulseFlow is a general-purpose messaging system that can be used in a wide variety of applications. It's particularly -useful in scenarios where there's a need for asynchronous communication between different parts of the system. - -## Getting Started - -This section provides a quick guide on how to get started with PulseFlow Local Messaging. - -### Installation - -PulseFlow is available as a NuGet package, which can be installed using the following command: - -```bash -dotnet add package Frank.PulseFlow -``` - -## Concepts - -This section provides an in-depth explanation of the key concepts and components within the system: Nexus, Conduit, -Pulse, and PulseFlow. Understanding these concepts is crucial for grasping how the system operates and interacts with -data. - -### Nexus - -The **Nexus** is the central hub of our messaging system, analogous to a neural network's core. It serves as the primary -processing service, where all data messages, or 'Pulses', are received, interpreted, and routed to their respective -destinations. - -- **Role**: Nexus acts as the orchestrator within the system, managing the flow of messages and ensuring that each one - is processed according to predefined rules and logic. -- **Functionality**: It handles various tasks like message validation, transformation, and decision-making on how and - where messages should be directed post-processing. -- **Scalability and Performance**: Designed for high performance and scalability, Nexus can handle a vast volume of - messages simultaneously, ensuring minimal latency and high throughput in data processing. - -### Conduit - -The **Conduit** represents the pathway through which messages, or 'Pulses', are transmitted within the system. It's the -messenger that ensures the delivery of data from one point to another. - -- **Mechanism**: Conduit facilitates the smooth and efficient transport of messages across different parts of the - system. -- **Reliability and Integrity**: Ensuring data integrity, Conduit maintains the fidelity of the messages as they - traverse through various processes. -- **Asynchronous Communication**: It supports asynchronous data flow, allowing for non-blocking and concurrent message - transmissions, which is key for a responsive and efficient system. - -### Pulse - -**Pulse** is the term used to describe the individual units of data or messages that flow through the system. - -- **Data Encapsulation**: Each Pulse is a packet of information, encapsulating the necessary data in a well-defined - format. -- **Types and Variability**: Pulses can vary in type and structure, ranging from simple text messages to complex data - structures, each tailored to carry specific information relevant to its intended process. -- **Lifecycle**: The lifecycle of a Pulse includes its creation, transmission through the Conduit, processing in the - Nexus, and final delivery or action as dictated by the system's logic. - -### PulseFlow - -**PulseFlow** is the sophisticated mechanism responsible for handling and manipulating the Pulses as they move through -the system. - -- **Message Handling**: It's specifically designed to process each Pulse, applying necessary transformations, routing, - and any other required operations. -- **Flexibility and Adaptability**: PulseFlow is adept at handling various types of Pulses, capable of adapting its - processing logic based on the nature and requirements of each message. -- **Integration Point**: Acting as a key integration point within the system, it ensures that Pulses are managed - efficiently and effectively, readying them for their next phase in the data journey. diff --git a/Frank.PulseFlow/ServiceCollectionExtensions.cs b/Frank.PulseFlow/ServiceCollectionExtensions.cs index bcc6e66..dadf142 100644 --- a/Frank.PulseFlow/ServiceCollectionExtensions.cs +++ b/Frank.PulseFlow/ServiceCollectionExtensions.cs @@ -4,11 +4,23 @@ namespace Frank.PulseFlow; +/// +/// Provides extension methods for the interface. +/// public static class ServiceCollectionExtensions { /// /// Adds the PulseFlow to the service collection. /// + /// + /// + /// services.AddPulseFlow(builder => + /// { + /// builder.AddFlow[Flow](); + /// builder.AddFlow[AnotherFlow](); + /// }); + /// + /// /// The service collection to which the PulseFlow components will be added. /// An action delegate to configure the PulseFlow builder. /// The updated service collection. diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000..69effdc --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,7 @@ +# Maintainers + +The maintainers of this repository are: + +| Name | GitHub | Role | +| ---- | ------ |-------------| +| Frank R. Haugen | [frankhaugen](https://github.com/frankhaugen) | Maintainer/Owner | diff --git a/README.md b/README.md index e43e652..f36f51f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,260 @@ -# Frank.PulseFlow +# PulseFlow (Local Messaging) -Frank.PulseFlow is an innovative C# library that wraps the Channel type, enhancing its DI friendliness and intuitive use in data-vent-driven architectures. It provides a streamlined approach for efficient message handling in various applications. +PulseFlow Local Messaging is a lightweight, high-performance messaging system that enables seamless communication, and thread-safe data transfer between different parts of an application. It's designed to be simple, flexible, and scalable, allowing for easy integration into any system architecture. -## Key Features -- **Pulse**: Represents messages in the system. -- **Conduit (IConduit)**: Acts as a message transmitter. -- **PulseFlow (IPulseFlow)**: Serves as a message handler. -- **Nexus**: A BackgroundService that processes all Pulses and routes them to the appropriate IPulseFlow handlers. +___ +[![GitHub License](https://img.shields.io/github/license/frankhaugen/Frank.PulseFlow)](LICENSE) +[![NuGet](https://img.shields.io/nuget/v/Frank.PulseFlow.svg)](https://www.nuget.org/packages/Frank.PulseFlow) +[![NuGet](https://img.shields.io/nuget/dt/Frank.PulseFlow.svg)](https://www.nuget.org/packages/Frank.PulseFlow) + +![GitHub contributors](https://img.shields.io/github/contributors/frankhaugen/Frank.PulseFlow) +![GitHub Release Date - Published_At](https://img.shields.io/github/release-date/frankhaugen/Frank.PulseFlow) +![GitHub last commit](https://img.shields.io/github/last-commit/frankhaugen/Frank.PulseFlow) +![GitHub commit activity](https://img.shields.io/github/commit-activity/m/frankhaugen/Frank.PulseFlow) +![GitHub pull requests](https://img.shields.io/github/issues-pr/frankhaugen/Frank.PulseFlow) +![GitHub issues](https://img.shields.io/github/issues/frankhaugen/Frank.PulseFlow) +![GitHub closed issues](https://img.shields.io/github/issues-closed/frankhaugen/Frank.PulseFlow) +___ + +## Table of Contents + +- [Overview](#overview) + - [Key Features](#key-features) + - [Illustration](#illustration) + - [Use Cases](#use-cases) +- [Getting Started](#getting-started) + - [Installation](#installation) +- [Concepts](#concepts) + - [Nexus](#nexus) + - [Conduit](#conduit) + - [Pulse](#pulse) + - [Flow](#flow) +___ + +## Acknowledgements + +This is a very thin abstraction layer on top of [System.Threading.Channels](https://www.nuget.org/packages/System.Threading.Channels), which is a NuGet package that gets shipped along with every release of .NET. +The reason for this abstraction layer is to make it easier to use `System.Threading.Channels` in a Dependency Injection scenario, and to make it easier to use `System.Threading.Channels` in a thread-safe manner. +Thanks to the .NET team for making `System.Threading.Channels`, and in particular [Stephen Toub](https://github.com/stephentoub) for his [blog post](https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/) on `System.Threading.Channels`, and as part of the rest of the team. + +## Overview + +PulseFlow Local Messaging is a lightweight, high-performance messaging system that enables seamless communication +between different parts of an application. It's designed to be simple, flexible, and scalable, allowing for easy +integration into any system architecture. + +### Key Features + +- **Lightweight**: PulseFlow is a lightweight messaging system, with a small footprint and minimal resource + requirements. +- **High Performance**: It's designed for high performance and scalability, capable of handling a vast volume of + messages simultaneously. +- **Asynchronous Communication**: PulseFlow supports asynchronous data flow, allowing for non-blocking and concurrent + message transmissions. +- **Flexible and Adaptable**: It's flexible and adaptable, capable of handling various types of messages and adapting + its processing logic based on the nature and requirements of each message. +- **Simple and Easy to Use**: PulseFlow is simple and easy to use, with a straightforward API and minimal configuration + requirements. This is assuming Dependency Injection is used. If not, then it's a bit more complicated, and not supported at this time. +- **Thread-Safe**: It's thread-safe, ensuring that messages are processed in a safe and reliable manner. +- **Open Source**: PulseFlow is open-source, with the source code available on GitHub. +- **Cross-Platform**: It's cross-platform, supporting multiple operating systems and platforms. +- **Supports multiple consumers**: PulseFlow supports multiple consumers, thereby allowing for parallel processing of + messages. This is particularly useful in scenarios where there's a need to save messages to some form of audit trail or log. + +### Illustration + +```mermaid +graph TB + subgraph "Transmission" + EmailPulse[Email : IPulse] -->|transmitted via| Conduit[IConduit] + FtpPulse[FTP : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse[API : IPulse] -->|transmitted via| Conduit[IConduit] + end + subgraph "Delivery" + Conduit -->|delivered to| IChannel[IChannel] + end + subgraph "Consumption and Routing" + IChannel -->|consumed and routed by| Nexus[Nexus] + Nexus -->|typeof==Email| EmailFlow[EmailFlow : IFlow] + Nexus -->|typeof==API| Flow[FtpAndApiFlow : IFlow] + Nexus -->|typeof==FTP| Flow[FtpAndApiFlow : IFlow] + Nexus -->|typeof==?| AuditFlow[AuditFlow : IFlow] + AuditFlow -->|audit trail by| ILogger[ILogger] + end +``` + +In this Mermaid diagram: +- **IPulse** is the interface for the Pulse. +- **IConduit** is the interface for the Conduit, which is the pathway through which messages are transmitted. +- **IChannel** is the interface for the Channel, which is a wrapper around the `System.Threading.Channels.Channel` class, which is a thread-safe data structure for passing data between producers and consumers located in different threads. +- **Nexus** is the central processing service, which handles the pulse messages. +- **IFlow** is the interface for the a flow, which is the mechanism that handles/consumes the pulse messages. +- **ILogger** is the interface for the generic logger in dotnet. + +When you include this in a GitHub Markdown file, GitHub will render the Mermaid diagram as a visual graph. Remember to remove the extra backticks (```) in the beginning and end when adding this to your README. + +### Use Cases + +PulseFlow is a general-purpose messaging system that can be used in a wide variety of applications. It's particularly +useful in scenarios where there's a need for asynchronous communication between different parts of the system. + +Another use case is when you need multiple threads to do some non-multiple-thread-safe work, like saving to a log-file. Example: You have a web API and you want to save a all requests' route, method and user to a log-file. You can use PulseFlow to do this in a thread-safe manner, because PulseFlow's `IConduit` and `IChannel` are thread-safe. You can have multiple threads saving to the same log-file, and PulseFlow will ensure that the log-file is not written to by multiple threads at the same time, and that the writing happens in the order the messages are received. + +#### Example + +```mermaid +graph TB + subgraph Transmission + ApiPulse1[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse2[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse3[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse4[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse5[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + ApiPulse6[ApiMessage : IPulse] -->|transmitted via| Conduit[IConduit] + end + subgraph Delivery + Conduit -->|delivered to| IChannel[IChannel] + end + subgraph Consumption and Routing + IChannel -->|consumed and routed by| Nexus[Nexus] + Nexus -->|typeof==API| Flow[FileLoggerFlow : IFlow] + end +``` ## Getting Started -To integrate Frank.PulseFlow, add it as a NuGet package and use `.AddPulseFlow()` on `IServiceCollection`. -## Usage -Implement the `IPulseFlow` interface in your classes and register these implementations with the `AddPulseFlow` method in your service collection. +This section provides a quick guide on how to get started with PulseFlow Local Messaging. + +### Installation + +PulseFlow is available as a NuGet package, which can be installed using the following command: + +```bash +dotnet add package Frank.PulseFlow +``` + +Once installed, you can start using PulseFlow by adding the following using statement to your code: + +```csharp +using Frank.PulseFlow; +``` + +### Basic Usage + +The following code snippet shows a basic example of how to use PulseFlow: + +```csharp +IHostBuilder builder = Host.CreateDefaultBuilder(); + +builder.ConfigureServices((context, services) => +{ + services.AddPulseFlow(messagingBuilder => + { + messagingBuilder.AddFlow(); + }); + services.AddHostedService(); +}); + +IHost app = builder.Build(); + +await app.RunAsync(); + +public class TextFlow : IFlow +{ + private readonly ILogger _logger; + + public TextFlow(ILogger logger) => _logger = logger; + + public async Task HandleAsync(IPulse message, CancellationToken cancellationToken) + { + if (message is TextPulse textMessage) + _logger.LogInformation("Received text message: {Text}", textMessage.Text); + await Task.CompletedTask; + } + + public bool CanHandle(Type pulseType) => pulseType == typeof(TextPulse); +} + +public class TestingService : BackgroundService +{ + private readonly IConduit _messenger; + + public TestingService(IConduit messenger) => _messenger = messenger; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await Task.Delay(2000, stoppingToken); + while (!stoppingToken.IsCancellationRequested) + { + await _messenger.SendAsync(new TextPulse { Id = Guid.NewGuid(), Text = "Hello World" }); + await Task.Delay(1000, stoppingToken); + } + } +} +public class TextPulse : BasePulse +{ + public string Text { get; set; } +} +``` + +## Concepts + +This section provides an in-depth explanation of the key concepts and components within the system: Nexus, Conduit, +Pulse, and PulseFlow. Understanding these concepts is crucial for grasping how the system operates and interacts with +data. + +### Nexus + +The **Nexus** is the central hub of our messaging system, analogous to a neural network's core. It serves as the primary +processing service, where all data messages, or 'Pulses', are received, interpreted, and routed to their respective +destinations. + +- **Role**: Nexus acts as the orchestrator within the system, managing the flow of messages and ensuring that each one + is processed according to predefined rules and logic. +- **Functionality**: It handles various tasks like message validation, transformation, and decision-making on how and + where messages should be directed post-processing. +- **Scalability and Performance**: Designed for high performance and scalability, Nexus can handle a vast volume of + messages simultaneously, ensuring minimal latency and high throughput in data processing. + +### Conduit + +The **Conduit** represents the pathway through which messages, or 'Pulses', are transmitted within the system. It's the +messenger that ensures the delivery of data from one point to another. + +- **Mechanism**: Conduit facilitates the smooth and efficient transport of messages across different parts of the + system. +- **Reliability and Integrity**: Ensuring data integrity, Conduit maintains the fidelity of the messages as they + traverse through various processes. +- **Asynchronous Communication**: It supports asynchronous data flow, allowing for non-blocking and concurrent message + transmissions, which is key for a responsive and efficient system. + +### Pulse + +**Pulse** is the term used to describe the individual units of data or messages that flow through the system. + +- **Data Encapsulation**: Each Pulse is a packet of information, encapsulating the necessary data in a well-defined + format. +- **Types and Variability**: Pulses can vary in type and structure, ranging from simple text messages to complex data + structures, each tailored to carry specific information relevant to its intended process. +- **Lifecycle**: The lifecycle of a Pulse includes its creation, transmission through the Conduit, processing in the + Nexus, and final delivery or action as dictated by the system's logic. + +### Flow + +**Flow** is the sophisticated mechanism responsible for handling and manipulating the Pulses as they move through +the system. + +- **Message Handling**: It's specifically designed to process each Pulse, applying necessary transformations, routing, + and any other required operations. +- **Flexibility and Adaptability**: PulseFlow is adept at handling various types of Pulses, capable of adapting its + processing logic based on the nature and requirements of each message. +- **Integration Point**: Acting as a key integration point within the system, it ensures that Pulses are managed + efficiently and effectively, readying them for their next phase in the data journey. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Contributing -Frank.PulseFlow simplifies message handling, making your .NET applications more efficient and modular. +Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details. \ No newline at end of file diff --git a/STYLE.md b/STYLE.md new file mode 100644 index 0000000..3902824 --- /dev/null +++ b/STYLE.md @@ -0,0 +1,114 @@ +# Style Guide + +## Introduction + +This document describes the coding style used in this repository. It is based on SOLID principles, and should emphasize Dependency Injections, and the Single Responsibility Principle. + +## Table of Contents + +## Naming Conventions + +| Token | Convention | Grammar Terms | Example | +|----------------|-------------|-----------------|-------------------| +| Namespace | PascalCase | Noun | `Frank.PulseFlow` | +| Class | PascalCase | Noun | `PulseFlow` | +| Interface | IPascalCase | Noun | `IPulseFlow` | +| Enum | PascalCase | Noun | `PulseFlowState` | +| Enum Value | PascalCase | Noun, Adjective | `Running` | +| Method | PascalCase | Verb | `Start` | +| Property | PascalCase | Noun | `State` | +| Field | _camelCase | Noun | `_state` | +| Parameter | camelCase | Noun | `state` | +| Local Variable | camelCase | Noun | `state` | +| Constant | PascalCase | Noun | `Running` | +| Event | PascalCase | Noun | `Started` | +| Delegate | PascalCase | Noun | `Started` | +| Type Parameter | PascalCase | Noun | `TKey` | +| Type Argument | PascalCase | Noun | `string` | + +## General Guidelines + +### Use `var` when possible + +Use `var` when the type of the variable is obvious from the right-hand side of the assignment, (e.g. `var x = 1;` is fine, but `var x = new Foo();` is not). + +### Use `nameof` when possible + +Use `nameof` when the name of the variable is needed, (e.g. `nameof(foo)` instead of `"foo"`). + +### Use `const` when possible + +Use `const` when the value of the variable is known at compile time, (e.g. `const int x = 1;` is fine, but `const int x = Foo();` is not). + +### Use `readonly` when possible + +Use `readonly` when the value of the variable is known at compile time, and the variable is not a constant, (e.g. `readonly int x = 1;` is fine, but `readonly int x = Foo();` is not). + +### Use `static` when possible + +Use `static` when the value of the variable is known at compile time, and the variable is not a constant, (e.g. `static int x = 1;` is fine, but `static int x = Foo();` is not). + +### Use Expression-Bodied Members when possible + +Use Expression-Bodied Members when the body of the member is a single expression, (e.g. `public int Foo() => 1;` is fine, but `public int Foo() { return 1; }` is not). + +## Class Guidelines + +### Use `sealed` when possible + +Use `sealed` when the class is not intended to be inherited from, (e.g. `sealed class Foo { }` is fine, but `class Foo { }` is not). + +### Use `static` when possible + +Use `static` when the class is not intended to be instantiated, (e.g. `static class Foo { }` is fine, but `class Foo { }` is not). + +## Helper Class Guidelines + +### Use `static` always + +All helper classes should be `static`, (e.g. `static class Foo { }` is fine, but `class Foo { }` is not). + +### Helpers should be `internal` or `private` unless they are intended to be used outside of the assembly + +All helper classes should be `internal` or `private` unless they are intended to be used outside of the assembly, (e.g. `internal static class Foo { }` is fine, but `public static class Foo { }` is not). + +When a helper class is intended to be used outside of the assembly, it should be `public`, (e.g. `public static class Foo { }` is fine, but `internal static class Foo { }` is not). This is rare, and should be avoided if possible, but something like a DateTime helper class that expose Week based operations might be useful to other assemblies. + +## Interface Guidelines + +### Use `I` prefix always + +All interfaces should be prefixed with `I`, (e.g. `IPulseFlow` is fine, but `PulseFlow` is not). + +### Use `internal` or `public` always + +All interfaces should be `internal` or `public`, (e.g. `internal interface IPulseFlow { }` is fine, but `private interface IPulseFlow { }` is not). + +## Enum Guidelines + +### Use `PascalCase` always + +All enums should be `PascalCase`, (e.g. `enum PulseFlowState { Running, Stopped }` is fine, but `enum PulseFlowState { running, stopped }` is not). + +### Don't suffix with `Enum`, 'Type', or `Flag` + +Don't suffix with `Enum`, 'Type', or `Flag`, (e.g. `enum PulseFlowState { Running, Stopped }` is fine, but `enum PulseFlowStateEnum { Running, Stopped }` is not). + +### Don't use `Flags` unless the enum is intended to be used as a set of flags + +Don't use `Flags` unless the enum is intended to be used as a set of flags, (e.g. `enum PulseFlowState { Running, Stopped }` is fine, but `enum PulseFlowState { Running = 1, Stopped = 2 }` is not). + +### Use `internal` or `public` always + +All enums should be `internal` or `public`, (e.g. `internal enum PulseFlowState { Running, Stopped }` is fine, but `private enum PulseFlowState { Running, Stopped }` is not). + +## Enum Value Guidelines + +### Use `PascalCase` always + +All enum values should be `PascalCase`, (e.g. `enum PulseFlowState { Running, Stopped }` is fine, but `enum PulseFlowState { running, stopped }` is not). + + + + + diff --git a/Frank.PulseFlow/icon.png b/icon.png similarity index 100% rename from Frank.PulseFlow/icon.png rename to icon.png