Init RaspberryIO
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
namespace Unosquare.Swan.Abstractions
|
||||
{
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// A base implementation of an Application service containing a worker task that performs background processing.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following code describes how to implement the <see cref="AppWorkerBase"/> class.
|
||||
/// <code>
|
||||
/// using System;
|
||||
/// using System.Threading.Tasks;
|
||||
/// using Unosquare.Swan;
|
||||
/// using Unosquare.Swan.Abstractions;
|
||||
///
|
||||
/// class Worker : AppWorkerBase
|
||||
/// {
|
||||
/// // an action that will be executed if the worker is stopped
|
||||
/// public Action OnExit { get; set; }
|
||||
///
|
||||
/// // override the base loop method, this is the code will
|
||||
/// // execute until the cancellation token is canceled.
|
||||
/// protected override Task WorkerThreadLoop()
|
||||
/// {
|
||||
/// // delay a second and then proceed
|
||||
/// await Task.Delay(TimeSpan.FromMilliseconds(1000), CancellationToken);
|
||||
///
|
||||
/// // just print out this
|
||||
/// $"Working...".WriteLine();
|
||||
/// }
|
||||
///
|
||||
/// // Once the worker is stopped this code will be executed
|
||||
/// protected override void OnWorkerThreadExit()
|
||||
/// {
|
||||
/// // execute the base method
|
||||
/// base.OnWorkerThreadExit();
|
||||
///
|
||||
/// // then if the OnExit Action is not null execute it
|
||||
/// OnExit?.Invoke();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public abstract class AppWorkerBase
|
||||
: IWorker, IDisposable
|
||||
{
|
||||
private readonly object _syncLock = new object();
|
||||
private AppWorkerState _workerState = AppWorkerState.Stopped;
|
||||
private CancellationTokenSource _tokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AppWorkerBase"/> class.
|
||||
/// </summary>
|
||||
protected AppWorkerBase()
|
||||
{
|
||||
State = AppWorkerState.Stopped;
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [state changed].
|
||||
/// </summary>
|
||||
public event EventHandler<AppWorkerStateChangedEventArgs> StateChanged;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state of the application service.
|
||||
/// In other words, useful to know whether the service is running.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The state.
|
||||
/// </value>
|
||||
public AppWorkerState State
|
||||
{
|
||||
get => _workerState;
|
||||
|
||||
private set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (value == _workerState) return;
|
||||
|
||||
$"Service state changing from {State} to {value}".Debug(GetType().Name);
|
||||
var newState = value;
|
||||
var oldState = _workerState;
|
||||
_workerState = value;
|
||||
|
||||
StateChanged?.Invoke(this, new AppWorkerStateChangedEventArgs(oldState, newState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cancellation token.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The cancellation token.
|
||||
/// </value>
|
||||
public CancellationToken CancellationToken => _tokenSource?.Token ?? default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the thread is busy.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is busy; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsBusy { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region AppWorkerBase Methods
|
||||
|
||||
/// <summary>
|
||||
/// Performs internal service initialization tasks required before starting the service.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Service cannot be initialized because it seems to be currently running.</exception>
|
||||
public virtual void Initialize() => CheckIsRunning();
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <exception cref="InvalidOperationException">Service cannot be started because it seems to be currently running.</exception>
|
||||
public virtual void Start()
|
||||
{
|
||||
CheckIsRunning();
|
||||
|
||||
CreateWorker();
|
||||
State = AppWorkerState.Running;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <exception cref="InvalidOperationException">Service cannot be stopped because it is not running.</exception>
|
||||
public virtual void Stop()
|
||||
{
|
||||
if (State != AppWorkerState.Running)
|
||||
return;
|
||||
|
||||
_tokenSource?.Cancel();
|
||||
"Service stop requested.".Debug(GetType().Name);
|
||||
State = AppWorkerState.Stopped;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => _tokenSource?.Dispose();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Abstract and Virtual Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called when an unhandled exception is thrown.
|
||||
/// </summary>
|
||||
/// <param name="ex">The ex.</param>
|
||||
protected virtual void OnWorkerThreadLoopException(Exception ex)
|
||||
=> "Service exception detected.".Debug(GetType().Name, ex);
|
||||
|
||||
/// <summary>
|
||||
/// This method is called when the user loop has exited.
|
||||
/// </summary>
|
||||
protected virtual void OnWorkerThreadExit() => "Service thread is stopping.".Debug(GetType().Name);
|
||||
|
||||
/// <summary>
|
||||
/// Implement this method as a loop that checks whether CancellationPending has been set to true
|
||||
/// If so, immediately exit the loop.
|
||||
/// </summary>
|
||||
/// <returns>A task representing the execution of the worker.</returns>
|
||||
protected abstract Task WorkerThreadLoop();
|
||||
|
||||
private void CheckIsRunning()
|
||||
{
|
||||
if (State != AppWorkerState.Stopped)
|
||||
throw new InvalidOperationException("Service cannot be initialized because it seems to be currently running.");
|
||||
}
|
||||
|
||||
private void CreateWorker()
|
||||
{
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
_tokenSource.Token.Register(() =>
|
||||
{
|
||||
IsBusy = false;
|
||||
OnWorkerThreadExit();
|
||||
});
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
IsBusy = true;
|
||||
|
||||
try
|
||||
{
|
||||
while (!CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await WorkerThreadLoop().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Log(GetType().Name);
|
||||
OnWorkerThreadLoopException(ex);
|
||||
|
||||
if (!_tokenSource.IsCancellationRequested)
|
||||
_tokenSource.Cancel();
|
||||
}
|
||||
},
|
||||
_tokenSource.Token);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Unosquare.Swan.Abstractions
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents event arguments whenever the state of an application service changes.
|
||||
/// </summary>
|
||||
public class AppWorkerStateChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AppWorkerStateChangedEventArgs" /> class.
|
||||
/// </summary>
|
||||
/// <param name="oldState">The old state.</param>
|
||||
/// <param name="newState">The new state.</param>
|
||||
public AppWorkerStateChangedEventArgs(AppWorkerState oldState, AppWorkerState newState)
|
||||
{
|
||||
OldState = oldState;
|
||||
NewState = newState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state to which the application service changed.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The new state.
|
||||
/// </value>
|
||||
public AppWorkerState NewState { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the old state.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The old state.
|
||||
/// </value>
|
||||
public AppWorkerState OldState { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#if !NET452
|
||||
namespace Unosquare.Swan.Abstractions
|
||||
{
|
||||
/// <summary>
|
||||
/// Mimic a Windows ServiceBase class. Useful to keep compatibility with applications
|
||||
/// running as services in OS different to Windows.
|
||||
/// </summary>
|
||||
public abstract class ServiceBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the service can be stopped once it has started.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance can stop; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool CanStop { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the service should be notified when the system is shutting down.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance can shutdown; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool CanShutdown { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the service can be paused and resumed.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance can pause and continue; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool CanPauseAndContinue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exit code.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The exit code.
|
||||
/// </value>
|
||||
public int ExitCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether to report Start, Stop, Pause, and Continue commands in the event log.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [automatic log]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool AutoLog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the service.
|
||||
/// </value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stops the executing service.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (!CanStop) return;
|
||||
|
||||
CanStop = false;
|
||||
OnStop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, executes when a Start command is sent to the service by the Service Control Manager (SCM)
|
||||
/// or when the operating system starts (for a service that starts automatically). Specifies actions to take when the service starts.
|
||||
/// </summary>
|
||||
/// <param name="args">The arguments.</param>
|
||||
protected virtual void OnStart(string[] args)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When implemented in a derived class, executes when a Stop command is sent to the service by the Service Control Manager (SCM).
|
||||
/// Specifies actions to take when a service stops running.
|
||||
/// </summary>
|
||||
protected virtual void OnStop()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user