-
Notifications
You must be signed in to change notification settings - Fork 769
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #548 from dotnet-state-machine/dev
Release 5.14.0
- Loading branch information
Showing
52 changed files
with
1,477 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Contributing to Stateless | ||
|
||
If you're reading this page, thank you for considering making a contribution to Stateless! This project depends on the work of the community. As maintainers, we'll try our best to make bug fixes, review PRs, and respond to issues and feature requests. | ||
|
||
## Getting Started | ||
|
||
If you've found a bug, need a new feature or want to suggest a change, be sure to take a look through the [issues](https://github.com/dotnet-state-machine/stateless/issues?q=is%3Aissue) and [pull requests](https://github.com/dotnet-state-machine/stateless/pulls) in case it's been discussed before or is already in progress. | ||
|
||
If you've found a security vulnerability, please report it using the [Security Advisories](https://github.com/dotnet-state-machine/stateless/security/advisories) page. | ||
|
||
For anyone new to contributing to open source, there are some great guides to help you get started, such as [this one by freeCodeCamp.org](https://github.com/freeCodeCamp/how-to-contribute-to-open-source) and [this one from Open Source Guides](https://opensource.guide/how-to-contribute/). | ||
|
||
## General Guidance | ||
|
||
It's best to start by discussing a proposed change in an [issue](https://github.com/dotnet-state-machine/stateless/issues), be it a new issue you've created or an existing issue you're willing to help with. Let others know you're working on it. | ||
|
||
Check that your [fork is synced with the upsream repo](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork) before you start working on a change, then create a branch from it and commit your changes to that branch. When you're ready for the change to be reviewed, create a pull request to merge your change back to the upstream `dotnet-state-machine:dev` branch. | ||
|
||
Please make sure your change meets the following criteria before raising a pull request: | ||
|
||
* Keep the change relevant to the specific issue being addressed; making changes that haven't been discussed could have unintended side effects. | ||
* Add unit test coverage for your work; this not only helps to validate that your change works as described, it also acts as documentation and helps to defend against future regressions. | ||
* Update the documentation! Help others benefit from your work by including guidance in the README. | ||
* Be open and encouraging to constructive feedback; reviewers may ask for further changes or may want to discuss alternative approaches; the project will benefit from your patience and your willingness to engage with reviewers. | ||
|
||
## Other Ways to Contribute | ||
|
||
* Participate in open discussions, for instance by helping to answer questions or offering guidance to others. | ||
* Improve the documentation, even something as small as fixing a typo or including a code snippet in the README; it all helps. | ||
* Review a pull request; take a look through the [open pull requests](https://github.com/dotnet-state-machine/stateless/pulls) and offer constructive feedback. | ||
* Boost the project; star the repository, mention it on social media, or link to it in your project's README. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Security Policy | ||
|
||
## Reporting a Vulnerability | ||
|
||
If you discover a security vulnerability in Stateles, please report it via the [Security Advisories](https://github.com/dotnet-state-machine/stateless/security/advisories) page. Creating a security advistory will notify the project owners and allow them to assess it and take appropriate action to resolve it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
using AlarmExample; | ||
using Stateless; | ||
using System.Diagnostics; | ||
|
||
namespace AlarmExample | ||
{ | ||
/// <summary> | ||
/// A sample class that implements an alarm as a state machine using Stateless | ||
/// (https://github.com/dotnet-state-machine/stateless). | ||
/// | ||
/// It also shows one way that temporary states can be implemented with the use of | ||
/// Timers. PreArmed, PreTriggered, Triggered, and ArmPaused are "temporary" states with | ||
/// a configurable delay (i.e. to allow for an "arm delay"... a delay between Disarmed | ||
/// and Armed). The Triggered state is also considered temporary, since if an alarm | ||
/// sounds for a certain period of time and no-one Acknowledges it, the state machine | ||
/// returns to the Armed state. | ||
/// | ||
/// Timers are triggered via OnEntry() and OnExit() methods. Transitions are written to | ||
/// the Trace in order to show what happens. | ||
/// | ||
/// The included PNG file shows what the state flow looks like. | ||
/// | ||
/// </summary> | ||
public partial class Alarm | ||
{ | ||
/// <summary> | ||
/// Moves the Alarm into the provided <see cref="AlarmState" /> via the defined <see cref="AlarmCommand" />. | ||
/// </summary> | ||
/// <param name="command">The <see cref="AlarmCommand" /> to execute on the current <see cref="AlarmState" />.</param> | ||
/// <returns>The new <see cref="AlarmState" />.</returns> | ||
public AlarmState ExecuteTransition(AlarmCommand command) | ||
{ | ||
if (_machine.CanFire(command)) | ||
{ | ||
_machine.Fire(command); | ||
} | ||
else | ||
{ | ||
throw new InvalidOperationException($"Cannot transition from {CurrentState} via {command}"); | ||
} | ||
|
||
return CurrentState(); | ||
} | ||
|
||
/// <summary> | ||
/// The current <see cref="AlarmState" /> of the alarm. | ||
/// </summary> | ||
public AlarmState CurrentState() | ||
{ | ||
if (_machine != null) | ||
return _machine.State; | ||
else | ||
throw new InvalidOperationException("Alarm hasn't been configured yet."); | ||
} | ||
|
||
/// <summary> | ||
/// Defines whether the <see cref="Alarm"/> has been configured. | ||
/// </summary> | ||
public bool IsConfigured { get; private set; } | ||
|
||
/// <summary> | ||
/// Returns whether the provided command is a valid transition from the Current State. | ||
/// </summary> | ||
/// <param name="command"></param> | ||
/// <returns></returns> | ||
public bool CanFireCommand(AlarmCommand command) | ||
{ | ||
return _machine.CanFire(command); | ||
} | ||
|
||
/// <summary> | ||
/// Default constructor. | ||
/// </summary> | ||
/// <param name="armDelay">The time (in seconds) the alarm will spend in the | ||
/// Prearmed status before continuing to the Armed status (if not transitioned to | ||
/// Disarmed via Disarm).</param> | ||
/// <param name="pauseDelay">The time (in seconds) the alarm will spend in the | ||
/// ArmPaused status before returning to Armed (if not transitioned to Triggered | ||
/// via Trigger).</param> | ||
/// <param name="triggerDelay">The time (in seconds) the alarm will spend in the | ||
/// PreTriggered status before continuing to the Triggered status (if not | ||
/// transitioned to Disarmed via Disarm).</param> | ||
/// <param name="triggerTimeOut">The time (in seconds) the alarm will spend in the | ||
/// Triggered status before returning to the Armed status (if not transitioned to | ||
/// Disarmed via Disarm).</param> | ||
public Alarm(int armDelay, int pauseDelay, int triggerDelay, int triggerTimeOut) | ||
{ | ||
_machine = new StateMachine<AlarmState, AlarmCommand>(AlarmState.Undefined); | ||
|
||
preArmTimer = new System.Timers .Timer(armDelay * 1000) { AutoReset = false, Enabled = false }; | ||
preArmTimer.Elapsed += TimeoutTimerElapsed; | ||
pauseTimer = new System.Timers.Timer(pauseDelay * 1000) { AutoReset = false, Enabled = false }; | ||
pauseTimer.Elapsed += TimeoutTimerElapsed; | ||
triggerDelayTimer = new System.Timers.Timer(triggerDelay * 1000) { AutoReset = false, Enabled = false }; | ||
triggerDelayTimer.Elapsed += TimeoutTimerElapsed; | ||
triggerTimeOutTimer = new System.Timers.Timer(triggerTimeOut * 1000) { AutoReset = false, Enabled = false }; | ||
triggerTimeOutTimer.Elapsed += TimeoutTimerElapsed; | ||
|
||
_machine.OnTransitioned(OnTransition); | ||
|
||
_machine.Configure(AlarmState.Undefined) | ||
.Permit(AlarmCommand.Startup, AlarmState.Disarmed) | ||
.OnExit(() => IsConfigured = true); | ||
|
||
_machine.Configure(AlarmState.Disarmed) | ||
.Permit(AlarmCommand.Arm, AlarmState.Prearmed); | ||
|
||
_machine.Configure(AlarmState.Armed) | ||
.Permit(AlarmCommand.Disarm, AlarmState.Disarmed) | ||
.Permit(AlarmCommand.Trigger, AlarmState.PreTriggered) | ||
.Permit(AlarmCommand.Pause, AlarmState.ArmPaused); | ||
|
||
_machine.Configure(AlarmState.Prearmed) | ||
.OnEntry(() => ConfigureTimer(true, preArmTimer, "Pre-arm")) | ||
.OnExit(() => ConfigureTimer(false, preArmTimer, "Pre-arm")) | ||
.Permit(AlarmCommand.TimeOut, AlarmState.Armed) | ||
.Permit(AlarmCommand.Disarm, AlarmState.Disarmed); | ||
|
||
_machine.Configure(AlarmState.ArmPaused) | ||
.OnEntry(() => ConfigureTimer(true, pauseTimer, "Pause delay")) | ||
.OnExit(() => ConfigureTimer(false, pauseTimer, "Pause delay")) | ||
.Permit(AlarmCommand.TimeOut, AlarmState.Armed) | ||
.Permit(AlarmCommand.Trigger, AlarmState.PreTriggered); | ||
|
||
_machine.Configure(AlarmState.Triggered) | ||
.OnEntry(() => ConfigureTimer(true, triggerTimeOutTimer, "Trigger timeout")) | ||
.OnExit(() => ConfigureTimer(false, triggerTimeOutTimer, "Trigger timeout")) | ||
.Permit(AlarmCommand.TimeOut, AlarmState.Armed) | ||
.Permit(AlarmCommand.Acknowledge, AlarmState.Acknowledged); | ||
|
||
_machine.Configure(AlarmState.PreTriggered) | ||
.OnEntry(() => ConfigureTimer(true, triggerDelayTimer, "Trigger delay")) | ||
.OnExit(() => ConfigureTimer(false, triggerDelayTimer, "Trigger delay")) | ||
.Permit(AlarmCommand.TimeOut, AlarmState.Triggered) | ||
.Permit(AlarmCommand.Disarm, AlarmState.Disarmed); | ||
|
||
_machine.Configure(AlarmState.Acknowledged) | ||
.Permit(AlarmCommand.Disarm, AlarmState.Disarmed); | ||
|
||
_machine.Fire(AlarmCommand.Startup); | ||
} | ||
|
||
private void TimeoutTimerElapsed(object? sender, System.Timers.ElapsedEventArgs e) | ||
{ | ||
_machine.Fire(AlarmCommand.TimeOut); | ||
} | ||
|
||
private void ConfigureTimer(bool active, System.Timers.Timer timer, string timerName) | ||
{ | ||
if (timer != null) | ||
if (active) | ||
{ | ||
timer.Start(); | ||
Trace.WriteLine($"{timerName} started."); | ||
} | ||
else | ||
{ | ||
timer.Stop(); | ||
Trace.WriteLine($"{timerName} cancelled."); | ||
} | ||
} | ||
|
||
private void OnTransition(StateMachine<AlarmState, AlarmCommand>.Transition transition) | ||
{ | ||
Trace.WriteLine($"Transitioned from {transition.Source} to " + | ||
$"{transition.Destination} via {transition.Trigger}."); | ||
} | ||
|
||
private StateMachine<AlarmState, AlarmCommand> _machine; | ||
private System.Timers.Timer? preArmTimer; | ||
private System.Timers.Timer? pauseTimer; | ||
private System.Timers.Timer? triggerDelayTimer; | ||
private System.Timers.Timer? triggerTimeOutTimer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
namespace AlarmExample | ||
{ | ||
public enum AlarmCommand | ||
{ | ||
Startup, | ||
Arm, | ||
Disarm, | ||
Trigger, | ||
Acknowledge, | ||
Pause, | ||
TimeOut | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Stateless\Stateless.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Oops, something went wrong.