4using System.Threading.Tasks;
6using Microsoft.Extensions.Logging;
7using Microsoft.Extensions.Options;
42 readonly ILogger<ServerUpdater>
logger;
79 ILogger<ServerUpdater>
logger,
80 IOptions<GeneralConfiguration> generalConfigurationOptions,
81 IOptions<UpdatesConfiguration> updatesConfigurationOptions)
87 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
88 generalConfiguration = generalConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(generalConfigurationOptions));
89 updatesConfiguration = updatesConfigurationOptions?.Value ??
throw new ArgumentNullException(nameof(updatesConfigurationOptions));
97 ArgumentNullException.ThrowIfNull(swarmService);
99 ArgumentNullException.ThrowIfNull(version);
104 return await
BeginUpdateImpl(swarmService, fileStreamProvider, version,
false, cancellationToken);
108 public async ValueTask<bool>
ExecuteUpdate(
string updatePath, CancellationToken cancellationToken, CancellationToken criticalCancellationToken)
110 ArgumentNullException.ThrowIfNull(updatePath);
113 if (serverUpdateOperation ==
null)
114 throw new InvalidOperationException($
"{nameof(serverUpdateOperation)} was null!");
116 var inMustCommitUpdate =
false;
119 var stagingDirectory = $
"{updatePath}-stage";
124 await
using var bufferedStream = tuple.Item1;
125 var needStreamUntilCommit = tuple.Item2;
126 var createdStagingDirectory =
false;
131 logger.LogTrace(
"Extracting zip package to {stagingDirectory}...", stagingDirectory);
132 var updateZipData = await bufferedStream.GetResult(cancellationToken);
134 createdStagingDirectory =
true;
137 if (!needStreamUntilCommit)
139 logger.LogTrace(
"Early disposing update stream provider...");
140 await bufferedStream.DisposeAsync();
152 logger.LogError(
"Swarm distributed commit failed, not applying update!");
157 logger.LogTrace(
"Moving {stagingDirectory} to {updateDirectory}...", stagingDirectory, updatePath);
160 catch (
Exception e) when (createdStagingDirectory)
169 throw new AggregateException(e, e2);
177 catch (OperationCanceledException) when (!inMustCommitUpdate)
179 logger.LogInformation(
"Server update cancelled!");
181 catch (
Exception ex) when (!inMustCommitUpdate)
183 logger.LogError(ex,
"Error updating server!");
185 catch (
Exception ex) when (inMustCommitUpdate)
187 logger.LogCritical(ex,
"Could not complete committed swarm update!");
208 throw new AggregateException(exception, e2);
224 await fileStreamProvider.GetResult(cancellationToken));
233 await bufferedStream.DisposeAsync();
240 var bufferingTask = bufferedStream.EnsureBuffered(cancellationToken);
246 var result = Tuple.Create(
251 bufferedStream =
null;
263 if (bufferedStream !=
null)
264 await bufferedStream.DisposeAsync();
282 CancellationToken cancellationToken)
287 if (fileStreamProvider ==
null)
289 logger.LogDebug(
"Looking for GitHub releases version {version}...", newVersion);
292 var releases = await gitHubService.GetTgsReleases(cancellationToken);
293 foreach (var kvp
in releases)
295 var version = kvp.Key;
296 var release = kvp.Value;
297 if (version == newVersion)
300 if (asset ==
default)
305 if (String.IsNullOrWhiteSpace(bearerToken))
313 if (fileStreamProvider ==
null)
317 logger.LogWarning(
"We didn't find the requested release, but GitHub has been known to just not give full results when querying all releases. We'll try one more time.");
318 return await
BeginUpdateImpl(swarmService,
null, newVersion,
true, cancellationToken);
339 fileStreamProvider =
null;
357 if (fileStreamProvider !=
null)
358 await fileStreamProvider.DisposeAsync();
General configuration options.
string? GitHubAccessToken
A classic GitHub personal access token to use for bypassing rate limits on requests....
Configuration for the automatic update system.
string? UpdatePackageAssetName
Asset package containing the new Host assembly in zip form.
Necessary data for performing a server update.
IFileStreamProvider FileStreamProvider
The IFileStreamProvider that contains the update zip file.
ISwarmService SwarmService
The ISwarmService for the operation.
Version TargetVersion
The Version being updated to.
async ValueTask< bool > ExecuteUpdate(string updatePath, CancellationToken cancellationToken, CancellationToken criticalCancellationToken)
Executes a pending server update by extracting the new server to a given updatePath ....
ServerUpdater(IGitHubServiceFactory gitHubServiceFactory, IIOManager ioManager, IFileDownloader fileDownloader, IServerControl serverControl, ILogger< ServerUpdater > logger, IOptions< GeneralConfiguration > generalConfigurationOptions, IOptions< UpdatesConfiguration > updatesConfigurationOptions)
Initializes a new instance of the ServerUpdater class.
async ValueTask< Tuple< BufferedFileStreamProvider, bool >?> PrepareUpdateClearStagingAndBufferStream(string stagingDirectory, CancellationToken cancellationToken)
Prepares the swarm update, deletes the stagingDirectory , and buffers the ServerUpdateOperation....
readonly IIOManager ioManager
The IIOManager for the ServerUpdater.
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the ServerUpdater.
readonly IFileDownloader fileDownloader
The IFileDownloader for the ServerUpdater.
ServerUpdateOperation? serverUpdateOperation
ServerUpdateOperation for an in-progress update operation.
readonly ILogger< ServerUpdater > logger
The ILogger for the ServerUpdater.
readonly object updateInitiationLock
Lock object used when initiating an update.
readonly IGitHubServiceFactory gitHubServiceFactory
The IGitHubServiceFactory for the ServerUpdater.
async ValueTask TryAbort(Exception exception)
Attempt to abort a prepared swarm update.
async ValueTask< ServerUpdateResult > BeginUpdateImpl(ISwarmService swarmService, IFileStreamProvider? fileStreamProvider, Version newVersion, bool recursed, CancellationToken cancellationToken)
Start the process of downloading and applying an update to a new server version. Doesn't perform argu...
async ValueTask< ServerUpdateResult > BeginUpdate(ISwarmService swarmService, IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken)
Start the process of downloading and applying an update to a new server version .A ValueTask<TResult>...
readonly IServerControl serverControl
The IServerControl for the ServerUpdater.
readonly UpdatesConfiguration updatesConfiguration
The UpdatesConfiguration for the ServerUpdater.
IFileStreamProvider that provides a ISeekableFileStreamProvider from an input Stream.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
bool TryStartUpdate(IServerUpdateExecutor updateExecutor, Version newVersion)
Attempt to update with a given updateExecutor .
Executes server update operations.
IFileStreamProvider DownloadFile(Uri url, string? bearerToken)
Downloads a file from a given url .
Interface for asynchronously consuming Streams of files.
Interface for using filesystems.
Task ZipToDirectory(string path, Stream zipFile, CancellationToken cancellationToken)
Extract a set of zipFile to a given path .
Task DeleteDirectory(string path, CancellationToken cancellationToken)
Recursively delete a directory, removes and does not enter any symlinks encounterd.
Task MoveDirectory(string source, string destination, CancellationToken cancellationToken)
Moves a directory at source to destination .
Used for swarm operations. Functions may be no-op based on configuration.
ValueTask< SwarmPrepareResult > PrepareUpdate(ISeekableFileStreamProvider fileStreamProvider, Version version, CancellationToken cancellationToken)
Signal to the swarm that an update is requested.
bool ExpectedNumberOfNodesConnected
Gets a value indicating if the expected amount of nodes are connected to the swarm.
ValueTask< SwarmCommitResult > CommitUpdate(CancellationToken cancellationToken)
Signal to the swarm that an update is ready to be applied.
ValueTask AbortUpdate()
Attempt to abort an uncommitted update.
Factory for IGitHubServices.
ValueTask< IGitHubService > CreateService(CancellationToken cancellationToken)
Create a IGitHubService.
ServerUpdateResult
The result of a call to start a server update.
SwarmCommitResult
How to proceed on the commit step of an update.
SwarmPrepareResult
Indicates the result of a swarm update prepare operation.