using System; using System.Threading; using System.Threading.Tasks; using System.Timers; using TweetLib.Core.Data; using Timer = System.Timers.Timer; namespace TweetLib.Core.Systems.Updates{ public sealed class UpdateHandler : IDisposable{ public const int CheckCodeUpdatesDisabled = -1; private readonly IUpdateCheckClient client; private readonly TaskScheduler scheduler; private readonly Timer timer; public event EventHandler<UpdateCheckEventArgs>? CheckFinished; private ushort lastEventId; public UpdateHandler(IUpdateCheckClient client, TaskScheduler scheduler){ this.client = client; this.scheduler = scheduler; this.timer = new Timer{ AutoReset = false, Enabled = false }; this.timer.Elapsed += timer_Elapsed; } public void Dispose(){ timer.Dispose(); } private void timer_Elapsed(object sender, ElapsedEventArgs e){ Check(false); } public void StartTimer(){ if (timer.Enabled){ return; } timer.Stop(); if (client.CanCheck){ DateTime now = DateTime.Now; TimeSpan nextHour = now.AddSeconds(60 * (60 - now.Minute) - now.Second) - now; if (nextHour.TotalMinutes < 15){ nextHour = nextHour.Add(TimeSpan.FromHours(1)); } timer.Interval = (int)Math.Ceiling(nextHour.TotalMilliseconds); timer.Start(); } } public int Check(bool force){ if (client.CanCheck || force){ int nextEventId = unchecked(++lastEventId); Task<UpdateInfo> checkTask = client.Check(); checkTask.ContinueWith(task => HandleUpdateCheckSuccessful(nextEventId, task.Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler); checkTask.ContinueWith(task => HandleUpdateCheckFailed(nextEventId, task.Exception.InnerException), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, scheduler); return nextEventId; } return CheckCodeUpdatesDisabled; } private void HandleUpdateCheckSuccessful(int eventId, UpdateInfo info){ CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(info))); } private void HandleUpdateCheckFailed(int eventId, Exception exception){ CheckFinished?.Invoke(this, new UpdateCheckEventArgs(eventId, new Result<UpdateInfo>(exception))); } } }