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); } } }