4using System.Threading.Tasks;
6using Microsoft.Extensions.Logging;
7using Microsoft.Extensions.Options;
52 readonly ILogger<ServerUpdater>
logger;
79 ILogger<ServerUpdater>
logger,
89 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
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);
296 foreach (var kvp
in releases)
298 var version = kvp.Key;
299 var release = kvp.Value;
300 if (version == newVersion)
302 var asset = release.Assets.Where(x => x.Name.Equals(updatesConfiguration.UpdatePackageAssetName, StringComparison.Ordinal)).FirstOrDefault();
303 if (asset ==
default)
306 logger.LogTrace(
"Creating download provider for {assetName}...", updatesConfiguration.UpdatePackageAssetName);
307 var bearerToken = generalConfiguration.GitHubAccessToken;
308 if (String.IsNullOrWhiteSpace(bearerToken))
316 if (fileStreamProvider ==
null)
320 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.");
321 return await
BeginUpdateImpl(swarmService,
null, newVersion,
true, cancellationToken);
342 fileStreamProvider =
null;
360 if (fileStreamProvider !=
null)
361 await fileStreamProvider.DisposeAsync();
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.
readonly IOptionsMonitor< GeneralConfiguration > generalConfigurationOptions
The IOptionsMonitor<TOptions> of GeneralConfiguration for the ServerUpdater.
async ValueTask< bool > ExecuteUpdate(string updatePath, CancellationToken cancellationToken, CancellationToken criticalCancellationToken)
Executes a pending server update by extracting the new server to a given updatePath ....
async ValueTask< Tuple< BufferedFileStreamProvider, bool >?> PrepareUpdateClearStagingAndBufferStream(string stagingDirectory, CancellationToken cancellationToken)
Prepares the swarm update, deletes the stagingDirectory , and buffers the ServerUpdateOperation....
ServerUpdater(IGitHubServiceFactory gitHubServiceFactory, IIOManager ioManager, IFileDownloader fileDownloader, IServerControl serverControl, ILogger< ServerUpdater > logger, IOptionsMonitor< GeneralConfiguration > generalConfigurationOptions, IOptionsMonitor< UpdatesConfiguration > updatesConfigurationOptions)
Initializes a new instance of the ServerUpdater class.
readonly IOptionsMonitor< UpdatesConfiguration > updatesConfigurationOptions
The IOptionsMonitor<TOptions> of UpdatesConfiguration for the ServerUpdater.
readonly IIOManager ioManager
The IIOManager 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.
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.
ValueTask 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.