Skip to content

Commit

Permalink
Check for updates on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
ArchLeaders committed Jan 15, 2024
1 parent c52d097 commit b8012f2
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
using Octokit;

namespace NxEditor.Launcher.Helpers;
namespace NxEditor.Core.Helpers;

public static class GitHubRepo
public static class GithubHelper
{
private static readonly GitHubClient _githubClient = new(
new ProductHeaderValue($"NxEditor.Launcher.Helpers.{Guid.NewGuid()}")
private static readonly GitHubClient _client = new(
new ProductHeaderValue($"NxEditor.Core.Helpers.GithubHelper.{Guid.NewGuid()}")
);

public static async Task<(Stream stream, string tag)> GetRelease(string org, string repo, string assetName)
=> await GetRelease((await _githubClient.Repository.Get(org, repo)).Id, assetName);
{
return await GetRelease((await _client.Repository.Get(org, repo)).Id, assetName);
}

public static async Task<(Stream stream, string tag)> GetRelease(long repoId, string assetName)
{
IReadOnlyList<Release> releases = await _githubClient.Repository.Release.GetAll(repoId);
IReadOnlyList<Release> releases = await _client.Repository.Release.GetAll(repoId);

Release? latest = null;
ReleaseAsset? asset = null;
Expand All @@ -31,15 +33,17 @@ public static class GitHubRepo

public static async Task<byte[]> GetAsset(string org, string repo, string assetPath)
{
return await _githubClient.Repository.Content.GetRawContent(org, repo, assetPath);
return await _client.Repository.Content.GetRawContent(org, repo, assetPath);
}

public static async Task<bool> HasUpdate(string org, string repo, string currentTag)
=> await HasUpdate((await _githubClient.Repository.Get(org, repo)).Id, currentTag);
{
return await HasUpdate((await _client.Repository.Get(org, repo)).Id, currentTag);
}

public static async Task<bool> HasUpdate(long repoId, string currentTag)
{
IReadOnlyList<Release> releases = await _githubClient.Repository.Release.GetAll(repoId);
IReadOnlyList<Release> releases = await _client.Repository.Release.GetAll(repoId);
return releases.Count > 0 && releases[0].TagName != currentTag;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace NxEditor.Launcher.Helpers;
namespace NxEditor.Core.Helpers;

public class AppPlatform
public class PlatformHelper
{
public static string GetExecutableName()
{
Expand All @@ -27,4 +27,20 @@ public static string GetOsFileName()
throw new NotSupportedException("The running operating system is not supported");
}
}

public static string GetLauncherFileName()
{
if (OperatingSystem.IsWindows()) {
return "Windows-Launcher.zip";
}
else if (OperatingSystem.IsMacOS()) {
return "MacOS-Launcher.zip";
}
else if (OperatingSystem.IsLinux()) {
return "Linux-Launcher.zip";
}
else {
throw new NotSupportedException("The running operating system is not supported");
}
}
}
59 changes: 59 additions & 0 deletions src/NxEditor.Core/Helpers/UpdateHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using NxEditor.Core.Components;
using NxEditor.Core.Models;
using NxEditor.PluginBase;
using System.IO.Compression;
using System.Text.Json;

namespace NxEditor.Core.Helpers;

public class UpdateHelper
{
private const string LAUNCHER_NAME = "NxEditor.Launcher.exe";
private const string GITHUB_ORG = "NX-Editor";
private const string GITHUB_REPO = "NxEditor";

public static readonly string LauncherPath = Path.Combine(GlobalConfig.StaticPath, LAUNCHER_NAME);

private static readonly string _versionFile = Path.Combine(GlobalConfig.StaticPath, "version.json");

public static async Task<bool> HasUpdate()
{
if (File.Exists(_versionFile)) {
using FileStream fs = File.OpenRead(_versionFile);
if (JsonSerializer.Deserialize<string>(fs) is string version) {
return await GithubHelper.HasUpdate(GITHUB_ORG, GITHUB_REPO, version);
}
}


return false;
}

public static async Task<int> GetPluginUpdates()
{
return await GetPluginUpdates(PluginManager.GetPluginInfo());
}

public static async Task<int> GetPluginUpdates(IEnumerable<PluginInfo> plugins)
{
int updates = 0;

foreach (var plugin in plugins.Where(x => !x.IsOnline && x.GitHubRepoId != -1)) {
if (plugin.CanUpdate = await GithubHelper.HasUpdate(plugin.GitHubRepoId, plugin.Version)) {
updates++;
}
}

return updates;
}

public static async Task DownloadLauncher()
{
(var stream, _) = await GithubHelper.GetRelease(GITHUB_ORG, GITHUB_REPO, PlatformHelper.GetLauncherFileName());
ZipArchive zip = new(stream);
if (zip.Entries.FirstOrDefault(x => x.Name == LAUNCHER_NAME)?.Open() is Stream exe) {
using FileStream fs = File.Create(LauncherPath);
await exe.CopyToAsync(fs);
}
}
}
4 changes: 4 additions & 0 deletions src/NxEditor.Core/NxEditor.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<EmbeddedResource Include="Resources\**" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Octokit" Version="9.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NxEditor.PluginBase\src\NxEditor.PluginBase.csproj" />
</ItemGroup>
Expand Down
24 changes: 8 additions & 16 deletions src/NxEditor.Launcher/Helpers/AppUpdater.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NxEditor.PluginBase;
using NxEditor.Core.Helpers;
using NxEditor.PluginBase;
using System.Diagnostics;
using System.IO.Compression;
using System.Text.Json;
Expand All @@ -13,28 +14,19 @@ public class AppUpdater
private const string GITHUB_REPO = "NxEditor";

private static readonly char _pathEnvChar = OperatingSystem.IsWindows() ? ';' : ':';
private static readonly string _zipFileName = AppPlatform.GetOsFileName();
private static readonly string _zipFileName = PlatformHelper.GetOsFileName();
private static readonly string _outputPath = Path.Combine(GlobalConfig.StaticPath, "bin");
private static readonly string _versionFile = Path.Combine(GlobalConfig.StaticPath, "version.json");
private static readonly string _launcherOutputPath = Path.Combine(GlobalConfig.StaticPath, "NxEditor.Launcher.exe");

public static bool IsInstalled => File.Exists(_versionFile);

public static async Task<bool> HasUpdate()
{
using FileStream fs = File.OpenRead(_versionFile);
string version = JsonSerializer.Deserialize<string>(fs)!;

return await GitHubRepo.HasUpdate(GITHUB_ORG, GITHUB_REPO, version);
}

public static async Task Install(bool addToPath = true)
{
CopyRunningLauncherToOutput();
CreateDesktopShortcuts();
Directory.CreateDirectory(_outputPath);

(Stream stream, string tag) = await GitHubRepo.GetRelease(GITHUB_ORG, GITHUB_REPO, _zipFileName);
(Stream stream, string tag) = await GithubHelper.GetRelease(GITHUB_ORG, GITHUB_REPO, _zipFileName);
ZipArchive archive = new(stream);
archive.ExtractToDirectory(_outputPath, true);

Expand Down Expand Up @@ -85,16 +77,16 @@ public static Task<bool> Uninstall()
private static void CopyRunningLauncherToOutput()
{
string? exe = Process.GetCurrentProcess().MainModule?.FileName;
if (exe is not null && File.Exists(exe) && !exe.SequenceEqual(_launcherOutputPath)) {
File.Copy(exe, _launcherOutputPath, true);
if (exe is not null && File.Exists(exe) && exe != UpdateHelper.LauncherPath) {
File.Copy(exe, UpdateHelper.LauncherPath, true);
}
}

private static void CreateDesktopShortcuts()
{
string app = Path.Combine(_outputPath, AppPlatform.GetExecutableName());
string app = Path.Combine(_outputPath, PlatformHelper.GetExecutableName());
Shortcut.Create(APP_NAME, Location.Application, app, "nxe");
Shortcut.Create(LAUNCHER_NAME, Location.Application, _launcherOutputPath, "nxe");
Shortcut.Create(LAUNCHER_NAME, Location.Application, UpdateHelper.LauncherPath, "nxe");
Shortcut.Create(APP_NAME, Location.Desktop, app, "nxe");
}

Expand Down
5 changes: 3 additions & 2 deletions src/NxEditor.Launcher/Helpers/PluginUpdater.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NxEditor.Core.Models;
using NxEditor.Core.Helpers;
using NxEditor.Core.Models;
using System.IO.Compression;

namespace NxEditor.Launcher.Helpers;
Expand All @@ -19,7 +20,7 @@ private static async Task Install(PluginInfo info)
return;
}

(Stream stream, string tag) = await GitHubRepo.GetRelease(info.GitHubRepoId, AppPlatform.GetOsFileName());
(Stream stream, string tag) = await GithubHelper.GetRelease(info.GitHubRepoId, PlatformHelper.GetOsFileName());
ZipArchive archive = new(stream);
Directory.CreateDirectory(info.Folder);
archive.ExtractToDirectory(info.Folder, true);
Expand Down
16 changes: 6 additions & 10 deletions src/NxEditor.Launcher/ViewModels/ShellViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using CommunityToolkit.Mvvm.Input;
using Markdown.Avalonia;
using NxEditor.Core.Components;
using NxEditor.Core.Helpers;
using NxEditor.Core.Models;
using NxEditor.Launcher.Helpers;
using NxEditor.PluginBase;
Expand Down Expand Up @@ -51,7 +52,7 @@ public ShellViewModel()
[RelayCommand]
public async Task ShowOnlinePlugins()
{
byte[] pluginsData = await GitHubRepo.GetAsset("NX-Editor", "Plugins", "public.json");
byte[] pluginsData = await GithubHelper.GetAsset("NX-Editor", "Plugins", "public.json");
Dictionary<string, PluginInfoView> plugins = JsonSerializer.Deserialize<Dictionary<string, PluginInfoView>>(pluginsData)!;

foreach ((var id, var plugin) in plugins) {
Expand Down Expand Up @@ -96,7 +97,7 @@ public async Task PrimaryButton()
if (IsEditorInstalled) {
await PluginUpdater.InstallAll(Plugins);
Process.Start(
Path.Combine(GlobalConfig.StaticPath, "bin", AppPlatform.GetExecutableName())
Path.Combine(GlobalConfig.StaticPath, "bin", PlatformHelper.GetExecutableName())
);

IsLoading = false;
Expand Down Expand Up @@ -136,7 +137,7 @@ public static Task Exit()
}

[RelayCommand]
private async Task ShowHelp()
private static async Task ShowHelp()
{
using Stream stream = AssetLoader.Open(new("avares://NxEditor.Launcher/Assets/Readme.md"));
int strlen = (int)stream.Length;
Expand All @@ -160,17 +161,12 @@ private async Task ShowHelp()

private async Task CheckForUpdates()
{
if (IsEditorInstalled && await AppUpdater.HasUpdate()) {
if (IsEditorInstalled && await UpdateHelper.HasUpdate()) {
_canUpdate = true;
FoundUpdates++;
}

foreach (var plugin in Plugins.Where(x => !x.IsOnline && x.GitHubRepoId != -1)) {
if (plugin.CanUpdate = await GitHubRepo.HasUpdate(plugin.GitHubRepoId, plugin.Version)) {
FoundUpdates++;
}
}

FoundUpdates += await UpdateHelper.GetPluginUpdates(Plugins);
IsLoading = false;
}
}
41 changes: 36 additions & 5 deletions src/NxEditor/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
using Avalonia.Controls.Notifications;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using Avalonia.VisualTree;
using ConfigFactory.Avalonia.Helpers;
using ConfigFactory.Models;
using NxEditor.Core.Components;
using NxEditor.Core.Helpers;
using NxEditor.Generators;
using NxEditor.Models;
using NxEditor.Models.Menus;
using NxEditor.PluginBase;
using NxEditor.PluginBase.Common;
using NxEditor.PluginBase.Models;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace NxEditor;
Expand Down Expand Up @@ -91,21 +94,31 @@ await Task.Run(() => {
await EditorManager.Shared.TryLoadEditor(EditorFile.FromFile(arg));
}
}

_ = Task.Run(async () => {
if (await UpdateHelper.HasUpdate() || await UpdateHelper.GetPluginUpdates() > 0) {
Toast("Updates available!", action: OpenLauncherAndExit);
}
});
}

base.OnFrameworkInitializationCompleted();
}

public static void Toast(string message, string title = "Notice", NotificationType type = NotificationType.Information, TimeSpan? expiration = null)
public static void Toast(string message, string title = "Notice", NotificationType type = NotificationType.Information, TimeSpan? expiration = null, Action? action = null)
{
_notificationManager?.Show(
new Notification(title, message, type, expiration));
Dispatcher.UIThread.Invoke(() => {
_notificationManager?.Show(
new Notification(title, message, type, expiration, action));
});
}

public static void ToastError(Exception ex)
{
_notificationManager?.Show(new Notification(
ex.GetType().Name, ex.Message, NotificationType.Error, onClick: ShellViewMenu.OpenLogs));
Dispatcher.UIThread.Invoke(() => {
_notificationManager?.Show(new Notification(
ex.GetType().Name, ex.Message, NotificationType.Error, onClick: ShellViewMenu.OpenLogs));
});
}

public static void Log(object obj, [CallerMemberName] string method = "")
Expand All @@ -116,4 +129,22 @@ public static void Log(object obj, [CallerMemberName] string method = "")

Logger.Write(obj, method);
}

private static async void OpenLauncherAndExit()
{
DialogResult result = await DialogBox.ShowAsync("Install Updates", """
Your current session will be lost.

Are you sure you would you like to open
the launcher and close NX-Editor?
""", primaryButtonContent: "Yes");

if (result == DialogResult.Primary) {
ShellViewModel.Shared.View.IsEnabled = false;
StatusModal.Set("Downloading launcher", "fa-solid fa-download", isWorkingStatus: true);
await UpdateHelper.DownloadLauncher();
Process.Start(UpdateHelper.LauncherPath);
Environment.Exit(0);
}
}
}

0 comments on commit b8012f2

Please sign in to comment.