tgstation-server 6.9.2
The /tg/station 13 server suite
Loading...
Searching...
No Matches
AdministrationController.cs
Go to the documentation of this file.
1using System;
2using System.IO;
3using System.Linq;
4using System.Net;
7using System.Web;
8
13
14using Octokit;
15
32
34{
40 {
44 const string OctokitException = "Bad GitHub API response, check configuration!";
45
49 static readonly object ReadCacheKey = new();
50
55
60
65
70
75
80
85
90
95
113 IDatabaseContext databaseContext,
114 IAuthenticationContext authenticationContext,
124 IOptions<FileLoggingConfiguration> fileLoggingConfigurationOptions,
126 : base(
127 databaseContext,
128 authenticationContext,
130 logger,
131 true)
132 {
141 fileLoggingConfiguration = fileLoggingConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(fileLoggingConfigurationOptions));
142 }
143
153 [HttpGet]
154 [TgsAuthorize(AdministrationRights.ChangeVersion)]
159 {
160 try
161 {
163 {
164 Version? greatestVersion = null;
165 Uri? repoUrl = null;
166 try
167 {
169 var repositoryUrlTask = gitHubService.GetUpdatesRepositoryUrl(cancellationToken);
171
172 foreach (var kvp in releases)
173 {
174 var version = kvp.Key;
175 var release = kvp.Value;
176 if (version.Major > 3 // Forward/backward compatible but not before TGS4
177 && (greatestVersion == null || version > greatestVersion))
179 }
180
182 }
183 catch (NotFoundException e)
184 {
185 Logger.LogWarning(e, "Not found exception while retrieving upstream repository info!");
186 }
187
188 return Json(new AdministrationResponse
189 {
190 LatestVersion = greatestVersion,
191 TrackedRepositoryUrl = repoUrl,
192 GeneratedAt = DateTimeOffset.UtcNow,
193 });
194 }
195
196 var ttl = TimeSpan.FromMinutes(30);
197 Task<JsonResult> task;
198 if (fresh == true || !cacheService.TryGetValue(ReadCacheKey, out var rawCacheObject))
199 {
200 using var entry = cacheService.CreateEntry(ReadCacheKey);
202 entry.Value = task = CacheFactory();
203 }
204 else
206
207 return await task;
208 }
210 {
211 return RateLimit(e);
212 }
213 catch (ApiException e)
214 {
215 Logger.LogWarning(e, OctokitException);
216 return this.StatusCode(HttpStatusCode.FailedDependency, new ErrorMessageResponse(ErrorCode.RemoteApiError)
217 {
218 AdditionalData = e.Message,
219 });
220 }
221 }
222
234 [HttpPost]
235 [TgsAuthorize(AdministrationRights.ChangeVersion | AdministrationRights.UploadVersion)]
242 {
243 ArgumentNullException.ThrowIfNull(model);
244
247 {
249 return Forbid();
250 }
252 return Forbid();
253
254 if (model.NewVersion == null)
255 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure)
256 {
257 AdditionalData = "newVersion is required!",
258 });
259
260 if (model.NewVersion.Major < 3)
261 return BadRequest(new ErrorMessageResponse(ErrorCode.CannotChangeServerSuite));
262
264 return UnprocessableEntity(new ErrorMessageResponse(ErrorCode.MissingHostWatchdog));
265
267 }
268
275 [HttpDelete]
280 {
281 try
282 {
284 {
285 Logger.LogDebug("Restart request failed due to lack of host watchdog!");
286 return UnprocessableEntity(new ErrorMessageResponse(ErrorCode.MissingHostWatchdog));
287 }
288
290 return NoContent();
291 }
293 {
294 return StatusCode(HttpStatusCode.ServiceUnavailable);
295 }
296 }
297
308 [TgsAuthorize(AdministrationRights.DownloadLogs)]
312 => Paginated(
313 async () =>
314 {
316 try
317 {
319 var tasks = files.Select(
321 {
322 Name = ioManager.GetFileName(file),
323 LastModified = await ioManager
324 .GetLastModified(
327 })
328 .ToList();
329
330 await Task.WhenAll(tasks);
331
333 tasks
334 .AsQueryable()
335 .Select(x => x.Result)
336 .OrderByDescending(x => x.Name));
337 }
338 catch (IOException ex)
339 {
342 {
343 AdditionalData = ex.ToString(),
344 }));
345 }
346 },
347 null,
348 page,
349 pageSize,
351
360 [HttpGet(Routes.Logs + "/{*path}")]
361 [TgsAuthorize(AdministrationRights.DownloadLogs)]
365 {
366 ArgumentNullException.ThrowIfNull(path);
367
368 path = HttpUtility.UrlDecode(path);
369
370 // guard against directory navigation
372 if (path != sanitizedPath)
373 return Forbid();
374
377 path);
378 try
379 {
382 () => null,
383 null,
384 fullPath,
385 true));
386
387 return Ok(new LogFileResponse
388 {
389 Name = path,
391 FileTicket = fileTransferTicket.FileTicket,
392 });
393 }
394 catch (IOException ex)
395 {
396 return Conflict(new ErrorMessageResponse(ErrorCode.IOError)
397 {
398 AdditionalData = ex.ToString(),
399 });
400 }
401 }
402
411 {
414 : null;
415
417 try
418 {
419 try
420 {
422 }
423 catch
424 {
426 await uploadTicket!.DisposeAsync();
427
428 throw;
429 }
430 }
432 {
433 return RateLimit(e);
434 }
435 catch (ApiException e)
436 {
437 Logger.LogWarning(e, OctokitException);
438 return this.StatusCode(HttpStatusCode.FailedDependency, new ErrorMessageResponse(ErrorCode.RemoteApiError)
439 {
440 AdditionalData = e.Message,
441 });
442 }
443
444 return updateResult switch
445 {
449 ServerUpdateResult.SwarmIntegrityCheckFailed => this.StatusCode(HttpStatusCode.FailedDependency, new ErrorMessageResponse(ErrorCode.SwarmIntegrityCheckFailed)),
450 _ => throw new InvalidOperationException($"Unexpected ServerUpdateResult: {updateResult}"),
451 };
452 }
453 }
454}
AdministrationRights? AdministrationRights
The Rights.AdministrationRights for the user.
Represents an error message returned by the server.
Routes to a server actions.
Definition Routes.cs:9
const string Administration
The server administration controller.
Definition Routes.cs:23
const string Logs
The endpoint to download server logs.
Definition Routes.cs:28
string GetFullLogDirectory(IIOManager ioManager, IAssemblyInformationProvider assemblyInformationProvider, IPlatformIdentifier platformIdentifier)
Gets the evaluated log Directory.
ValueTask< IActionResult > ListLogs([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken)
List LogFileResponses present.
readonly FileLoggingConfiguration fileLoggingConfiguration
The FileLoggingConfiguration for the AdministrationController.
readonly IMemoryCache cacheService
The IMemoryCache for the AdministrationController.
readonly IAssemblyInformationProvider assemblyInformationProvider
The IAssemblyInformationProvider for the AdministrationController.
readonly IFileTransferTicketProvider fileTransferService
The IFileTransferTicketProvider for the AdministrationController.
async ValueTask< IActionResult > Read([FromQuery] bool? fresh, CancellationToken cancellationToken)
Get AdministrationResponse server information.
async ValueTask< IActionResult > Update([FromBody] ServerUpdateRequest model, CancellationToken cancellationToken)
Attempt to perform a server upgrade.
AdministrationController(IDatabaseContext databaseContext, IAuthenticationContext authenticationContext, IGitHubServiceFactory gitHubServiceFactory, IServerControl serverControl, IServerUpdateInitiator serverUpdateInitiator, IAssemblyInformationProvider assemblyInformationProvider, IIOManager ioManager, IPlatformIdentifier platformIdentifier, IFileTransferTicketProvider fileTransferService, IMemoryCache cacheService, ILogger< AdministrationController > logger, IOptions< FileLoggingConfiguration > fileLoggingConfigurationOptions, IApiHeadersProvider apiHeadersProvider)
Initializes a new instance of the AdministrationController class.
static readonly object ReadCacheKey
The IMemoryCache key for Read(bool?, CancellationToken).
async ValueTask< IActionResult > GetLog(string path, CancellationToken cancellationToken)
Download a LogFileResponse.
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the AdministrationController.
const string OctokitException
Default Exception.Message for ApiExceptions.
readonly IGitHubServiceFactory gitHubServiceFactory
The IGitHubServiceFactory for the AdministrationController.
readonly IIOManager ioManager
The IIOManager for the AdministrationController.
async ValueTask< IActionResult > AttemptInitiateUpdate(Version newVersion, bool attemptingUpload, CancellationToken cancellationToken)
Attempt to initiate an update.
async ValueTask< IActionResult > Delete()
Attempts to restart the server.
readonly IServerUpdateInitiator serverUpdateInitiator
The IServerUpdateInitiator for the AdministrationController.
readonly IServerControl serverControl
The IServerControl for the AdministrationController.
Base Controller for API functions.
StatusCodeResult StatusCode(HttpStatusCode statusCode)
Strongly type calls to ControllerBase.StatusCode(int).
ObjectResult RateLimit(RateLimitExceededException rateLimitException)
429 response for a given rateLimitException .
ILogger< ApiController > Logger
The ILogger for the ApiController.
PermissionSet PermissionSet
The User's effective PermissionSet.
Represents a file on disk to be downloaded.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
bool WatchdogPresent
true if live updates are supported, false. TryStartUpdate(IServerUpdateExecutor, Version) and Restart...
ValueTask Restart()
Restarts the Host.
ValueTask< ServerUpdateResult > InitiateUpdate(IFileStreamProvider? fileStreamProvider, Version version, CancellationToken cancellationToken)
Start the process of downloading and applying an update to a new server version .
Interface for using filesystems.
Definition IIOManager.cs:13
Task< IReadOnlyList< string > > GetFiles(string path, CancellationToken cancellationToken)
Returns full file names in a given path .
string GetFileName(string path)
Gets the file name portion of a path .
string ConcatPath(params string[] paths)
Combines an array of strings into a path.
Task< DateTimeOffset > GetLastModified(string path, CancellationToken cancellationToken)
Get the DateTimeOffset of when a given path was last modified.
Represents the currently authenticated Models.User.
For identifying the current platform.
Service for temporarily storing files to be downloaded or uploaded.
FileTicketResponse CreateDownload(FileDownloadProvider fileDownloadProvider)
Create a FileTicketResponse for a download.
IFileUploadTicket CreateUpload(FileUploadStreamKind streamKind)
Create a IFileUploadTicket.
A FileTicketResponse that waits for a pending upload.
ValueTask< IGitHubService > CreateService(CancellationToken cancellationToken)
Create a IGitHubService.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
Definition ErrorCode.cs:12
@ List
User may list files if the Models.Instance allows it.
AdministrationRights
Administration rights for the server.
ServerUpdateResult
The result of a call to start a server update.
FileUploadStreamKind
Determines the type of global::System.IO.Stream returned from IFileUploadTicket's created from IFileT...