using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using TweetDuck.Core.Controls; using TweetDuck.Core.Other.Interfaces; using TweetDuck.Data; using TweetDuck.Updates.Events; using Timer = System.Windows.Forms.Timer; namespace TweetDuck.Updates{ sealed class UpdateHandler : IDisposable{ public const int CheckCodeUpdatesDisabled = -1; public const int CheckCodeNotOnTweetDeck = -2; private readonly UpdateCheckClient client; private readonly TaskScheduler scheduler; private readonly ITweetDeckBrowser browser; private readonly Timer timer; public event EventHandler<UpdateEventArgs> UpdateAccepted; public event EventHandler<UpdateEventArgs> UpdateDelayed; public event EventHandler<UpdateEventArgs> UpdateDismissed; public event EventHandler<UpdateCheckEventArgs> CheckFinished; private ushort lastEventId; private UpdateInfo lastUpdateInfo; public UpdateHandler(ITweetDeckBrowser browser, string installerFolder){ this.client = new UpdateCheckClient(installerFolder); this.scheduler = TaskScheduler.FromCurrentSynchronizationContext(); this.browser = browser; this.browser.RegisterBridge("$TDU", new Bridge(this)); this.timer = new Timer(); this.timer.Tick += timer_Tick; } public void Dispose(){ timer.Dispose(); } private void timer_Tick(object sender, EventArgs e){ timer.Stop(); Check(false); } public void StartTimer(){ if (timer.Enabled){ return; } timer.Stop(); if (Program.UserConfig.EnableUpdateCheck){ 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 (Program.UserConfig.EnableUpdateCheck || force){ if (!browser.IsTweetDeckWebsite){ return CheckCodeNotOnTweetDeck; } 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; } public void PrepareUpdate(UpdateInfo info){ CleanupDownload(); lastUpdateInfo = info; lastUpdateInfo.BeginSilentDownload(); } public void BeginUpdateDownload(Form ownerForm, UpdateInfo updateInfo, Action<UpdateInfo> onFinished){ UpdateDownloadStatus status = updateInfo.DownloadStatus; if (status == UpdateDownloadStatus.Done || status == UpdateDownloadStatus.AssetMissing){ onFinished(updateInfo); } else{ FormUpdateDownload downloadForm = new FormUpdateDownload(updateInfo); downloadForm.VisibleChanged += (sender, args) => { downloadForm.MoveToCenter(ownerForm); ownerForm.Hide(); }; downloadForm.FormClosed += (sender, args) => { if (downloadForm.DialogResult != DialogResult.OK){ updateInfo.CancelDownload(); } downloadForm.Dispose(); onFinished(updateInfo); }; downloadForm.Show(); } } public void CleanupDownload(){ if (lastUpdateInfo != null){ lastUpdateInfo.DeleteInstaller(); lastUpdateInfo = null; } } 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))); } private void TriggerUpdateAcceptedEvent(){ if (lastUpdateInfo != null){ UpdateAccepted?.Invoke(this, new UpdateEventArgs(lastUpdateInfo)); } } private void TriggerUpdateDelayedEvent(){ if (lastUpdateInfo != null){ UpdateDelayed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo)); } } private void TriggerUpdateDismissedEvent(){ if (lastUpdateInfo != null){ UpdateDismissed?.Invoke(this, new UpdateEventArgs(lastUpdateInfo)); CleanupDownload(); } } public sealed class Bridge{ private readonly UpdateHandler owner; public Bridge(UpdateHandler owner){ this.owner = owner; } public void TriggerUpdateCheck(){ owner.Check(false); } public void OnUpdateAccepted(){ owner.TriggerUpdateAcceptedEvent(); } public void OnUpdateDelayed(){ owner.TriggerUpdateDelayedEvent(); } public void OnUpdateDismissed(){ owner.TriggerUpdateDismissedEvent(); } } } }