Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 5.14.0 #548

Merged
merged 67 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
2fed1cf
Enable Source Link and Determnistic Builds; don't attempt to publish …
mclift Dec 30, 2022
aff2f73
Merge branch 'dotnet-state-machine:dev' into feature/net-foundation-r…
mclift Dec 30, 2022
ec93a7c
Merge pull request #3 from mclift/feature/net-foundation-recommendations
mclift Dec 30, 2022
a436129
Remove unsupported input.
mclift Dec 30, 2022
0883481
Create SECURITY.md
mclift Dec 30, 2022
159b88f
Create CONTRIBUTING.md
mclift Dec 31, 2022
cbdeef9
Link to CONTRIBUTING.md in README.
mclift Dec 31, 2022
3a0d1fe
Merge pull request #501 from mclift/dev
mclift Jan 27, 2023
03e9752
Merge pull request #502 from dotnet-state-machine/docs/security-policy
mclift Jan 27, 2023
05d4432
Merge pull request #503 from dotnet-state-machine/docs/contributing
mclift Jan 27, 2023
b6a77a4
fix: InternalTransitionAsyncIf guard parameters
LipatovAlexander Apr 11, 2023
f755ddf
Represent async "entry actions from trigger" in the same way as the s…
Apr 11, 2023
46d3883
Fix spelling mistake "fireing" to "firing"
Apr 11, 2023
a74dc78
For StateInfo, Substates, FixedTransitions and DynamicTransitions are…
Apr 12, 2023
1cbd658
Restore the newline at the end of ActionInfo.cs
Apr 14, 2023
a6343fc
Merge pull request #514 from leeoades/bugfix-StateMachineInfo.Initial…
mclift Apr 14, 2023
22149f4
Merge pull request #512 from leeoades/fix-spelling-mistake-firing
mclift Apr 14, 2023
8c03b2b
Implemented an example for an alarm.
celloza Apr 14, 2023
83bae7a
Merge pull request #511 from leeoades/bugfix-async-entry-actions-lack…
crozone Apr 17, 2023
5775438
Add an option to retain the synchronization context
Apr 24, 2023
e465b90
Make specifying whether to retain the sync context on StateRepresenta…
Apr 24, 2023
cefd21c
Specify whether to retain the sync context on StateRepresentation eve…
Apr 24, 2023
c9ffd2c
Also apply the sync context to a sync action internal trigger
Apr 24, 2023
4625bcd
Make test clearer
Apr 24, 2023
1a185a7
Added comments
Apr 24, 2023
a5a35ca
Remove unused using declarations
Apr 24, 2023
ce95223
Added documentation to the README
Apr 25, 2023
b2b3a40
Further documentation of the tests
Apr 25, 2023
12e0b11
Update example apps to net6.0
Apr 25, 2023
487842c
Fix typo
Apr 25, 2023
d9f5778
Fix typos
Apr 25, 2023
fa6bb4e
Remove redundant parentheses
Apr 25, 2023
3408c7d
Remove obsolete TargetFrameworks
pentp Apr 25, 2023
3b64d8f
Replace net45 and net472 with net462
pentp Apr 25, 2023
0f8b36b
Merge pull request #521 from leeoades/fix-typos
mclift Apr 28, 2023
e2d6d73
Merge branch 'dev' into retain-synchronizationcontext
mclift Apr 28, 2023
5bef9ad
Remove the two tests that do not prove that the sync context is lost …
leeoades Apr 29, 2023
9311ad4
Merge pull request #519 from leeoades/retain-synchronizationcontext
mclift Apr 29, 2023
e46e521
Merge pull request #520 from leeoades/upgrade-example-apps-to-net6
mclift Apr 29, 2023
19793af
Merge pull request #522 from leeoades/remove-redundant-parentheses
mclift Apr 29, 2023
7a84e2b
Bump solution to VS 2022
mclift Apr 29, 2023
1c36356
There is a race condition where Task.Delay could theoretically finish…
leeoades Apr 29, 2023
2473872
Use Task.Yield instead
leeoades Apr 30, 2023
860de43
Revert "Use Task.Yield instead"
leeoades Apr 30, 2023
e69c66c
Merge pull request #528 from leeoades/bugfix/guarantee-synchronizatio…
mclift May 10, 2023
ff6ad59
Merge pull request #526 from mclift/update-vs-version
mclift May 10, 2023
14472a3
Merge branch 'dev' into celloza/alarmexample
celloza May 31, 2023
57c68f2
Merge pull request #510 from teal-inc/lipatov/850-internal-transition…
mclift Jun 2, 2023
c5ad663
Restore and deprecate old InternalTransitionAsyncIf signatures.
mclift Jun 2, 2023
0ba05aa
Merge pull request #516 from celloza/celloza/alarmexample
mclift Jun 2, 2023
2ab545b
bugfix: Execute OnEntryFromAsync actions asynchronously
mclift Jun 2, 2023
5bcedd6
Throw InvalidOperationException when firing async action synchronously.
mclift Jun 2, 2023
22e29cd
Merge pull request #524 from pentp/obsolete-targets
mclift Jun 11, 2023
b45b999
Merge pull request #532 from mclift/bugfix/OnEntryFromAsync-InvalidOp…
mclift Jul 4, 2023
dc70a9d
Merge pull request #530 from dotnet-state-machine/850-internal-transi…
mclift Jul 4, 2023
63c8d51
Added FireAsync(TriggerWithParameters, params object[]) overload
DeepakParamkusam Jul 14, 2023
f9b291b
In the case of a superstate having a trigger that moves the state to …
Oct 5, 2023
1f9a302
Update README.md
jafin Oct 7, 2023
e88e6eb
Merge pull request #545 from jafin/fix/readme-link
HenningNT Nov 3, 2023
99e49a8
Merge pull request #544 from hooligan495/bugfix/543_prevent_reentry
mclift Nov 8, 2023
996bb50
Release 5.14.0
mclift Nov 8, 2023
d1f08d6
Bump date in CHANGELOG.md
mclift Nov 9, 2023
bdcf10f
Fix typo in CHANGELOG.md
mclift Nov 9, 2023
3cf3106
Bump date in CHANGELOG.md
mclift Nov 10, 2023
7a35aaf
Merge pull request #536 from DeepakParamkusam/fire-async-param
mclift Nov 13, 2023
e28496c
Added PR to ChangeLog; bumped date.
mclift Nov 13, 2023
b936479
Bump date in CHANGELOG
mclift Nov 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions .github/workflows/BuildAndTestOnPullRequests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,33 @@ on:
push:
branches: [ dev, master ]
pull_request:
branches: [ dev , master ]
branches: [ dev, master ]

