add partial background downloading and update prompt
This commit is contained in:
@@ -53,10 +53,6 @@ namespace BlueMine
|
||||
/// </summary>
|
||||
private async void OnStartup(object sender, StartupEventArgs e)
|
||||
{
|
||||
#if !DEBUG
|
||||
var update = new UpdateManager();
|
||||
await update.CheckAndInstallAsync();
|
||||
#endif
|
||||
await _host.StartAsync();
|
||||
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
|
||||
mainWindow.Show();
|
||||
|
||||
@@ -28,5 +28,41 @@
|
||||
"Nem elszámolható hívások, email, chat",
|
||||
"Nem elszámolható telefon, chat, email kommunikáció",
|
||||
];
|
||||
|
||||
public static readonly string UpdateScript = @"# Wait for the main app to close completely
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
$exePath = '{currentExe}'
|
||||
$zipPath = '{tempZip}'
|
||||
$destDir = '{appDir}'
|
||||
|
||||
# Retry logic for deletion (in case antivirus or OS holds the lock)
|
||||
$maxRetries = 10
|
||||
$retryCount = 0
|
||||
|
||||
while ($retryCount -lt $maxRetries) {{
|
||||
try {{
|
||||
# Attempt to delete the old executable
|
||||
if (Test-Path $exePath) {{ Remove-Item $exePath -Force -ErrorAction Stop }}
|
||||
break # If successful, exit loop
|
||||
}}
|
||||
catch {{
|
||||
Start-Sleep -Milliseconds 500
|
||||
$retryCount++
|
||||
}}
|
||||
}}
|
||||
|
||||
# Unzip the new version
|
||||
Expand-Archive -Path $zipPath -DestinationPath $destDir -Force
|
||||
|
||||
# CLEANUP: Delete the zip
|
||||
Remove-Item $zipPath -Force
|
||||
|
||||
# RESTART: Launch the new executable
|
||||
# 'Start-Process' is the robust way to launch detached processes in PS
|
||||
Start-Process -FilePath $exePath -WorkingDirectory $destDir
|
||||
|
||||
# SELF-DESTRUCT: Remove this script
|
||||
Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +256,15 @@
|
||||
|
||||
<ui:ProgressRing x:Name="progressRing" Grid.Row="4" Height="10" Width="10" Margin="10" HorizontalAlignment="Left" IsIndeterminate="True" />
|
||||
<ui:TextBlock x:Name="statusTextBlock" Grid.Row="4" Grid.ColumnSpan="6" FontSize="8" Text="Staus: OK" Margin="30, 10, 10, 10" />
|
||||
<ui:TextBlock x:Name="versionTextBlock" Grid.Row="4" Grid.Column="2" HorizontalAlignment="Right" FontSize="8" Text="0.0.0" Margin="10" />
|
||||
<Grid Grid.Row="4" Grid.Column="2" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ui:SymbolIcon x:Name="updateIcon" Symbol="ArrowCircleUp24" Grid.Column="1" Margin="10" Filled="True"
|
||||
Foreground="{ui:ThemeResource AccentTextFillColorPrimaryBrush}" Visibility="Hidden" />
|
||||
<ui:TextBlock x:Name="versionTextBlock" Grid.Column="2" HorizontalAlignment="Right" FontSize="8" Text="0.0.0" Margin="10" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ui:FluentWindow>
|
||||
|
||||
@@ -45,9 +45,35 @@ namespace BlueMine
|
||||
Task getHoursTask = GetHours();
|
||||
|
||||
await Task.WhenAll(loadIssuesTask, getHoursTask);
|
||||
#if !DEBUG
|
||||
if(await UpdateManager.IsUpdateAvailable())
|
||||
{
|
||||
updateIcon.Visibility = Visibility.Visible;
|
||||
UpdateManager.DownloadCompleted += UpdateManager_DownloadCompleted;
|
||||
await UpdateManager.DownloadUpdateAsync();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private async void UpdateManager_DownloadCompleted()
|
||||
{
|
||||
await Dispatcher.Invoke(async () =>
|
||||
{
|
||||
var result = await new Wpf.Ui.Controls.MessageBox
|
||||
{
|
||||
Title = "Frissítés elérhető",
|
||||
Content = "Szeretnél most frissíteni?",
|
||||
PrimaryButtonText = "Frissítés",
|
||||
SecondaryButtonText = "Később",
|
||||
IsCloseButtonEnabled = false,
|
||||
}.ShowDialogAsync();
|
||||
|
||||
if (result == Wpf.Ui.Controls.MessageBoxResult.Primary)
|
||||
await UpdateManager.PerformUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
private void CalendarButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
flyoutCalendar.IsOpen = true;
|
||||
|
||||
@@ -2,33 +2,69 @@
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using Windows.Media.Protection.PlayReady;
|
||||
|
||||
namespace Blueberry
|
||||
{
|
||||
public class UpdateManager
|
||||
public static class UpdateManager
|
||||
{
|
||||
private const string releaseUrl = "https://git.technopunk.space/api/v1/repos/tomi/Blueberry/releases/latest";
|
||||
public const string CurrentVersion = "0.1.1";
|
||||
public const string CurrentVersion = "0.1.2";
|
||||
private static readonly string AppDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
private static readonly HttpClient client = new();
|
||||
public delegate void DownloadCompletedEventArgs();
|
||||
public static event DownloadCompletedEventArgs DownloadCompleted;
|
||||
private static bool isDownloading = false;
|
||||
|
||||
public async Task CheckAndInstallAsync()
|
||||
public static async Task<bool> IsUpdateAvailable()
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
var json = await client.GetStringAsync(releaseUrl);
|
||||
var release = JsonSerializer.Deserialize<Root>(json);
|
||||
return release != null && release.tag_name != CurrentVersion;
|
||||
}
|
||||
|
||||
public static async Task DownloadUpdateAsync()
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "Blueberry-Updater");
|
||||
|
||||
try
|
||||
{
|
||||
var json = client.GetStringAsync(releaseUrl).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
// 1. Use await here, don't block
|
||||
var json = await client.GetStringAsync(releaseUrl);
|
||||
var release = JsonSerializer.Deserialize<Root>(json);
|
||||
|
||||
if (release == null)
|
||||
throw new NullReferenceException();
|
||||
if (release == null) return;
|
||||
|
||||
if (release.tag_name != CurrentVersion)
|
||||
{
|
||||
var file = release.assets.Find(x => x.name.Contains(".zip")) ?? throw new NullReferenceException();
|
||||
string downloadUrl = file.browser_download_url;
|
||||
await PerformUpdate(client, downloadUrl);
|
||||
var file = release.assets.Find(x => x.name.Contains(".zip"));
|
||||
if (file == null) return;
|
||||
|
||||
string zipPath = Path.Combine(AppDir, "blueberry_update.zip");
|
||||
long offset = 0;
|
||||
|
||||
if (File.Exists(zipPath))
|
||||
{
|
||||
long localSize = new FileInfo(zipPath).Length;
|
||||
|
||||
if (localSize == file.size)
|
||||
{
|
||||
DownloadCompleted?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
if (localSize > file.size)
|
||||
{
|
||||
File.Delete(zipPath);
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = localSize;
|
||||
}
|
||||
}
|
||||
if (!isDownloading)
|
||||
await Download(client, file.browser_download_url, offset);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -37,55 +73,45 @@ namespace Blueberry
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PerformUpdate(HttpClient client, string url)
|
||||
private static async Task Download(HttpClient client, string url, long offset = 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
isDownloading = true;
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
|
||||
// If we have an offset, ask the server for the rest of the file
|
||||
if (offset > 0)
|
||||
{
|
||||
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(offset, null);
|
||||
}
|
||||
|
||||
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
// If offset > 0, we APPEND. If 0, we CREATE/OVERWRITE.
|
||||
var fileMode = offset > 0 ? FileMode.Append : FileMode.Create;
|
||||
string filePath = Path.Combine(AppDir, "blueberry_update.zip");
|
||||
|
||||
using var contentStream = await response.Content.ReadAsStreamAsync();
|
||||
using var fileStream = new FileStream(filePath, fileMode, FileAccess.Write, FileShare.None);
|
||||
|
||||
await contentStream.CopyToAsync(fileStream);
|
||||
isDownloading = false;
|
||||
DownloadCompleted?.Invoke();
|
||||
} catch (Exception)
|
||||
{
|
||||
isDownloading = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task PerformUpdate()
|
||||
{
|
||||
string tempZip = Path.Combine(Path.GetTempPath(), "blueberry_update.zip");
|
||||
string currentExe = Process.GetCurrentProcess().MainModule.FileName;
|
||||
string appDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
// 1. Download
|
||||
var data = await client.GetByteArrayAsync(url);
|
||||
File.WriteAllBytes(tempZip, data);
|
||||
|
||||
// 2. Create a temporary batch script to handle the swap
|
||||
// We use a small delay (timeout) to allow the main app to close fully
|
||||
string psScript = $@"
|
||||
# Wait for the main app to close completely
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
$exePath = '{currentExe}'
|
||||
$zipPath = '{tempZip}'
|
||||
$destDir = '{appDir}'
|
||||
|
||||
# Retry logic for deletion (in case antivirus or OS holds the lock)
|
||||
$maxRetries = 10
|
||||
$retryCount = 0
|
||||
|
||||
while ($retryCount -lt $maxRetries) {{
|
||||
try {{
|
||||
# Attempt to delete the old executable
|
||||
if (Test-Path $exePath) {{ Remove-Item $exePath -Force -ErrorAction Stop }}
|
||||
break # If successful, exit loop
|
||||
}}
|
||||
catch {{
|
||||
Start-Sleep -Milliseconds 500
|
||||
$retryCount++
|
||||
}}
|
||||
}}
|
||||
|
||||
# Unzip the new version
|
||||
Expand-Archive -Path $zipPath -DestinationPath $destDir -Force
|
||||
|
||||
# CLEANUP: Delete the zip
|
||||
Remove-Item $zipPath -Force
|
||||
|
||||
# RESTART: Launch the new executable
|
||||
# 'Start-Process' is the robust way to launch detached processes in PS
|
||||
Start-Process -FilePath $exePath -WorkingDirectory $destDir
|
||||
|
||||
# SELF-DESTRUCT: Remove this script
|
||||
Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force
|
||||
";
|
||||
string psScript = Constants.UpdateScript;
|
||||
string psPath = Path.Combine(Path.GetTempPath(), "blueberry_updater.ps1");
|
||||
File.WriteAllText(psPath, psScript);
|
||||
|
||||
@@ -114,6 +140,7 @@ Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force
|
||||
public class Asset
|
||||
{
|
||||
public string name { get; set; }
|
||||
public long size { get; set; }
|
||||
public string browser_download_url { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user