2022-08-09 00:35:38 +00:00
|
|
|
|
using System;
|
2017-03-07 19:23:42 +00:00
|
|
|
|
using System.Collections.Generic;
|
2016-05-09 19:40:59 +00:00
|
|
|
|
using System.Net;
|
2016-05-10 18:24:15 +00:00
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
using System.Net.Sockets;
|
2017-03-07 19:23:42 +00:00
|
|
|
|
using System.Linq;
|
2025-04-04 03:43:01 +00:00
|
|
|
|
using System.Text.Json;
|
2025-04-03 14:25:04 +00:00
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
|
|
using System.Threading;
|
2016-05-09 19:40:59 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2017-03-06 00:25:17 +00:00
|
|
|
|
using System.Windows;
|
2020-04-21 09:12:17 +00:00
|
|
|
|
using Flow.Launcher.Plugin.SharedCommands;
|
|
|
|
|
|
using Flow.Launcher.Infrastructure;
|
|
|
|
|
|
using Flow.Launcher.Infrastructure.Http;
|
|
|
|
|
|
using Flow.Launcher.Infrastructure.UserSettings;
|
2020-07-05 22:00:22 +00:00
|
|
|
|
using Flow.Launcher.Plugin;
|
2025-04-03 14:25:04 +00:00
|
|
|
|
using JetBrains.Annotations;
|
|
|
|
|
|
using Squirrel;
|
2016-05-09 19:40:59 +00:00
|
|
|
|
|
2020-04-21 09:12:17 +00:00
|
|
|
|
namespace Flow.Launcher.Core
|
2016-05-09 19:40:59 +00:00
|
|
|
|
{
|
2020-01-07 00:34:46 +00:00
|
|
|
|
public class Updater
|
2016-05-09 19:40:59 +00:00
|
|
|
|
{
|
2025-02-23 05:55:33 +00:00
|
|
|
|
public string GitHubRepository { get; init; }
|
2025-01-12 12:04:44 +00:00
|
|
|
|
|
2025-04-13 09:26:21 +00:00
|
|
|
|
private static readonly string ClassName = nameof(Updater);
|
|
|
|
|
|
|
2025-02-23 11:48:38 +00:00
|
|
|
|
private readonly IPublicAPI _api;
|
2017-03-26 23:08:56 +00:00
|
|
|
|
|
2025-02-23 05:55:33 +00:00
|
|
|
|
public Updater(IPublicAPI publicAPI, string gitHubRepository)
|
2020-01-07 00:34:46 +00:00
|
|
|
|
{
|
2025-02-23 11:48:38 +00:00
|
|
|
|
_api = publicAPI;
|
2020-01-07 00:34:46 +00:00
|
|
|
|
GitHubRepository = gitHubRepository;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-10-09 16:34:41 +00:00
|
|
|
|
private SemaphoreSlim UpdateLock { get; } = new SemaphoreSlim(1);
|
|
|
|
|
|
|
2025-01-13 04:00:45 +00:00
|
|
|
|
public async Task UpdateAppAsync(bool silentUpdate = true)
|
2016-05-09 19:40:59 +00:00
|
|
|
|
{
|
2023-01-04 04:23:56 +00:00
|
|
|
|
await UpdateLock.WaitAsync().ConfigureAwait(false);
|
2016-05-09 19:40:59 +00:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2020-12-20 09:44:46 +00:00
|
|
|
|
if (!silentUpdate)
|
2025-09-23 09:14:30 +00:00
|
|
|
|
_api.ShowMsg(Localize.pleaseWait(),
|
|
|
|
|
|
Localize.update_flowlauncher_update_check());
|
2020-12-20 09:44:46 +00:00
|
|
|
|
|
2022-08-09 00:35:38 +00:00
|
|
|
|
using var updateManager = await GitHubUpdateManagerAsync(GitHubRepository).ConfigureAwait(false);
|
2020-12-20 09:44:46 +00:00
|
|
|
|
|
2017-03-26 23:08:56 +00:00
|
|
|
|
// UpdateApp CheckForUpdate will return value only if the app is squirrel installed
|
2021-10-09 16:34:41 +00:00
|
|
|
|
var newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false);
|
2016-05-09 19:40:59 +00:00
|
|
|
|
|
2025-07-16 18:52:42 +00:00
|
|
|
|
var newReleaseVersion =
|
|
|
|
|
|
SemanticVersioning.Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString());
|
2024-06-23 00:31:47 +00:00
|
|
|
|
var currentVersion = SemanticVersioning.Version.Parse(Constant.Version);
|
2016-05-09 19:40:59 +00:00
|
|
|
|
|
2025-04-13 09:26:21 +00:00
|
|
|
|
_api.LogInfo(ClassName, $"Future Release <{Formatted(newUpdateInfo.FutureReleaseEntry)}>");
|
2020-07-05 22:00:22 +00:00
|
|
|
|
|
2020-12-20 09:44:46 +00:00
|
|
|
|
if (newReleaseVersion <= currentVersion)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!silentUpdate)
|
2025-09-23 09:14:30 +00:00
|
|
|
|
_api.ShowMsgBox(Localize.update_flowlauncher_already_on_latest());
|
2020-12-20 09:44:46 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-07-05 22:00:22 +00:00
|
|
|
|
|
2020-12-20 09:44:46 +00:00
|
|
|
|
if (!silentUpdate)
|
2025-09-23 09:14:30 +00:00
|
|
|
|
_api.ShowMsg(Localize.update_flowlauncher_update_found(),
|
|
|
|
|
|
Localize.update_flowlauncher_updating());
|
2020-12-29 09:54:39 +00:00
|
|
|
|
|
2020-12-31 05:06:31 +00:00
|
|
|
|
await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false);
|
2020-02-25 10:08:51 +00:00
|
|
|
|
|
2020-12-31 05:06:31 +00:00
|
|
|
|
await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false);
|
2020-02-25 10:08:51 +00:00
|
|
|
|
|
2020-12-20 09:44:46 +00:00
|
|
|
|
if (DataLocation.PortableDataLocationInUse())
|
|
|
|
|
|
{
|
2025-07-16 18:52:42 +00:00
|
|
|
|
var targetDestination = updateManager.RootAppDirectory +
|
|
|
|
|
|
$"\\app-{newReleaseVersion}\\{DataLocation.PortableFolderName}";
|
2025-02-23 11:48:38 +00:00
|
|
|
|
FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => _api.ShowMsgBox(s));
|
2025-07-16 18:52:42 +00:00
|
|
|
|
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination,
|
|
|
|
|
|
(s) => _api.ShowMsgBox(s)))
|
2025-09-23 09:14:30 +00:00
|
|
|
|
_api.ShowMsgBox(Localize.update_flowlauncher_fail_moving_portable_user_profile_data(DataLocation.PortableDataPath, targetDestination));
|
2020-12-20 09:44:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-12-31 05:06:31 +00:00
|
|
|
|
await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false);
|
2020-12-20 09:44:46 +00:00
|
|
|
|
}
|
2020-12-29 09:54:39 +00:00
|
|
|
|
|
2022-10-30 19:23:04 +00:00
|
|
|
|
var newVersionTips = NewVersionTips(newReleaseVersion.ToString());
|
2020-02-25 10:08:51 +00:00
|
|
|
|
|
2025-04-13 09:26:21 +00:00
|
|
|
|
_api.LogInfo(ClassName, $"Update success:{newVersionTips}");
|
2020-07-05 22:00:22 +00:00
|
|
|
|
|
2025-09-23 09:14:30 +00:00
|
|
|
|
if (_api.ShowMsgBox(newVersionTips, Localize.update_flowlauncher_new_update(),
|
2025-07-16 18:52:42 +00:00
|
|
|
|
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
2020-12-20 09:44:46 +00:00
|
|
|
|
{
|
|
|
|
|
|
UpdateManager.RestartApp(Constant.ApplicationFileName);
|
|
|
|
|
|
}
|
2020-02-25 10:08:51 +00:00
|
|
|
|
}
|
2023-01-04 04:23:56 +00:00
|
|
|
|
catch (Exception e)
|
2020-07-05 22:00:22 +00:00
|
|
|
|
{
|
2025-07-16 18:52:42 +00:00
|
|
|
|
if (e is HttpRequestException or WebException or SocketException ||
|
|
|
|
|
|
e.InnerException is TimeoutException)
|
2025-04-13 08:44:14 +00:00
|
|
|
|
{
|
2025-07-16 18:52:42 +00:00
|
|
|
|
_api.LogException(ClassName,
|
|
|
|
|
|
$"Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
|
2025-04-13 08:44:14 +00:00
|
|
|
|
}
|
2023-01-04 04:23:56 +00:00
|
|
|
|
else
|
2025-04-13 08:44:14 +00:00
|
|
|
|
{
|
2025-04-13 09:26:21 +00:00
|
|
|
|
_api.LogException(ClassName, $"Error Occurred", e);
|
2025-04-13 08:44:14 +00:00
|
|
|
|
}
|
2025-07-16 18:52:42 +00:00
|
|
|
|
|
2021-12-19 17:37:27 +00:00
|
|
|
|
if (!silentUpdate)
|
2025-09-23 09:14:30 +00:00
|
|
|
|
_api.ShowMsgError(Localize.update_flowlauncher_fail(),
|
|
|
|
|
|
Localize.update_flowlauncher_check_connection());
|
2021-10-09 16:34:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateLock.Release();
|
2020-07-05 22:00:22 +00:00
|
|
|
|
}
|
2017-03-06 01:30:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-03-07 19:37:38 +00:00
|
|
|
|
[UsedImplicitly]
|
|
|
|
|
|
private class GithubRelease
|
2017-03-07 19:23:42 +00:00
|
|
|
|
{
|
2025-07-16 18:52:42 +00:00
|
|
|
|
[JsonPropertyName("prerelease")] public bool Prerelease { get; [UsedImplicitly] set; }
|
2017-03-07 19:23:42 +00:00
|
|
|
|
|
2025-07-16 18:52:42 +00:00
|
|
|
|
[JsonPropertyName("published_at")] public DateTime PublishedAt { get; [UsedImplicitly] set; }
|
2017-03-07 19:23:42 +00:00
|
|
|
|
|
2025-07-16 18:52:42 +00:00
|
|
|
|
[JsonPropertyName("html_url")] public string HtmlUrl { get; [UsedImplicitly] set; }
|
2016-05-09 19:40:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-30 13:04:56 +00:00
|
|
|
|
// https://github.com/Squirrel/Squirrel.Windows/blob/master/src/Squirrel/UpdateManager.Factory.cs
|
2025-04-03 14:25:04 +00:00
|
|
|
|
private static async Task<UpdateManager> GitHubUpdateManagerAsync(string repository)
|
2016-05-09 19:40:59 +00:00
|
|
|
|
{
|
2017-03-07 19:23:42 +00:00
|
|
|
|
var uri = new Uri(repository);
|
2017-03-26 23:08:56 +00:00
|
|
|
|
var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases";
|
2017-03-07 19:23:42 +00:00
|
|
|
|
|
2021-10-09 16:34:41 +00:00
|
|
|
|
await using var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false);
|
2017-03-07 19:23:42 +00:00
|
|
|
|
|
2025-04-09 13:19:09 +00:00
|
|
|
|
var releases = await JsonSerializer.DeserializeAsync<List<GithubRelease>>(jsonStream).ConfigureAwait(false);
|
2025-07-16 18:52:42 +00:00
|
|
|
|
var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First();
|
2017-03-07 19:23:42 +00:00
|
|
|
|
var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/");
|
2021-12-19 17:37:27 +00:00
|
|
|
|
|
2025-07-16 18:52:42 +00:00
|
|
|
|
var client = new WebClient { Proxy = Http.WebProxy };
|
2017-03-07 19:23:42 +00:00
|
|
|
|
var downloader = new FileDownloader(client);
|
|
|
|
|
|
|
|
|
|
|
|
var manager = new UpdateManager(latestUrl, urlDownloader: downloader);
|
|
|
|
|
|
|
|
|
|
|
|
return manager;
|
2016-05-09 19:40:59 +00:00
|
|
|
|
}
|
2017-03-06 00:25:17 +00:00
|
|
|
|
|
2025-09-23 09:14:30 +00:00
|
|
|
|
private static string NewVersionTips(string version)
|
2017-03-06 00:25:17 +00:00
|
|
|
|
{
|
2025-09-23 09:14:30 +00:00
|
|
|
|
var tips = Localize.newVersionTips(version);
|
2022-10-30 19:23:04 +00:00
|
|
|
|
|
2017-03-06 00:25:17 +00:00
|
|
|
|
return tips;
|
|
|
|
|
|
}
|
2025-04-02 11:30:15 +00:00
|
|
|
|
|
|
|
|
|
|
private static string Formatted<T>(T t)
|
|
|
|
|
|
{
|
2025-07-16 18:52:42 +00:00
|
|
|
|
var formatted = JsonSerializer.Serialize(t, new JsonSerializerOptions { WriteIndented = true });
|
2025-04-02 11:30:15 +00:00
|
|
|
|
|
|
|
|
|
|
return formatted;
|
|
|
|
|
|
}
|
2016-05-09 19:40:59 +00:00
|
|
|
|
}
|
2022-08-09 00:35:38 +00:00
|
|
|
|
}
|