jobs:
Build_Stateless_solution:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
dotnet-version: 3.1.101
- uses: actions/checkout@v3

- name: Install dependencies
run: dotnet restore

- name: Build Stateless solution
run: dotnet build Stateless.sln --configuration Release --no-restore
run: dotnet build Stateless.sln --configuration Release --no-restore

- name: Test Stateless
run: dotnet test --no-restore --no-build --configuration Release

- name: Pack alpha version
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
if: github.ref == 'refs/heads/dev' && github.event_name == 'push' && github.repository == 'dotnet-state-machine/stateless'
run: dotnet pack src\Stateless\Stateless.csproj --version-suffix dev-${{github.run_id}} --configuration Release
- name: Publish alpha version
if: github.ref == 'refs/heads/dev' && github.event_name == 'push'
if: github.ref == 'refs/heads/dev' && github.event_name == 'push' && github.repository == 'dotnet-state-machine/stateless'
run: dotnet nuget push src\Stateless\bin\Release\*.nupkg -s nuget.org --api-key ${{ secrets.NUGETAPIKEY }}

- name: Pack Release version
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'dotnet-state-machine/stateless'
run: dotnet pack src\Stateless\Stateless.csproj --configuration Release
- name: Publish Release version
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
if: github.ref == 'refs/heads/master' && github.event_name == 'push' && github.repository == 'dotnet-state-machine/stateless'
run: dotnet nuget push src\Stateless\bin\Release\*.nupkg -s nuget.org --api-key ${{ secrets.NUGETAPIKEY }}
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 5.14.0 - 2023.11.14
### Added
- Enable Source Link & Deterministic Builds [#501]
- Added optional `RetainSynchronizationContext` property [#519]
- Update example apps to `net6.0` [#520]
- Bump solution Visual Studio version to 2022 [#526]
- Remove obsolete TargetFrameworks [#524]
- Added `FireAsync(TriggerWithParameters, params object[])` overload [#536]
### Fixed
- `StateMachineInfo.InitialState.Transitions` throws if `AddRelationships` not called [#514]
- Trigger information is missing for `OnEntryFromAsync` [#511]
- Fixed typos & redundant parentheses [#512], [#521], [#522]
- Change mechanism for losing the synchronization context [#528]
- `InvalidOperationException` thrown from call to `FireAsync` [#532]
- Added missing guard function parameter support from `InternalTransitionAsyncIf` [#530]
- Using `PermitIf` on a state with substates leads to reentry [#544]

## 5.13.0 - 2022.12.29
### Added
- Add method to get permitted triggers with parameter information [#494]
Expand Down
31 changes: 31 additions & 0 deletions CONTRIBUTING.md
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.
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ phoneCall.Fire(Trigger.CallDialled);
Assert.AreEqual(State.Ringing, phoneCall.State);
```

This project, as well as the example above, was inspired by [Simple State Machine](http://simplestatemachine.codeplex.com/).
This project, as well as the example above, was inspired by [Simple State Machine (Archived)](https://web.archive.org/web/20170814020207/http://simplestatemachine.codeplex.com/).

## Features

Expand Down Expand Up @@ -124,7 +124,7 @@ phoneCall.Configure(State.OffHook)

Guard clauses within a state must be mutually exclusive (multiple guard clauses cannot be valid at the same time.) Substates can override transitions by respecifying them, however substates cannot disallow transitions that are allowed by the superstate.

The guard clauses will be evaluated whenever a trigger is fired. Guards should therefor be made side effect free.
The guard clauses will be evaluated whenever a trigger is fired. Guards should therefore be made side effect free.

### Parameterised Triggers

Expand Down Expand Up @@ -225,11 +225,30 @@ await stateMachine.FireAsync(Trigger.Assigned);

**Note:** while `StateMachine` may be used _asynchronously_, it remains single-threaded and may not be used _concurrently_ by multiple threads.

## Advanced Features ##

### Retaining the SynchronizationContext ###
In specific situations where all handler methods must be invoked with the consumer's SynchronizationContext, set the _RetainSynchronizationContext_ property on creation:

```csharp
var stateMachine = new StateMachine<State, Trigger>(initialState)
{
RetainSynchronizationContext = true
};
```

Setting this is vital within a Microsoft Orleans Grain for example, which requires the SynchronizationContext in order to make calls to other Grains.

## Building

Stateless runs on .NET 4.0+ and practically all modern .NET platforms by targeting .NET Standard 1.0 and .NET Standard2.0. Visual Studio 2017 or later is required to build the solution.


## Contributing

We welcome contributions to this project. Check [CONTRIBUTING.md](CONTRIBUTING.md) for more info.


## Project Goals

This page is an almost-complete description of Stateless, and its explicit aim is to remain minimal.
Expand Down
5 changes: 5 additions & 0 deletions SECURITY.md
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.
11 changes: 9 additions & 2 deletions Stateless.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29505.145
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{8DE7A8AE-D87D-46A0-9757-88BA4AF7EDA5}"
ProjectSection(SolutionItems) = preProject
Expand Down Expand Up @@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelephoneCallExample", "exa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonExample", "example\JsonExample\JsonExample.csproj", "{809A7873-DD78-4D5D-A432-9718C929BECA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlarmExample", "example\AlarmExample\AlarmExample.csproj", "{4E44B325-F791-4C24-872B-D1454DBBA30D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -66,6 +68,10 @@ Global
{809A7873-DD78-4D5D-A432-9718C929BECA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{809A7873-DD78-4D5D-A432-9718C929BECA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{809A7873-DD78-4D5D-A432-9718C929BECA}.Release|Any CPU.Build.0 = Release|Any CPU
{4E44B325-F791-4C24-872B-D1454DBBA30D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E44B325-F791-4C24-872B-D1454DBBA30D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E44B325-F791-4C24-872B-D1454DBBA30D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E44B325-F791-4C24-872B-D1454DBBA30D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -77,6 +83,7 @@ Global
{19ABDDFE-C040-404E-897B-37BE6C248ED7} = {45C09CCA-6C76-4E10-B386-5D95A7610FE0}
{5182CA95-8E6F-4D16-9790-8F7D1C5A9C87} = {45C09CCA-6C76-4E10-B386-5D95A7610FE0}
{809A7873-DD78-4D5D-A432-9718C929BECA} = {45C09CCA-6C76-4E10-B386-5D95A7610FE0}
{4E44B325-F791-4C24-872B-D1454DBBA30D} = {45C09CCA-6C76-4E10-B386-5D95A7610FE0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7A73ADDC-8150-4AFC-AAF0-BA8B4D7A94D7}
Expand Down
175 changes: 175 additions & 0 deletions example/AlarmExample/Alarm.cs
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;
}
}
13 changes: 13 additions & 0 deletions example/AlarmExample/AlarmCommand.cs
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
}
}
14 changes: 14 additions & 0 deletions example/AlarmExample/AlarmExample.csproj
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>
Loading