tgstation-server 6.19.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
InstanceController.cs
Go to the documentation of this file.
1using System;
4using System.IO;
5using System.Linq;
10
15
16using NCrontab;
17
35
37{
42#pragma warning disable CA1506 // TODO: Decomplexify
44 {
48 public const string InstanceAttachFileName = "TGS4_ALLOW_INSTANCE_ATTACH";
49
54
59
64
69
74
79
84
130
139 [HttpPut]
144 {
145 ArgumentNullException.ThrowIfNull(model);
146
147 if (String.IsNullOrWhiteSpace(model.Name) || String.IsNullOrWhiteSpace(model.Path))
148 return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceWhitespaceNameOrPath));
149
151 if (earlyOut != null)
152 return earlyOut;
153
156
159 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtConflictingPath));
160
161 // Validate it's not a child of any other instance
163 .Instances
164 .Where(x => x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier)
165 .Select(x => new Models.Instance
166 {
167 Path = x.Path,
168 })
169 .ToListAsync(cancellationToken);
170
171 var generalConfiguration = generalConfigurationOptions.Value;
172 if ((instancePaths.Count + 1) >= generalConfiguration.InstanceLimit)
173 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceLimitReached));
174
176 .Select(otherInstance => ioManager.PathIsChildOf(otherInstance.Path!, targetInstancePath, cancellationToken))
177 .ToArray();
178
179 await Task.WhenAll(instancePathChecks);
180
181 if (instancePathChecks.Any(task => task.Result))
182 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtConflictingPath));
183
184 // Last test, ensure it's in the list of valid paths
185 var pathChecks = generalConfiguration.ValidInstancePaths?
186 .Select(path => ioManager.PathIsChildOf(path, targetInstancePath, cancellationToken))
187 .ToArray()
188 ?? Enumerable.Empty<Task<bool>>();
189 await Task.WhenAll(pathChecks);
190 if (!pathChecks.All(task => task.Result))
191 return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceNotAtWhitelistedPath));
192
194 {
195 if (!await ioManager.DirectoryExists(targetInstancePath, cancellationToken))
196 return false;
197
198 var filesTask = ioManager.GetFiles(targetInstancePath, cancellationToken);
200
203
204 return files.Concat(dirs).Any();
205 }
206
208 bool attached = false;
211 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtExistingPath));
212 else
213 attached = true;
214
215 var newInstance = await CreateDefaultInstance(model, cancellationToken);
216 if (newInstance == null)
217 return Conflict(new ErrorMessageResponse(ErrorCode.NoPortsAvailable));
218
220 try
221 {
222 await DatabaseContext.Save(cancellationToken);
223
224 try
225 {
226 // actually reserve it now
229 }
230 catch
231 {
232 // oh shit delete the model
234
235 // DCT: Operation must always run
237 throw;
238 }
239 }
240 catch (IOException e)
241 {
242 return Conflict(new ErrorMessageResponse(ErrorCode.IOError)
243 {
244 AdditionalData = e.Message,
245 });
246 }
247
248 Logger.LogInformation(
249 "{userName} {attachedOrCreated} instance {instanceName}: {instanceId} ({instancePath})",
251 attached ? "attached" : "created",
252 newInstance.Name,
253 newInstance.Id,
254 newInstance.Path);
255
257 newInstance.InstancePermissionSets.First(),
258 cancellationToken);
259
260 var api = newInstance.ToApi();
261 api.Accessible = true; // instances are always accessible by their creator
262 return attached ? Json(api) : this.Created(api);
263 }
264
273 [HttpDelete("{id}")]
277 public async ValueTask<IActionResult> Delete(long id, CancellationToken cancellationToken)
278 {
280 .Instances
281 .Where(x => x.Id == id && x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier)
282 .FirstOrDefaultAsync(cancellationToken);
283 if (originalModel == default)
284 return this.Gone();
285 if (originalModel.Online!.Value)
286 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceDetachOnline));
287
290 try
291 {
292 if (await ioManager.DirectoryExists(originalPath, cancellationToken))
293 await ioManager.WriteAllBytes(attachFileName, Array.Empty<byte>(), cancellationToken);
294 }
296 {
297 // DCT: Operation must always run
299 throw;
300 }
301
302 try
303 {
304 // yes this is racy af. I hate it
305 // there's a bug where removing the root instance doesn't work sometimes
308 .Where(x => x.Job!.Instance!.Id == id)
309 .ExecuteDeleteAsync(cancellationToken);
312 .Where(x => x.RevisionInformation.InstanceId == id)
313 .ExecuteDeleteAsync(cancellationToken);
316 .Where(x => x.InstanceId == id)
317 .ExecuteDeleteAsync(cancellationToken);
318
320 await DatabaseContext.Save(cancellationToken); // cascades everything else
321 }
322 catch
323 {
324 await ioManager.DeleteFile(attachFileName, CancellationToken.None); // DCT: Shouldn't be cancelled
325 throw;
326 }
327
328 return NoContent();
329 }
330
340 [HttpPost]
342 InstanceManagerRights.Relocate
343 | InstanceManagerRights.Rename
344 | InstanceManagerRights.SetAutoUpdate
345 | InstanceManagerRights.SetConfiguration
346 | InstanceManagerRights.SetOnline
347 | InstanceManagerRights.SetChatBotLimit
348 | InstanceManagerRights.SetAutoStart
349 | InstanceManagerRights.SetAutoStop)]
353#pragma warning disable CA1502 // TODO: Decomplexify
355 {
356 ArgumentNullException.ThrowIfNull(model);
357
358 IQueryable<Models.Instance> InstanceQuery() => DatabaseContext
359 .Instances
360 .Where(x => x.Id == model.Id && x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier);
361
363 .SelectMany(x => x.Jobs)
364 .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move)
365 .Select(x => new Job(x.Id!.Value))
366 .FirstOrDefaultAsync(cancellationToken);
367
368 if (moveJob != null)
369 {
370 // don't allow them to cancel it if they can't start it.
372 return Forbid();
373 await jobManager.CancelJob(moveJob, AuthenticationContext.User, true, cancellationToken); // cancel it now
374 }
375
377 .Include(x => x.RepositorySettings)
378 .Include(x => x.ChatSettings)
379 .ThenInclude(x => x.Channels)
380 .Include(x => x.DreamDaemonSettings) // need these for onlining
381 .FirstOrDefaultAsync(cancellationToken);
382 if (originalModel == default(Models.Instance))
383 return this.Gone();
384
386 await DatabaseContext.Save(cancellationToken);
387
390 {
392 var property = (PropertyInfo)memberSelectorExpression.Member;
393
394 var newVal = property.GetValue(model);
395 if (newVal == null)
396 return false;
397 if (!userRights.HasFlag(requiredRight) && property.GetValue(originalModel) != newVal)
398 return true;
399
400 property.SetValue(originalModel, newVal);
401 return false;
402 }
403
404 string? originalModelPath = null;
405 string? normalizedPath = null;
406 var originalOnline = originalModel.Online!.Value;
407 if (model.Path != null)
408 {
410
411 if (normalizedPath != originalModel.Path)
412 {
413 if (!userRights.HasFlag(InstanceManagerRights.Relocate))
414 return Forbid();
415 if (originalOnline && model.Online != true)
416 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceRelocateOnline));
417
418 var dirExistsTask = ioManager.DirectoryExists(model.Path, cancellationToken);
419 if (await ioManager.FileExists(model.Path, cancellationToken) || await dirExistsTask)
420 return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtExistingPath));
421
424 }
425 }
426
427 var oldAutoUpdateInterval = originalModel.AutoUpdateInterval!.Value;
428 var oldAutoUpdateCron = originalModel.AutoUpdateCron;
429 var oldAutoStartCron = originalModel.AutoStartCron;
430 var oldAutoStopCron = originalModel.AutoStopCron;
431
433 if (earlyOut != null)
434 return earlyOut;
435
438
439 var changedAutoStart = model.AutoStartCron != null && oldAutoStartCron != model.AutoStartCron;
440 var changedAutoStop = model.AutoStopCron != null && oldAutoStopCron != model.AutoStopCron;
441
442 var renamed = model.Name != null && originalModel.Name != model.Name;
443
444 if (CheckModified(x => x.AutoUpdateInterval, InstanceManagerRights.SetAutoUpdate)
445 || CheckModified(x => x.AutoUpdateCron, InstanceManagerRights.SetAutoUpdate)
446 || CheckModified(x => x.ConfigurationType, InstanceManagerRights.SetConfiguration)
447 || CheckModified(x => x.Name, InstanceManagerRights.Rename)
448 || CheckModified(x => x.Online, InstanceManagerRights.SetOnline)
449 || CheckModified(x => x.ChatBotLimit, InstanceManagerRights.SetChatBotLimit)
450 || CheckModified(x => x.AutoStartCron, InstanceManagerRights.SetAutoStart)
451 || CheckModified(x => x.AutoStopCron, InstanceManagerRights.SetAutoStop))
452 return Forbid();
453
454 if (model.ChatBotLimit.HasValue)
455 {
457 .ChatBots
458 .Where(x => x.InstanceId == originalModel.Id)
459 .CountAsync(cancellationToken);
460
461 if (countOfExistingChatBots > model.ChatBotLimit.Value)
462 return Conflict(new ErrorMessageResponse(ErrorCode.ChatBotMax));
463 }
464
469
470 await DatabaseContext.Save(cancellationToken);
471
472 if (renamed)
473 {
474 // ignoring retval because we don't care if it's offline
477 {
478 await componentInstance.InstanceRenamed(originalModel.Name!, cancellationToken);
479 return null;
480 },
482 }
483
484 var oldAutoStart = originalModel.DreamDaemonSettings!.AutoStart;
485 try
486 {
487 if (originalOnline && model.Online == false)
489 else if (!originalOnline && model.Online == true)
490 {
491 // force autostart false here because we don't want any long running jobs right now
492 // remember to document this
495 }
496 }
497 catch (Exception e)
498 {
500 Logger.LogError(e, "Error changing instance online state!");
503 if (originalModelPath != null)
505
506 // DCT: Operation must always run
508 throw;
509 }
510
511 var api = (AuthenticationContext.GetRight(RightsType.InstanceManager) & (ulong)InstanceManagerRights.Read) != 0 ? originalModel.ToApi() : new InstanceResponse
512 {
513 Id = originalModel.Id,
514 };
515
516 var moving = originalModelPath != null;
517 if (moving)
518 {
519 var description = $"Move instance ID {originalModel.Id} from {originalModelPath} to {normalizedPath}";
522
524 job,
525 (core, databaseContextFactory, paramJob, progressHandler, ct) // core will be null here since the instance is offline
527 cancellationToken);
528 api.MoveJob = job.ToApi();
529 }
530
533 {
534 // ignoring retval because we don't care if it's offline
537 {
538 var autoUpdateTask = changedAutoUpdate
539 ? componentInstance.ScheduleAutoUpdate(model.AutoUpdateInterval!.Value, model.AutoUpdateCron)
540 : ValueTask.CompletedTask;
541
542 var autoStartTask = changedAutoStart
543 ? componentInstance.ScheduleServerStart(model.AutoStartCron)
544 : ValueTask.CompletedTask;
545
546 var autoStopTask = changedAutoStop
547 ? componentInstance.ScheduleServerStop(model.AutoStopCron)
548 : ValueTask.CompletedTask;
549
550 await ValueTaskExtensions.WhenAll(autoUpdateTask, autoStartTask, autoStopTask);
551
552 return null;
553 },
555 }
556
557 await CheckAccessible(api, cancellationToken);
558 return moving ? Accepted(api) : Json(api);
559 }
560#pragma warning restore CA1502
561
574 [FromQuery] int? page,
575 [FromQuery] int? pageSize,
576 CancellationToken cancellationToken)
577 {
578 IQueryable<Models.Instance> GetBaseQuery()
579 {
580 var query = DatabaseContext
581 .Instances
582 .Where(x => x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier);
584 query = query
585 .Where(x => x.InstancePermissionSets.Any(y => y.PermissionSetId == AuthenticationContext.PermissionSet.Id))
586 .Where(x => x.InstancePermissionSets.Any(instanceUser =>
587 instanceUser.EngineRights != EngineRights.None ||
588 instanceUser.ChatBotRights != ChatBotRights.None ||
589 instanceUser.ConfigurationRights != ConfigurationRights.None ||
590 instanceUser.DreamDaemonRights != DreamDaemonRights.None ||
591 instanceUser.DreamMakerRights != DreamMakerRights.None ||
592 instanceUser.InstancePermissionSetRights != InstancePermissionSetRights.None));
593
594 // Hack for EF IAsyncEnumerable BS
595 return query.Select(x => x);
596 }
597
599 .SelectMany(x => x.Jobs)
600 .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move)
601 .Include(x => x.StartedBy!)
602 .ThenInclude(x => x.CreatedBy)
603 .Include(x => x.Instance)
604 .ToListAsync(cancellationToken);
605
606 var needsUpdate = false;
607 var result = await Paginated<Models.Instance, InstanceResponse>(
611 .OrderBy(x => x.Id))),
612 async instance =>
613 {
615 instance.MoveJob = moveJobs.FirstOrDefault(x => x.Instance!.Id == instance.Id)?.ToApi();
616 await CheckAccessible(instance, cancellationToken);
617 },
618 page,
619 pageSize,
620 cancellationToken);
621
622 if (needsUpdate)
623 await DatabaseContext.Save(cancellationToken);
624
625 return result;
626 }
627
636 [HttpGet("{id}")]
640 public async ValueTask<IActionResult> GetId(long id, CancellationToken cancellationToken)
641 {
643 IQueryable<Models.Instance> QueryForUser()
644 {
645 var query = DatabaseContext
646 .Instances
647 .Where(x => x.Id == id && x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier);
648
649 if (cantList)
650 query = query.Include(x => x.InstancePermissionSets);
651 return query;
652 }
653
654 var instance = await QueryForUser().FirstOrDefaultAsync(cancellationToken);
655
656 if (instance == null)
657 return this.Gone();
658
659 if (ValidateInstanceOnlineStatus(instance))
660 await DatabaseContext.Save(cancellationToken);
661
662 if (cantList && !instance.InstancePermissionSets.Any(instanceUser => instanceUser.PermissionSetId == AuthenticationContext.PermissionSet.Require(x => x.Id)
663 && (instanceUser.RepositoryRights != RepositoryRights.None ||
664 instanceUser.EngineRights != EngineRights.None ||
665 instanceUser.ChatBotRights != ChatBotRights.None ||
666 instanceUser.ConfigurationRights != ConfigurationRights.None ||
667 instanceUser.DreamDaemonRights != DreamDaemonRights.None ||
668 instanceUser.DreamMakerRights != DreamMakerRights.None ||
669 instanceUser.InstancePermissionSetRights != InstancePermissionSetRights.None)))
670 return Forbid();
671
672 var api = instance.ToApi();
673
675 .SelectMany(x => x.Jobs)
676 .Where(x => !x.StoppedAt.HasValue && x.JobCode == JobCode.Move)
677 .Include(x => x.StartedBy!)
678 .ThenInclude(x => x.CreatedBy)
679 .Include(x => x.Instance)
680 .FirstOrDefaultAsync(cancellationToken);
681 api.MoveJob = moveJob?.ToApi();
682 await CheckAccessible(api, cancellationToken);
683 return Json(api);
684 }
685
693 [HttpPatch("{id}")]
694 [TgsAuthorize(InstanceManagerRights.GrantPermissions)]
698 {
699 IQueryable<Models.Instance> BaseQuery() => DatabaseContext
700 .Instances
701 .Where(x => x.Id == id && x.SwarmIdentifer == swarmConfigurationOptions.Value.Identifier);
702
703 // ensure the current user has write privilege on the instance
705 .SelectMany(x => x.InstancePermissionSets)
706 .Where(x => x.PermissionSetId == AuthenticationContext.PermissionSet.Id)
707 .FirstOrDefaultAsync(cancellationToken);
708 if (usersInstancePermissionSet == default)
709 {
710 // does the instance actually exist?
712 .AnyAsync(cancellationToken);
713
714 if (!instanceExists)
715 return this.Gone();
716
720 }
721 else
723
724 await DatabaseContext.Save(cancellationToken);
725
726 return NoContent();
727 }
728
736 {
737 var ddPort = await portAllocator.GetAvailablePort(1024, false, cancellationToken);
738 if (!ddPort.HasValue)
739 return null;
740
741 // try to use the old default if possible
742 const ushort DefaultDreamDaemonPort = 1337;
743 if (ddPort.Value < DefaultDreamDaemonPort)
745
746 const ushort DefaultApiValidationPort = 1339;
749 Math.Min((ushort)(ddPort.Value + 1), DefaultApiValidationPort),
750 false,
751 cancellationToken);
752 if (!dmPort.HasValue)
753 return null;
754
755 // try to use the old default if possible
758
759 return new Models.Instance
760 {
763 {
764 AllowWebClient = false,
765 AutoStart = false,
766 Port = ddPort,
767 OpenDreamTopicPort = 0,
768 SecurityLevel = DreamDaemonSecurity.Safe,
769 Visibility = DreamDaemonVisibility.Public,
770 StartupTimeout = 60,
771 HealthCheckSeconds = 60,
772 DumpOnHealthCheckRestart = false,
773 TopicRequestTimeout = generalConfigurationOptions.Value.ByondTopicTimeout,
774 AdditionalParameters = String.Empty,
775 StartProfiler = false,
776 LogOutput = false,
777 MapThreads = 0,
778 Minidumps = true,
779 },
781 {
782 ApiValidationPort = dmPort,
783 ApiValidationSecurityLevel = DreamDaemonSecurity.Safe,
785 Timeout = TimeSpan.FromHours(1),
786 CompilerAdditionalArguments = null,
787 },
788 Name = initialSettings.Name,
789 Online = false,
790 Path = initialSettings.Path,
791 AutoUpdateInterval = initialSettings.AutoUpdateInterval ?? 0,
792 AutoUpdateCron = initialSettings.AutoUpdateCron ?? String.Empty,
793 AutoStartCron = initialSettings.AutoStartCron ?? String.Empty,
794 AutoStopCron = initialSettings.AutoStopCron ?? String.Empty,
797 {
798 CommitterEmail = Components.Repository.Repository.DefaultCommitterEmail,
799 CommitterName = Components.Repository.Repository.DefaultCommitterName,
800 PushTestMergeCommits = false,
801 ShowTestMergeCommitters = false,
802 AutoUpdatesKeepTestMerges = false,
803 AutoUpdatesSynchronize = false,
804 PostTestMergeComment = false,
805 CreateGitHubDeployments = false,
806 UpdateSubmodules = true,
807 },
808 InstancePermissionSets = new List<InstancePermissionSet> // give this user full privileges on the instance
809 {
811 },
812 SwarmIdentifer = swarmConfigurationOptions.Value.Identifier,
813 };
814 }
815
837
843 [return: NotNullIfNotNull(nameof(path))]
844 string? NormalizePath(string? path)
845 {
846 if (path == null)
847 return null;
848
851
852 return path;
853 }
854
862 {
865 .Where(x => x.InstanceId == instanceResponse.Id && x.PermissionSetId == AuthenticationContext.PermissionSet.Id)
866 .AnyAsync(cancellationToken);
867 }
868
875 {
876 if (!String.IsNullOrWhiteSpace(instance.AutoUpdateCron))
877 {
878 if ((instance.AutoUpdateInterval.HasValue && instance.AutoUpdateInterval.Value != 0)
879 || (CrontabSchedule.TryParse(
880 instance.AutoUpdateCron,
881 new CrontabSchedule.ParseOptions
882 {
883 IncludingSeconds = true,
884 }) == null))
885 return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
886
888 }
889 else
891
892 return null;
893 }
894 }
895}
Represents a set of server permissions.
InstanceManagerRights? InstanceManagerRights
The Rights.InstanceManagerRights for the user.
Represents configurable settings for a git repository.
Represents an error message returned by the server.
Routes to a server actions.
Definition Routes.cs:9
const string InstanceManager
The Models.Instance controller.
Definition Routes.cs:48
const string List
The postfix for list operations.
Definition Routes.cs:113
Extension methods for the ValueTask and ValueTask<TResult> classes.
static async ValueTask WhenAll(IEnumerable< ValueTask > tasks)
Fully await a given list of tasks .
ILogger< ApiController > Logger
The ILogger for the ApiController.
async ValueTask< IActionResult?> WithComponentInstanceNullable(Func< IInstanceCore, ValueTask< IActionResult?> > action, Models.Instance? instance=null)
Run a given action with the relevant IInstance.
IInstanceOperations InstanceOperations
Access the IInstanceOperations instance.
readonly IInstanceManager instanceManager
The IInstanceManager for the ComponentInterfacingController.
bool ValidateInstanceOnlineStatus(Api.Models.Instance metadata)
Corrects discrepencies between the Api.Models.Instance.Online status of IInstances in the database vs...
ApiController for managing Components.Instances.
async ValueTask< Models.Instance?> CreateDefaultInstance(InstanceCreateRequest initialSettings, CancellationToken cancellationToken)
Creates a default Models.Instance from initialSettings .
readonly IOptions< SwarmConfiguration > swarmConfigurationOptions
The IOptions<TOptions> of SwarmConfiguration for the InstanceController.
async ValueTask< IActionResult > GetId(long id, CancellationToken cancellationToken)
Get a specific Api.Models.Instance.
readonly IJobManager jobManager
The IJobManager for the InstanceController.
BadRequestObjectResult? ValidateCronSetting(Api.Models.Instance instance)
Validates a given instance 's Api.Models.Instance.AutoUpdateCron setting.
string? NormalizePath(string? path)
Normalize a given path for an instance.
readonly IPortAllocator portAllocator
The IPortAllocator for the InstanceController.
async ValueTask< IActionResult > Update([FromBody] InstanceUpdateRequest model, CancellationToken cancellationToken)
Modify an Api.Models.Instance's settings.
InstancePermissionSet InstanceAdminPermissionSet(InstancePermissionSet? permissionSetToModify)
Generate an InstancePermissionSet with full rights.
async ValueTask< IActionResult > List([FromQuery] int? page, [FromQuery] int? pageSize, CancellationToken cancellationToken)
List Api.Models.Instances.
const string InstanceAttachFileName
File name to allow attaching instances.
readonly IOptionsSnapshot< GeneralConfiguration > generalConfigurationOptions
The IOptionsSnapshot<TOptions> of GeneralConfiguration for the InstanceController.
async ValueTask< IActionResult > Create([FromBody] InstanceCreateRequest model, CancellationToken cancellationToken)
Create or attach an Api.Models.Instance.
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the InstanceController.
InstanceController(IDatabaseContext databaseContext, IAuthenticationContext authenticationContext, ILogger< InstanceController > logger, IInstanceManager instanceManager, IJobManager jobManager, IIOManager ioManager, IPlatformIdentifier platformIdentifier, IPortAllocator portAllocator, IPermissionsUpdateNotifyee permissionsUpdateNotifyee, IOptions< SwarmConfiguration > swarmConfigurationOptions, IOptionsSnapshot< GeneralConfiguration > generalConfigurationOptions, IApiHeadersProvider apiHeaders)
Initializes a new instance of the InstanceController class.
readonly IPermissionsUpdateNotifyee permissionsUpdateNotifyee
The IPermissionsUpdateNotifyee for the InstanceController.
async ValueTask< IActionResult > Delete(long id, CancellationToken cancellationToken)
Detach an Api.Models.Instance with the given id .
async ValueTask CheckAccessible(InstanceResponse instanceResponse, CancellationToken cancellationToken)
Populate the InstanceResponse.Accessible property of a given instanceResponse .
readonly IIOManager ioManager
The IIOManager for the InstanceController.
async ValueTask< IActionResult > GrantPermissions(long id, CancellationToken cancellationToken)
Gives the current user full permissions on a given instance id .
Backend abstract implementation of IDatabaseContext.
DbSet< Instance > Instances
The Instances in the DatabaseContext.
DbSet< InstancePermissionSet > InstancePermissionSets
The InstancePermissionSets in the DatabaseContext.
DbSet< CompileJob > CompileJobs
The CompileJobs in the DatabaseContext.
Task Save(CancellationToken cancellationToken)
Saves changes made to the IDatabaseContext.A Task representing the running operation.
DbSet< ChatBot > ChatBots
The ChatBots in the DatabaseContext.
DbSet< RevInfoTestMerge > RevInfoTestMerges
The RevInfoTestMerges in the DatabaseContext.
DbSet< RevisionInformation > RevisionInformations
The RevisionInformations in the DatabaseContext.
IIOManager that resolves paths to Environment.CurrentDirectory.
const string CurrentDirectory
Path to the current working directory for the IIOManager.
Instance? Instance
The parent Models.Instance.
Represents an Api.Models.Instance in the database.
Definition Instance.cs:11
const ushort DefaultChatBotLimit
Default for Api.Models.Instance.ChatBotLimit.
Definition Instance.cs:15
static Job Create(JobCode code, User? startedBy, Api.Models.Instance instance)
Creates a new job for registering in the Jobs.IJobService.
PermissionSet PermissionSet
The User's effective PermissionSet.
ulong GetRight(RightsType rightsType)
Get the value of a given rightsType .The value of rightsType . Note that if InstancePermissionSet is ...
ValueTask OnlineInstance(Models.Instance metadata, CancellationToken cancellationToken)
Online an IInstance.
ValueTask MoveInstance(Models.Instance metadata, string oldPath, CancellationToken cancellationToken)
Move an IInstance.
ValueTask OfflineInstance(Models.Instance metadata, User user, CancellationToken cancellationToken)
Offline an IInstance.
Interface for using filesystems.
Definition IIOManager.cs:14
Task< IReadOnlyList< string > > GetFiles(string path, CancellationToken cancellationToken)
Returns full file names in a given path .
Task< bool > PathIsChildOf(string parentPath, string childPath, CancellationToken cancellationToken)
Check if a given parentPath is a parent of a given parentPath .
string ResolvePath()
Retrieve the full path of the current working directory.
string ConcatPath(params string[] paths)
Combines an array of strings into a path.
Task< IReadOnlyList< string > > GetDirectories(string path, CancellationToken cancellationToken)
Returns full directory names in a given path .
Task CreateDirectory(string path, CancellationToken cancellationToken)
Create a directory at path .
Task DeleteFile(string path, CancellationToken cancellationToken)
Deletes a file at path .
ValueTask WriteAllBytes(string path, byte[] contents, CancellationToken cancellationToken)
Writes some contents to a file at path overwriting previous content.
Task< bool > FileExists(string path, CancellationToken cancellationToken)
Check that the file at path exists.
Task< bool > DirectoryExists(string path, CancellationToken cancellationToken)
Check that the directory at path exists.
Manages the runtime of Jobs.
ValueTask< Job?> CancelJob(Job job, User? user, bool blocking, CancellationToken cancellationToken)
Cancels a give job .
ValueTask RegisterOperation(Job job, JobEntrypoint operation, CancellationToken cancellationToken)
Registers a given Job and begins running it.
For creating and accessing authentication contexts.
Receives notifications about permissions updates.
ValueTask InstancePermissionSetCreated(InstancePermissionSet instancePermissionSet, CancellationToken cancellationToken)
Called when a given instancePermissionSet is successfully created.
For identifying the current platform.
string NormalizePath(string path)
Normalize a path for consistency.
Gets unassigned ports for use by TGS.
ValueTask< ushort?> GetAvailablePort(ushort basePort, bool checkOne, CancellationToken cancellationToken)
Gets a port not currently in use by TGS.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
Definition ErrorCode.cs:12
DreamDaemonVisibility
The visibility setting for DreamDaemon.
JobCode
The different types of Response.JobResponse.
Definition JobCode.cs:9
ConfigurationType
The type of configuration allowed on an Instance.
@ Online
The watchdog is online and DreamDaemon is running.
DreamDaemonSecurity
DreamDaemon's security level.
DMApiValidationMode
The DMAPI validation setting for deployments.
ChatBotRights
Rights for chat bots.
ConfigurationRights
Rights for Models.IConfigurationFiles.
@ List
User may list files if the Models.Instance allows it.
DreamMakerRights
Rights for deployment.
RightsType
The type of rights a model uses.
Definition RightsType.cs:7
EngineRights
Rights for engine version management.
RepositoryRights
Rights for the git repository.
InstancePermissionSetRights
Rights for an Models.Instance.
DreamDaemonRights
Rights for managing DreamDaemon.
InstanceManagerRights
Rights for managing Models.Instances.
@ Api
The ApiHeaders.ApiVersionHeader header is missing or invalid.