private async void CheckForUpdates()
        {
            updateMessage.text        = "Checking...";
            updateMessage.color       = Color.gray;
            updateButton.interactable = false;

            UpdateChecker.Release release = await UpdateChecker.GetNewestReleaseAsync(CancellationToken.None);

            if (release != null)
            {
                int status = UpdateChecker.CompareRelease(release);
                if (status < 0)
                {
                    // GitHub version is lower than local version, the heck how
                    Plugin.Log.Info("Plugin version is higher than on GitHub???");
                    updateMessage.text = "Higher version";
                }
                else if (status == 0)
                {
                    // GitHub version is the same as local version
                    updateMessage.text = "Up to date";
                }
                else
                {
                    // GitHub version is higher than local version and plugin needs to be updated
                    Plugin.Log.Info("Plugin needs to be updated.");
                    updateMessage.text        = "Update available";
                    updateMessage.color       = Color.green;
                    updateButton.interactable = true;
                }
            }
            else
            {
                // Failed to get release information
                Plugin.Log.Info("Failed to retrieve release information.");
                updateMessage.text  = "Update check failed";
                updateMessage.color = Color.red;
            }
        }
 private void OnCheckUpdateCompleted(object sender, UpdateChecker.CheckUpdateEventArgs e)
 {
     try
     {
         string text = null;
         if (e.App == UpdateChecker.App.GUI)
         {
             text = e.ReleaseList.Count == 0 ?
                    I18N.GetString("GUI is up to date") :
                    string.Format(I18N.GetString("New GUI version {0} is available"), e.ReleaseList[0].version);
             ShowBalloonTip("", text, ToolTipIcon.Info, 3000);
             if (e.ReleaseList.Count > 0)
             {
                 BalloonTopOpenWebPageAction action = new BalloonTopOpenWebPageAction(UpdateChecker.GUI_RELEASE_PAGE, 4000);
                 action.Timeout += OnBalloonTipActionTimeout;
                 action.Tag      = _balloonTipActions.AddLast(action);
             }
         }
         else if (e.App == UpdateChecker.App.KCPTun)
         {
             UpdateChecker.Release release = null;
             string arch = Environment.Is64BitOperatingSystem ? "windows-amd64" : "windows-386";
             foreach (UpdateChecker.Release r in e.ReleaseList)
             {
                 if (r.name.IndexOf(arch) > 0)
                 {
                     release = r;
                     break;
                 }
             }
             if (release != null)
             {
                 if (e.UserState != null || controller.ConfigController.GetConfigurationCopy().auto_upgrade_kcptun)
                 {
                     controller.UpdateChecker.Download(release);
                 }
                 else
                 {
                     text = string.Format(I18N.GetString("New kcptun version {0} is available"), release.version);
                     ShowBalloonTip("", text, ToolTipIcon.Info, 3000);
                     BalloonTopOpenWebPageAction action = new BalloonTopOpenWebPageAction(UpdateChecker.KCPTUN_RELEASE_PAGE, 3000);
                     action.Timeout += OnBalloonTipActionTimeout;
                     action.Tag      = _balloonTipActions.AddLast(action);
                 }
             }
             else
             {
                 text = I18N.GetString("kcptun is up to date");
                 ShowBalloonTip("", text, ToolTipIcon.Info, 3000);
             }
         }
         else
         {
             /* do nothing */
         }
     }
     catch (Exception ex)
     {
         Logging.LogUsefulException(ex);
     }
 }