using ElectronNET.API.Entities; using System; using System.Collections.Generic; using System.Threading.Tasks; // ReSharper disable InconsistentNaming namespace ElectronNET.API { /// /// Enable apps to automatically update themselves. Based on electron-updater. /// public sealed class AutoUpdater : ApiBase { protected override SocketTaskEventNameTypes SocketTaskEventNameType => SocketTaskEventNameTypes.DashesLowerFirst; protected override SocketTaskMessageNameTypes SocketTaskMessageNameType => SocketTaskMessageNameTypes.DashesLowerFirst; protected override SocketEventNameTypes SocketEventNameType => SocketEventNameTypes.DashedLower; /// /// Whether to automatically download an update when it is found. (Default is true) /// public bool AutoDownload { get { return Task.Run(() => this.InvokeAsync()).Result; } set { BridgeConnector.Socket.Emit("autoUpdater-autoDownload-set", value); } } /// /// Whether to automatically install a downloaded update on app quit (if `QuitAndInstall` was not called before). /// /// Applicable only on Windows and Linux. /// public bool AutoInstallOnAppQuit { get { return Task.Run(() => this.InvokeAsync()).Result; } set { BridgeConnector.Socket.Emit("autoUpdater-autoInstallOnAppQuit-set", value); } } /// /// *GitHub provider only.* Whether to allow update to pre-release versions. /// Defaults to "true" if application version contains prerelease components (e.g. "0.12.1-alpha.1", here "alpha" is a prerelease component), otherwise "false". /// /// If "true", downgrade will be allowed("allowDowngrade" will be set to "true"). /// public bool AllowPrerelease { get { return Task.Run(() => this.InvokeAsync()).Result; } set { BridgeConnector.Socket.Emit("autoUpdater-allowPrerelease-set", value); } } /// /// *GitHub provider only.* /// Get all release notes (from current version to latest), not just the latest (Default is false). /// public bool FullChangelog { get { return Task.Run(() => this.InvokeAsync()).Result; } set { BridgeConnector.Socket.Emit("autoUpdater-fullChangelog-set", value); } } /// /// Whether to allow version downgrade (when a user from the beta channel wants to go back to the stable channel). /// Taken in account only if channel differs (pre-release version component in terms of semantic versioning). /// Default is false. /// public bool AllowDowngrade { get { return Task.Run(() => this.InvokeAsync()).Result; } set { BridgeConnector.Socket.Emit("autoUpdater-allowDowngrade-set", value); } } /// /// For test only. /// public string UpdateConfigPath { get { return Task.Run(() => this.InvokeAsync()).Result; } } /// /// The current application version /// public Task CurrentVersionAsync { get { return Task.Run(() => this.InvokeAsync()); } } /// /// Get the update channel. Not applicable for GitHub. /// Doesn’t return channel from the update configuration, only if was previously set. /// [Obsolete("Use the asynchronous version ChannelAsync instead")] public string Channel { get { return ChannelAsync.Result; } } /// /// Get the update channel. Not applicable for GitHub. /// Doesn’t return channel from the update configuration, only if was previously set. /// public Task ChannelAsync { get { return Task.Run(() => this.InvokeAsync()); } } /// /// Set the update channel. Not applicable for GitHub. /// public string SetChannel { set { BridgeConnector.Socket.Emit("autoUpdater-channel-set", value); } } /// /// The request headers. /// public Task> RequestHeadersAsync { get { return Task.Run(() => this.InvokeAsync>()); } } /// /// The request headers. /// public Dictionary RequestHeaders { set { BridgeConnector.Socket.Emit("autoUpdater-requestHeaders-set", value); } } /// /// Emitted when there is an error while updating. /// public event Action OnError { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } /// /// Emitted when checking if an update has started. /// public event Action OnCheckingForUpdate { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } /// /// Emitted when there is an available update. /// The update is downloaded automatically if AutoDownload is true. /// public event Action OnUpdateAvailable { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } /// /// Emitted when there is no available update. /// public event Action OnUpdateNotAvailable { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } /// /// Emitted on download progress. /// public event Action OnDownloadProgress { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } /// /// Emitted on download complete. /// public event Action OnUpdateDownloaded { add => AddEvent(value, GetHashCode()); remove => RemoveEvent(value, GetHashCode()); } private static AutoUpdater _autoUpdater; private static object _syncRoot = new object(); internal AutoUpdater() { } internal static AutoUpdater Instance { get { if (_autoUpdater == null) { lock (_syncRoot) { if (_autoUpdater == null) { _autoUpdater = new AutoUpdater(); } } } return _autoUpdater; } } /// /// Asks the server whether there is an update. /// /// public Task CheckForUpdatesAsync() { var taskCompletionSource = new TaskCompletionSource(); string guid = Guid.NewGuid().ToString(); BridgeConnector.Socket.Once("autoUpdater-checkForUpdates-completed" + guid, (result) => { try { BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesError" + guid); taskCompletionSource.SetResult(result); } catch (Exception ex) { taskCompletionSource.SetException(ex); } }); BridgeConnector.Socket.Once("autoUpdater-checkForUpdatesError" + guid, (result) => { BridgeConnector.Socket.Off("autoUpdater-checkForUpdates-completed" + guid); string message = "An error occurred in CheckForUpdatesAsync"; if (!string.IsNullOrEmpty(result)) message = result; taskCompletionSource.SetException(new Exception(message)); }); BridgeConnector.Socket.Emit("autoUpdater-checkForUpdates", guid); return taskCompletionSource.Task; } /// /// Asks the server whether there is an update. /// /// This will immediately download an update, then install when the app quits. /// /// public Task CheckForUpdatesAndNotifyAsync() { var taskCompletionSource = new TaskCompletionSource(); string guid = Guid.NewGuid().ToString(); BridgeConnector.Socket.Once("autoUpdater-checkForUpdatesAndNotify-completed" + guid, (result) => { try { BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotifyError" + guid); taskCompletionSource.SetResult(result); } catch (Exception ex) { taskCompletionSource.SetException(ex); } }); BridgeConnector.Socket.Once("autoUpdater-checkForUpdatesAndNotifyError" + guid, (result) => { BridgeConnector.Socket.Off("autoUpdater-checkForUpdatesAndNotify-completed" + guid); string message = "An error occurred in CheckForUpdatesAndNotifyAsync"; if (!string.IsNullOrEmpty(result)) message = result; taskCompletionSource.SetException(new Exception(message)); }); BridgeConnector.Socket.Emit("autoUpdater-checkForUpdatesAndNotify", guid); return taskCompletionSource.Task; } /// /// Restarts the app and installs the update after it has been downloaded. /// It should only be called after `update-downloaded` has been emitted. /// /// Note: QuitAndInstall() will close all application windows first and only emit `before-quit` event on `app` after that. /// This is different from the normal quit event sequence. /// /// *windows-only* Runs the installer in silent mode. Defaults to `false`. /// Run the app after finish even on silent install. Not applicable for macOS. Ignored if `isSilent` is set to `false`. public void QuitAndInstall(bool isSilent = false, bool isForceRunAfter = false) { BridgeConnector.Socket.Emit("autoUpdater-quitAndInstall", isSilent, isForceRunAfter); } /// /// Start downloading update manually. You can use this method if "AutoDownload" option is set to "false". /// /// Path to downloaded file. public Task DownloadUpdateAsync() { var tcs = new TaskCompletionSource(); string guid = Guid.NewGuid().ToString(); BridgeConnector.Socket.Once("autoUpdater-downloadUpdate-completed" + guid, tcs.SetResult); BridgeConnector.Socket.Emit("autoUpdater-downloadUpdate", guid); return tcs.Task; } /// /// Feed URL. /// /// Feed URL. public Task GetFeedURLAsync() { var tcs = new TaskCompletionSource(); string guid = Guid.NewGuid().ToString(); BridgeConnector.Socket.Once("autoUpdater-getFeedURL-completed" + guid, tcs.SetResult); BridgeConnector.Socket.Emit("autoUpdater-getFeedURL", guid); return tcs.Task; } } }