Skip to content

Commit 0ce0163

Browse files
Merge pull request #95 from nullinside-development-group/feat/updater
feat: increasing rebustness of github updater
2 parents 2ce470f + 3cef491 commit 0ce0163

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/Nullinside.Api.Common/Desktop/GitHubUpdateManager.cs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using System.Net;
1+
using System.Diagnostics;
2+
using System.IO.Compression;
3+
using System.Net;
4+
5+
using Microsoft.VisualBasic.FileIO;
26

37
using Newtonsoft.Json;
48

@@ -36,4 +40,88 @@ public static class GitHubUpdateManager {
3640
string body = await response.Content.ReadAsStringAsync();
3741
return JsonConvert.DeserializeObject<GithubLatestReleaseJson>(body);
3842
}
43+
44+
/// <summary>
45+
/// Prepares to update this application before this application is closed.
46+
/// </summary>
47+
public static async Task PrepareUpdate() {
48+
// To prepare the update, we just need to back up our files
49+
string ourFolder = Path.GetDirectoryName(typeof(GitHubUpdateManager).Assembly.Location) ?? "";
50+
string backupFolder = Path.Combine(ourFolder, "..", "backup");
51+
await DeleteRetry(backupFolder);
52+
53+
Directory.CreateDirectory(backupFolder);
54+
FileSystem.CopyDirectory(ourFolder, backupFolder);
55+
}
56+
57+
/// <summary>
58+
/// Runs this application from the backup folder to initiate the update on the installed folder.
59+
/// </summary>
60+
public static void ExitApplicationToUpdate() {
61+
// Since we have a backup folder from PrepareUpdate() we can just run the backup executable
62+
string ourFolder = Path.GetDirectoryName(typeof(GitHubUpdateManager).Assembly.Location) ?? "";
63+
string backupFolder = Path.Combine(ourFolder, "..", "backup");
64+
if (!Directory.Exists(backupFolder)) {
65+
return;
66+
}
67+
68+
string ourExecutable = $"{AppDomain.CurrentDomain.FriendlyName}.exe";
69+
70+
// we must pass the installation folder to the executable so it knows where to install
71+
Process.Start(Path.Combine(backupFolder, ourExecutable), $"--update \"{ourFolder}\"");
72+
Environment.Exit(0);
73+
}
74+
75+
/// <summary>
76+
/// Performs the application update. This involves downloading the latest release from GitHub, extracting its contents
77+
/// to the installation folder, and closing the currently running application while running the new one.
78+
/// </summary>
79+
public static async Task PerformUpdateAndRestart(string owner, string repo, string installFolder, string assetName) {
80+
// Delete the old install folder.
81+
await DeleteRetry(installFolder);
82+
83+
// Get the latest version of the application from GitHub.
84+
string ourFolder = Path.GetDirectoryName(typeof(GitHubUpdateManager).Assembly.Location) ?? "";
85+
string zipLocation = Path.Combine(ourFolder, assetName);
86+
GithubLatestReleaseJson? latestVersion = await GetLatestVersion(owner, repo);
87+
using (var client = new HttpClient()) {
88+
using HttpResponseMessage response = await client.GetAsync($"https://github.com/{owner}/{repo}/releases/download/{latestVersion?.name}/{assetName}");
89+
await using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync();
90+
await using var fileStream = new FileStream(zipLocation, FileMode.Create);
91+
await streamToReadFrom.CopyToAsync(fileStream);
92+
}
93+
94+
// Extract the zip file to the installation folder.
95+
ZipFile.ExtractToDirectory(zipLocation, installFolder);
96+
97+
// Run the new version of the application.
98+
Process.Start(Path.Combine(installFolder, $"{AppDomain.CurrentDomain.FriendlyName}.exe"), "--justUpdated");
99+
100+
// Close this version of the application.
101+
Environment.Exit(0);
102+
}
103+
104+
/// <summary>
105+
/// Cleans up the previous update's files.
106+
/// </summary>
107+
public static async Task CleanupUpdate() {
108+
string ourFolder = Path.GetDirectoryName(typeof(GitHubUpdateManager).Assembly.Location) ?? "";
109+
string backupFolder = Path.Combine(ourFolder, "..", "backup");
110+
111+
await DeleteRetry(backupFolder);
112+
}
113+
114+
/// <summary>
115+
/// Retries deleting a folder multiple times.
116+
/// </summary>
117+
/// <param name="folder">The folder to delete.</param>
118+
private static async Task DeleteRetry(string folder) {
119+
await Retry.Execute<bool>(() => {
120+
if (Directory.Exists(folder)) {
121+
Directory.Delete(folder, true);
122+
}
123+
124+
return Task.FromResult(true);
125+
}, 30, waitTime: TimeSpan.FromSeconds(1));
126+
}
39127
}

src/Nullinside.Api.Common/Twitch/TwitchClientProxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public string? TwitchOAuthToken {
111111
if (value == _twitchOAuthToken) {
112112
return;
113113
}
114-
114+
115115
_twitchOAuthToken = value;
116116

117117
// If we have a client, try to connect.

0 commit comments

Comments
 (0)