diff --git a/Implab/Components/PollingComponent.cs b/Implab/Components/PollingComponent.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/PollingComponent.cs @@ -0,0 +1,73 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Implab.Components { + public abstract class PollingComponent : RunnableComponent { + + readonly Timer m_timer; + + readonly CancellationTokenSource m_cancellation = new CancellationTokenSource(); + + /// + /// Poll interval in milliseconds. + /// + /// + public int Interval { get; set; } + + /// + /// Delay to the first poll after start in milliseconds + /// + /// + public int Delay { get; set; } + + /// + /// Indicates how to handle unhandled exceptions in method. + /// + /// + public bool FailOnError { get; set; } + + /// + /// Event for the unhandled exceptions in method. + /// + public event EventHandler UnhandledException; + + protected PollingComponent(bool initialized) : base(initialized) { + m_timer = new Timer(OnTimer); + } + + protected override void RunInternal() { + ScheduleNextPoll(Delay); + } + + + //TODO override stop + + protected abstract Task Poll(CancellationToken ct); + + void ScheduleNextPoll(int timeout) { + lock (SynchronizationObject) { + if (State == ExecutionState.Running) + m_timer.Change(timeout, Timeout.Infinite); + } + } + + void OnTimer(object state) { + try { + Poll(m_cancellation.Token); + } catch (Exception e) { + UnhandledException.DispatchEvent(this, new UnhandledExceptionEventArgs(e, false)); + if (FailOnError) + Fail(e); + } + ScheduleNextPoll(Interval); + } + + protected override void Dispose(bool disposing) { + if (disposing) + Safe.Dispose(m_timer, m_cancellation); + base.Dispose(disposing); + } + + } +} \ No newline at end of file