diff --git a/Components/AppilcationUpdate/Lua/ApplicationUpdateInstanceThread.cs b/Components/AppilcationUpdate/Lua/ApplicationUpdateInstanceThread.cs index 758209b9..6512ce2e 100644 --- a/Components/AppilcationUpdate/Lua/ApplicationUpdateInstanceThread.cs +++ b/Components/AppilcationUpdate/Lua/ApplicationUpdateInstanceThread.cs @@ -2,11 +2,14 @@ using Slipstream.Shared; using Slipstream.Shared.Lua; -using Squirrel; -using System.Diagnostics; -using System.Linq; using System.Threading; -using System.Threading.Tasks; +using AutoUpdaterDotNET; +using System.Reflection; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.IO; +using System.Net; namespace Slipstream.Components.AppilcationUpdate.Lua { @@ -16,8 +19,10 @@ public class ApplicationUpdateInstanceThread : BaseInstanceThread, IApplicationU private readonly IApplicationUpdateEventFactory ApplicationUpdateEventFactory; private readonly IEventBus EventBus; private readonly IEventBusSubscription Subscription; + private readonly IApplicationVersionService ApplicationVersionService; private readonly string UpdateLocation; private readonly bool Prerelease; + private UpdateInfoEventArgs? LastUpdateInfoEventArgs; public ApplicationUpdateInstanceThread( string instanceId, @@ -27,7 +32,9 @@ public ApplicationUpdateInstanceThread( IEventHandlerController eventHandlerController, IApplicationUpdateEventFactory applicationUpdateEventFactory, IEventBus eventBus, - IEventBusSubscription subscription) : base(instanceId, logger) + IEventBusSubscription subscription, + IApplicationVersionService applicationVersionService + ) : base(instanceId, logger) { UpdateLocation = location; Prerelease = prerelease; @@ -35,108 +42,148 @@ public ApplicationUpdateInstanceThread( ApplicationUpdateEventFactory = applicationUpdateEventFactory; EventBus = eventBus; Subscription = subscription; + ApplicationVersionService = applicationVersionService; } - protected override void Main() + private void AutoUpdaterOnParseUpdateInfoEvent(ParseUpdateInfoEventArgs args) { - if (Debugger.IsAttached) + // We're expecting a github endpoint, returning a JSON of what is available on the release page. + // see https://api.github.com/repos/dennis/slipstream/releases + // We will always use the latest version and check if that differs from the installed version + // When looking for which asset to download, we'll just download the first .exe file we find. + + // AutoUpdaterDotNET also features UI, giving a dialog box that asks user if they want to update, + // skip or remind later. But to utilize this, we need to be doing this from the UI thread. + // It might make sense to move it to WinForm? + + if (!(JsonConvert.DeserializeObject(args.RemoteData) is JArray json)) { - Logger.Information("Auto update is disabled when a Debugger is attached"); + Logger.Information("Auto update, can't read json returned from update server"); return; } - Logger.Information($"Auto update, updating from {UpdateLocation}, prerelease: {Prerelease} {Thread.CurrentThread.ManagedThreadId}"); + static string GetVersionFromTag(string tag) => tag.Remove(0, tag.IndexOf('v') + 1); - Init(); + var latestRelease = json[0]; + if (latestRelease == null) + { + Logger.Information("Auto update, didn't find any information for last version"); + return; + } - while (!Stopping) + if (!(latestRelease["tag_name"] is JValue newestRelease)) { - IEvent? @event = Subscription.NextEvent(100); + Logger.Information("Auto update, can't read newest version information"); + return; + } - if (@event != null) + var newestReleaseStr = newestRelease.Value as string; + var CurrentVersion = GetVersionFromTag(newestReleaseStr!); + var ChangelogUrl = string.Empty; + + if (!(latestRelease["assets"] is JArray assets)) + { + Logger.Information("Auto update, no assets found"); + return; + } + + foreach (var asset in assets) + { + if (asset["browser_download_url"] is JValue downloadUrl && downloadUrl.Value is string downloadUrlStr && downloadUrlStr.EndsWith(".exe")) { - EventHandlerController.HandleEvent(@event); + args.UpdateInfo = new UpdateInfoEventArgs + { + CurrentVersion = CurrentVersion, + ChangelogURL = ChangelogUrl, + DownloadURL = downloadUrlStr + }; + + break; } } } - private void Init() + protected override void Main() { - if (string.IsNullOrEmpty(UpdateLocation)) - { - Logger.Information("Auto update is disabled, no update location specified"); - return; - } - - using var updateManager = CreateUpdateManager(); + Logger.Information($"Auto update, updating from {UpdateLocation}, prerelease: {Prerelease} {Thread.CurrentThread.ManagedThreadId}"); - if (updateManager?.IsInstalledApp == true) - { - Logger.Information($"Installed application: auto update enabled {Thread.CurrentThread.ManagedThreadId}"); + AutoUpdater.HttpUserAgent = $"{Assembly.GetExecutingAssembly().GetName().Name} v{ApplicationVersionService.Version}"; + AutoUpdater.ParseUpdateInfoEvent += AutoUpdaterOnParseUpdateInfoEvent; + AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckFOrUpdateEvent; + AutoUpdater.PersistenceProvider = new JsonFilePersistenceProvider(Path.Combine(Environment.CurrentDirectory, "autoupdate.json")); - var applicationUpdate = EventHandlerController.Get(); + var applicationUpdate = EventHandlerController.Get(); + applicationUpdate.OnApplicationUpdateCommandCheckLatestVersion += (s, e) => CheckForAppUpdates(); + applicationUpdate.OnApplicationUpdateLatestVersionChanged += (s, e) => OnApplicationVersionChanged(); - applicationUpdate.OnApplicationUpdateCommandCheckLatestVersion += async (s, e) => await CheckForAppUpdates(); - applicationUpdate.OnApplicationUpdateLatestVersionChanged += async (s, e) => await OnApplicationVersionChanged(); + while (!Stopping) + { + IEvent? @event = Subscription.NextEvent(100); - // Send update event to check for update at startup - EventBus.PublishEvent(ApplicationUpdateEventFactory.CreateApplicationUpdateCommandCheckLatestVersion()); + if (@event != null) + { + EventHandlerController.HandleEvent(@event); + } } } - private UpdateManager? CreateUpdateManager() + private void OnApplicationVersionChanged() { - if (string.IsNullOrEmpty(UpdateLocation)) + if (LastUpdateInfoEventArgs == null) + return; + + try { - return null; + if (AutoUpdater.DownloadUpdate(LastUpdateInfoEventArgs)) + { + Logger.Information("Auto update: Updated version. Restart to use it"); + } + else + { + Logger.Information("Auto update cancelled"); + } } - - var isGitHub = UpdateLocation.StartsWith("https://github.com"); - - if (isGitHub) + catch (Exception exception) { - var asyncUpdateManager = UpdateManager.GitHubUpdateManager(UpdateLocation, prerelease: Prerelease); - asyncUpdateManager.Wait(); - return asyncUpdateManager.Result; + Logger.Error("Auto update error: " + exception.Message); } - return new UpdateManager(UpdateLocation); + LastUpdateInfoEventArgs = null; } - private async Task CheckForAppUpdates() + private void AutoUpdaterOnCheckFOrUpdateEvent(UpdateInfoEventArgs args) { - Logger.Information("Auto update, checking lastest version"); - using var updateManager = CreateUpdateManager(); - - if (updateManager == null) - return; + if (args.Error == null) + { + if (args.IsUpdateAvailable) + { + Logger.Information($"Auto update, new version {args.CurrentVersion} available. You are using version {args.InstalledVersion}."); - var canUpdate = await updateManager.CheckForUpdate(); + LastUpdateInfoEventArgs = args; - if (canUpdate.ReleasesToApply.Any()) - { - Logger.Information("Auto update, new version available, raising the event"); - EventBus.PublishEvent(ApplicationUpdateEventFactory.CreateApplicationUpdateLatestVersionChanged(canUpdate.FutureReleaseEntry.Version.ToString())); + EventBus.PublishEvent(ApplicationUpdateEventFactory.CreateApplicationUpdateLatestVersionChanged(args.CurrentVersion)); + } + else + { + Logger.Information("Auto update, no update available"); + } } else { - Logger.Information($"Auto update, no update available {Thread.CurrentThread.ManagedThreadId}"); + if (args.Error is WebException) + { + Logger.Error("Auto update, can't reach update server"); + } + else + { + Logger.Error("Auto update error: " + args.Error.Message); + } } } - private async Task OnApplicationVersionChanged() - { - using var updateManager = CreateUpdateManager(); - if (updateManager == null) - return; - await DoAppUpdates(updateManager); - } - - private async Task DoAppUpdates(UpdateManager updateManager) + private void CheckForAppUpdates() { - Logger.Information("Auto updating to the latest version"); - var releaseInfo = await updateManager.UpdateApp(); - Logger.Information($"Auto update, update completed for {releaseInfo.Version}"); + AutoUpdater.Start(UpdateLocation); } } } \ No newline at end of file diff --git a/Components/AppilcationUpdate/Lua/ApplicationUpdateLuaLibrary.cs b/Components/AppilcationUpdate/Lua/ApplicationUpdateLuaLibrary.cs index 66505a33..16036f16 100644 --- a/Components/AppilcationUpdate/Lua/ApplicationUpdateLuaLibrary.cs +++ b/Components/AppilcationUpdate/Lua/ApplicationUpdateLuaLibrary.cs @@ -8,7 +8,7 @@ namespace Slipstream.Components.AppilcationUpdate.Lua { - public class ApplicationUpdateLuaLibrary : BaseLuaLibrary + public class ApplicationUpdateLuaLibrary : SingletonLuaLibrary { private static readonly DictionaryValidator ConfigurationValidator; diff --git a/Components/AppilcationUpdate/Lua/ApplicationUpdateReference.cs b/Components/AppilcationUpdate/Lua/ApplicationUpdateReference.cs index 45e58864..51236f76 100644 --- a/Components/AppilcationUpdate/Lua/ApplicationUpdateReference.cs +++ b/Components/AppilcationUpdate/Lua/ApplicationUpdateReference.cs @@ -1,14 +1,27 @@ -namespace Slipstream.Components.AppilcationUpdate.Lua +using Slipstream.Shared; + +namespace Slipstream.Components.AppilcationUpdate.Lua { public class ApplicationUpdateReference : IApplicationUpdateReference { private ApplicationUpdateLuaLibrary LuaLibrary { get; } public string InstanceId { get; } - public ApplicationUpdateReference(ApplicationUpdateLuaLibrary luaLibrary, string instanceId) + private readonly IApplicationUpdateEventFactory ApplicationUpdateEventFactory; + private readonly IEventBus EventBus; + + public ApplicationUpdateReference(ApplicationUpdateLuaLibrary luaLibrary, string instanceId, IEventBus eventBus, IApplicationUpdateEventFactory eventFactory) { LuaLibrary = luaLibrary; InstanceId = instanceId; + ApplicationUpdateEventFactory = eventFactory; + EventBus = eventBus; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "This is expose in Lua, so we want to keep that naming style")] + public void start() + { + EventBus.PublishEvent(ApplicationUpdateEventFactory.CreateApplicationUpdateCommandCheckLatestVersion()); } public void Dispose() diff --git a/Slipstream.csproj b/Slipstream.csproj index d634390a..70bd84cc 100644 --- a/Slipstream.csproj +++ b/Slipstream.csproj @@ -1,5 +1,4 @@  - Debug @@ -59,6 +58,9 @@ packages\Autofac.6.1.0\lib\netstandard2.0\Autofac.dll + + packages\Autoupdater.NET.Official.1.6.4\lib\net45\AutoUpdater.NET.dll + packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll @@ -122,9 +124,6 @@ packages\NLua.1.5.7\lib\net46\NLua.dll - - packages\squirrel.windows.2.0.1\lib\Net45\NuGet.Squirrel.dll - packages\Serilog.2.10.0\lib\net46\Serilog.dll @@ -134,9 +133,6 @@ packages\SharpCompress.0.17.1\lib\net45\SharpCompress.dll - - packages\squirrel.windows.2.0.1\lib\Net45\Squirrel.dll - packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll @@ -173,6 +169,7 @@ packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + @@ -497,7 +494,6 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - diff --git a/packages.config b/packages.config index 8dc185a9..54c22693 100644 --- a/packages.config +++ b/packages.config @@ -1,6 +1,7 @@  + @@ -20,7 +21,6 @@ -