Skip to content

Commit

Permalink
Refactor and simplify updater logic
Browse files Browse the repository at this point in the history
  • Loading branch information
X9VoiD committed Dec 29, 2022
1 parent 1eee9d7 commit e79f4e6
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 492 deletions.
3 changes: 2 additions & 1 deletion OpenTabletDriver.Console/ProgramCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using OpenTabletDriver.Desktop.Contracts;
using OpenTabletDriver.Desktop.Profiles;
using OpenTabletDriver.Desktop.Reflection;
using OpenTabletDriver.Desktop.Updater;
using OpenTabletDriver.Output;
using static System.Console;

Expand Down Expand Up @@ -377,7 +378,7 @@ public async Task GetDiagnostics()
[Command("update", "Install OpenTabletDriver update if available")]
public async Task InstallUpdate()
{
if (await _driverDaemon.HasUpdate())
if (await _driverDaemon.CheckForUpdates() is not null)
{
await _driverDaemon.InstallUpdate();
}
Expand Down
31 changes: 22 additions & 9 deletions OpenTabletDriver.Daemon/DriverDaemon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class DriverDaemon : IDriverDaemon
private readonly ISleepDetector _sleepDetector;
private readonly IUpdater? _updater;

private UpdateInfo? _updateInfo;

public DriverDaemon(
IServiceProvider serviceProvider,
IDriver driver,
Expand Down Expand Up @@ -414,22 +416,33 @@ public Task<IEnumerable<TypeProxy>> GetMatchingTypes(string typeName)
return Task.FromResult(matchingTypes);
}

public Task<bool> HasUpdate()
{
return _updater?.CheckForUpdates() ?? Task.FromResult(false);
}

public async Task<UpdateInfo?> GetUpdateInfo()
public async Task<SerializedUpdateInfo?> CheckForUpdates()
{
if (_updater == null)
return null;

return await _updater.GetInfo();
_updateInfo = await _updater.CheckForUpdates();
return _updateInfo?.ToSerializedUpdateInfo();
}

public Task InstallUpdate()
public async Task InstallUpdate()
{
return _updater?.InstallUpdate() ?? Task.CompletedTask;
if (_updateInfo == null)
throw new InvalidOperationException("No update available"); // Misbehaving client

try
{
var update = await _updateInfo.GetUpdate();
_updater?.Install(update);
}
catch
{
throw;
}
finally
{
_updateInfo = null;
}
}

private void PostDebugReport(string tablet, IDeviceReport report)
Expand Down
4 changes: 2 additions & 2 deletions OpenTabletDriver.Desktop/Contracts/IDriverDaemon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ public interface IDriverDaemon
Task<TypeProxy> GetProxiedType(string typeName);
Task<IEnumerable<TypeProxy>> GetMatchingTypes(string typeName);

Task<bool> HasUpdate();
Task<UpdateInfo?> GetUpdateInfo();
Task<SerializedUpdateInfo?> CheckForUpdates();
Task InstallUpdate();

Task<IEnumerable<PluginMetadata>> GetInstalledPlugins();
event EventHandler<Settings>? SettingsChanged;
Task Initialize();
Expand Down
28 changes: 20 additions & 8 deletions OpenTabletDriver.Desktop/Updater/GitHubUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,35 @@

namespace OpenTabletDriver.Desktop.Updater
{
public abstract class GitHubUpdater : Updater<UpdateInfo>
public abstract class GitHubUpdater : Updater
{
private readonly IGitHubClient _github;

protected GitHubUpdater(Version? currentVersion, IAppInfo appInfo, IGitHubClient client)
protected GitHubUpdater(Version currentVersion, IAppInfo appInfo, IGitHubClient client)
: base(currentVersion, appInfo.BinaryDirectory, appInfo.AppDataDirectory, appInfo.BackupDirectory)
{
_github = client;
}

protected override async Task<UpdateInfo?> GetUpdate()
protected abstract Task<Update> Download(Release release, Version version);

protected override async Task<UpdateInfo?> CheckForUpdatesCore()
{
var release = await _github.Repository.Release.GetLatest("OpenTabletDriver", "OpenTabletDriver");
var version = new Version(release!.TagName[1..]); // remove `v` from `vW.X.Y.Z
return new GitHubRelease(release, version);
try
{
var release = await _github.Repository.Release.GetLatest("OpenTabletDriver", "OpenTabletDriver");
var version = new Version(release!.TagName[1..]); // remove `v` from `vW.X.Y.Z

return new UpdateInfo(async () => await Download(release, version))
{
Version = version
};
}
catch (Exception ex)
{
Log.Write(nameof(GitHubUpdater), $"Failed to check for updates: {ex}", LogLevel.Error);
return null;
}
}
}

public record GitHubRelease(Release Release, Version Version) : UpdateInfo(Version);
}
21 changes: 21 additions & 0 deletions OpenTabletDriver.Desktop/Updater/IUpdate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Immutable;

namespace OpenTabletDriver.Desktop.Updater
{
public record Update
{
public Update(Version version, ImmutableArray<string> paths)
{
Version = version;
Paths = paths;
}

public Version Version { get; init; }

/// <summary>
/// Gets the paths of files/directories directly in the root of the update.
/// </summary>
public ImmutableArray<string> Paths { get; init; }
}
}
33 changes: 30 additions & 3 deletions OpenTabletDriver.Desktop/Updater/IUpdater.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
using System;
using System.Threading.Tasks;

namespace OpenTabletDriver.Desktop.Updater
{
public interface IUpdater
{
Task<bool> CheckForUpdates();
Task<UpdateInfo?> GetInfo();
Task InstallUpdate();
/// <summary>
/// Checks if an update is available.
/// </summary>
/// <returns>
/// Returns an <see cref="UpdateInfo"/> if an update is available, otherwise returns null.
/// </returns>
Task<UpdateInfo?> CheckForUpdates();

/// <summary>
/// Installs an update.
/// </summary>
/// <param name="update">The update to install.</param>
/// <returns>The result of installing the update.</returns>
Task Install(Update update);

/// <summary>
/// Occurs when an update is being installed.
/// </summary>
event Action<Update> UpdateInstalling;

/// <summary>
/// Occurs when a rollback is created. This event provides the path to the rollback directory.
/// </summary>
event Action<string> RollbackCreated;

/// <summary>
/// Occurs when an update is installed.
/// </summary>
event Action<Update> UpdateInstalled;
}
}
18 changes: 13 additions & 5 deletions OpenTabletDriver.Desktop/Updater/MacOSUpdater.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
Expand All @@ -16,19 +18,20 @@ public class MacOSUpdater : GitHubUpdater
public MacOSUpdater(IAppInfo appInfo, IGitHubClient client)
: base(AssemblyVersion, appInfo, client)
{
UpdateInstalled += _ => PostInstall();
}

protected override void PostInstall()
private void PostInstall()
{
// Mark the binaries executable, SharpZipLib doesn't do this.
var subPath = Path.Join(DownloadDirectory, "OpenTabletDriver.app", "Contents", "MacOS");
var subPath = Path.Join(BinaryDirectory, "OpenTabletDriver.app", "Contents", "MacOS");
Process.Start("chmod", $"+x {subPath}/OpenTabletDriver.UX.MacOS");
Process.Start("chmod", $"+x {subPath}/OpenTabletDriver.Daemon");
Move(subPath, BinaryDirectory);
}

protected override async Task Download(Release release)
protected override async Task<Update> Download(Release release, Version version)
{
var downloadPath = GetDownloadPath();
var asset = release.Assets.First(r => r.Name.Contains("osx-x64"));

// Download and extract tar gzip
Expand All @@ -37,8 +40,13 @@ protected override async Task Download(Release release)
await using (var decompressionStream = new GZipStream(httpStream, CompressionMode.Decompress))
using (var tar = TarArchive.CreateInputTarArchive(decompressionStream))
{
tar.ExtractContents(DownloadDirectory);
tar.ExtractContents(downloadPath);
}

return new Update(
version,
ImmutableArray.Create(Directory.GetFileSystemEntries(downloadPath))
);
}
}
}
14 changes: 14 additions & 0 deletions OpenTabletDriver.Desktop/Updater/SerializedUpdateInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace OpenTabletDriver.Desktop.Updater
{
public sealed class SerializedUpdateInfo
{
public SerializedUpdateInfo(UpdateInfo updateInfo)
{
Version = updateInfo.Version;
}

public Version Version { get; set; } = new Version();
}
}
22 changes: 21 additions & 1 deletion OpenTabletDriver.Desktop/Updater/UpdateInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
using System;
using System.Threading.Tasks;

namespace OpenTabletDriver.Desktop.Updater
{
public record UpdateInfo(Version Version);
public sealed class UpdateInfo
{
private readonly Func<Task<Update>> _updateFactory;
private Update? _update;

public UpdateInfo(Func<Task<Update>> updateFactory)
{
_updateFactory = updateFactory;
}

public Version Version { get; init; } = new Version();

public async Task<Update> GetUpdate()
{
_update ??= await _updateFactory();
return _update;
}

public SerializedUpdateInfo ToSerializedUpdateInfo() => new(this);
}
}
Loading

0 comments on commit e79f4e6

Please sign in to comment.