tgstation-server  4.3.2
The /tg/station 13 server suite
InstanceController.cs
Go to the documentation of this file.
1 using Microsoft.AspNetCore.Mvc;
2 using Microsoft.EntityFrameworkCore;
3 using Microsoft.Extensions.Logging;
4 using Microsoft.Extensions.Options;
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.IO;
9 using System.Linq;
10 using System.Linq.Expressions;
11 using System.Net;
12 using System.Reflection;
13 using System.Threading;
14 using System.Threading.Tasks;
15 using Tgstation.Server.Api;
21 using Tgstation.Server.Host.IO;
26 
27 namespace Tgstation.Server.Host.Controllers
28 {
32  [Route(Routes.InstanceManager)]
33  #pragma warning disable CA1506 // TODO: Decomplexify
34  public sealed class InstanceController : ApiController
35  {
39  const string InstanceAttachFileName = "TGS4_ALLOW_INSTANCE_ATTACH";
40 
41  const string MoveInstanceJobPrefix = "Move instance ID ";
42 
47 
52 
57 
62 
67 
72 
86  IDatabaseContext databaseContext,
87  IAuthenticationContextFactory authenticationContextFactory,
88  IJobManager jobManager,
89  IInstanceManager instanceManager,
90  IIOManager ioManager,
91  IAssemblyInformationProvider assemblyInformationProvider,
92  IPlatformIdentifier platformIdentifier,
93  IOptions<GeneralConfiguration> generalConfigurationOptions,
94  ILogger<InstanceController> logger)
95  : base(databaseContext, authenticationContextFactory, logger, false, true)
96  {
97  this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager));
98  this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
99  this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
100  this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider));
101  this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier));
102  generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions));
103  }
104 
105  string NormalizePath(string path)
106  {
107  if (path == null)
108  return null;
109 
110  path = ioManager.ResolvePath(path);
111  if (platformIdentifier.IsWindows)
112  path = path.ToUpperInvariant().Replace('\\', '/');
113 
114  return path;
115  }
116 
117  Models.InstanceUser InstanceAdminUser() => new Models.InstanceUser
118  {
119  ByondRights = (ByondRights)~0U,
126  UserId = AuthenticationContext.User.Id
127  };
128 
137  [HttpPut]
138  [TgsAuthorize(InstanceManagerRights.Create)]
139  [ProducesResponseType(typeof(Api.Models.Instance), 200)]
140  [ProducesResponseType(typeof(Api.Models.Instance), 201)]
141  public async Task<IActionResult> Create([FromBody] Api.Models.Instance model, CancellationToken cancellationToken)
142  {
143  if (model == null)
144  throw new ArgumentNullException(nameof(model));
145 
146  if (String.IsNullOrWhiteSpace(model.Name))
147  return BadRequest(new ErrorMessage(ErrorCode.InstanceWhitespaceName));
148 
149  var targetInstancePath = NormalizePath(model.Path);
150  model.Path = targetInstancePath;
151 
152  var installationDirectoryPath = NormalizePath(DefaultIOManager.CurrentDirectory);
153 
154  bool InstanceIsChildOf(string otherPath)
155  {
156  if (!targetInstancePath.StartsWith(otherPath, StringComparison.Ordinal))
157  return false;
158 
159  bool sameLength = targetInstancePath.Length == otherPath.Length;
160  char dirSeparatorChar = targetInstancePath.ToCharArray()[Math.Min(otherPath.Length, targetInstancePath.Length - 1)];
161  return sameLength
162  || dirSeparatorChar == Path.DirectorySeparatorChar
163  || dirSeparatorChar == Path.AltDirectorySeparatorChar;
164  }
165 
166  if (InstanceIsChildOf(installationDirectoryPath))
167  return Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
168 
169  // Validate it's not a child of any other instance
170  IActionResult earlyOut = null;
171  ulong countOfOtherInstances = 0;
172  using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
173  {
174  var newCancellationToken = cts.Token;
175  try
176  {
177  await DatabaseContext
178  .Instances
179  .AsQueryable()
180  .Select(x => new Models.Instance
181  {
182  Path = x.Path
183  })
184  .ForEachAsync(
185  otherInstance =>
186  {
187  if (++countOfOtherInstances >= generalConfiguration.InstanceLimit)
188  earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached));
189  else if (InstanceIsChildOf(otherInstance.Path))
190  earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath));
191 
192  if (earlyOut != null && !newCancellationToken.IsCancellationRequested)
193  cts.Cancel();
194  },
195  newCancellationToken)
196  .ConfigureAwait(false);
197  }
198  catch (OperationCanceledException)
199  {
200  cancellationToken.ThrowIfCancellationRequested();
201  }
202  }
203 
204  if (earlyOut != null)
205  return earlyOut;
206 
207  // Last test, ensure it's in the list of valid paths
208  if (!(generalConfiguration.ValidInstancePaths?
209  .Select(path => NormalizePath(path))
210  .Any(path => InstanceIsChildOf(path)) ?? true))
211  return BadRequest(new ErrorMessage(ErrorCode.InstanceNotAtWhitelistedPath));
212 
213  async Task<bool> DirExistsAndIsNotEmpty()
214  {
215  if (!await ioManager.DirectoryExists(model.Path, cancellationToken).ConfigureAwait(false))
216  return false;
217 
218  var filesTask = ioManager.GetFiles(model.Path, cancellationToken);
219  var dirsTask = ioManager.GetDirectories(model.Path, cancellationToken);
220 
221  var files = await filesTask.ConfigureAwait(false);
222  var dirs = await dirsTask.ConfigureAwait(false);
223 
224  return files.Concat(dirs).Any();
225  }
226 
227  var dirExistsTask = DirExistsAndIsNotEmpty();
228  bool attached = false;
229  if (await ioManager.FileExists(model.Path, cancellationToken).ConfigureAwait(false) || await dirExistsTask.ConfigureAwait(false))
230  if (!await ioManager.FileExists(ioManager.ConcatPath(model.Path, InstanceAttachFileName), cancellationToken).ConfigureAwait(false))
231  return Conflict(new ErrorMessage(ErrorCode.InstanceAtExistingPath));
232  else
233  attached = true;
234 
235  var newInstance = new Models.Instance
236  {
237  ConfigurationType = model.ConfigurationType ?? ConfigurationType.Disallowed,
239  {
240  AllowWebClient = false,
241  AutoStart = false,
242  PrimaryPort = 1337,
243  SecondaryPort = 1338,
244  SecurityLevel = DreamDaemonSecurity.Safe,
245  StartupTimeout = 60,
246  HeartbeatSeconds = 60
247  },
249  {
250  ApiValidationPort = 1339,
251  ApiValidationSecurityLevel = DreamDaemonSecurity.Safe
252  },
253  Name = model.Name,
254  Online = false,
255  Path = model.Path,
256  AutoUpdateInterval = model.AutoUpdateInterval ?? 0,
257  ChatBotLimit = model.ChatBotLimit ?? Models.Instance.DefaultChatBotLimit,
259  {
260  CommitterEmail = "tgstation-server@users.noreply.github.com",
261  CommitterName = assemblyInformationProvider.VersionPrefix,
262  PushTestMergeCommits = false,
263  ShowTestMergeCommitters = false,
264  AutoUpdatesKeepTestMerges = false,
265  AutoUpdatesSynchronize = false,
266  PostTestMergeComment = false
267  },
268  InstanceUsers = new List<Models.InstanceUser> // give this user full privileges on the instance
269  {
270  InstanceAdminUser()
271  }
272  };
273 
274  DatabaseContext.Instances.Add(newInstance);
275  try
276  {
277  await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
278 
279  try
280  {
281  // actually reserve it now
282  await ioManager.CreateDirectory(targetInstancePath, cancellationToken).ConfigureAwait(false);
283  await ioManager.DeleteFile(ioManager.ConcatPath(targetInstancePath, InstanceAttachFileName), cancellationToken).ConfigureAwait(false);
284  }
285  catch
286  {
287  // oh shit delete the model
288  DatabaseContext.Instances.Remove(newInstance);
289 
290  await DatabaseContext.Save(default).ConfigureAwait(false);
291  throw;
292  }
293  }
294  catch (IOException e)
295  {
296  return Conflict(new ErrorMessage(ErrorCode.IOError)
297  {
298  AdditionalData = e.Message
299  });
300  }
301 
302  Logger.LogInformation("{0} {1} instance {2}: {3} ({4})", AuthenticationContext.User.Name, attached ? "attached" : "created", newInstance.Name, newInstance.Id, newInstance.Path);
303 
304  var api = newInstance.ToApi();
305  return attached ? (IActionResult)Json(api) : StatusCode((int)HttpStatusCode.Created, api);
306  }
307 
316  [HttpDelete("{id}")]
317  [TgsAuthorize(InstanceManagerRights.Delete)]
318  [ProducesResponseType(204)]
319  [ProducesResponseType(410)]
320  public async Task<IActionResult> Delete(long id, CancellationToken cancellationToken)
321  {
322  var originalModel = await DatabaseContext
323  .Instances
324  .AsQueryable()
325  .Where(x => x.Id == id)
326  .Include(x => x.WatchdogReattachInformation)
327  .Include(x => x.WatchdogReattachInformation.Alpha)
328  .Include(x => x.WatchdogReattachInformation.Bravo)
329  .FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
330  if (originalModel == default)
331  return StatusCode((int)HttpStatusCode.Gone);
332  if (originalModel.Online.Value)
333  return Conflict(new ErrorMessage(ErrorCode.InstanceDetachOnline));
334 
335  if (originalModel.WatchdogReattachInformation != null)
336  {
337  DatabaseContext.WatchdogReattachInformations.Remove(originalModel.WatchdogReattachInformation);
338  if (originalModel.WatchdogReattachInformation.Alpha != null)
339  DatabaseContext.ReattachInformations.Remove(originalModel.WatchdogReattachInformation.Alpha);
340  if (originalModel.WatchdogReattachInformation.Bravo != null)
341  DatabaseContext.ReattachInformations.Remove(originalModel.WatchdogReattachInformation.Bravo);
342  }
343 
344  DatabaseContext.Instances.Remove(originalModel);
345 
346  var attachFileName = ioManager.ConcatPath(originalModel.Path, InstanceAttachFileName);
347  await ioManager.WriteAllBytes(attachFileName, Array.Empty<byte>(), default).ConfigureAwait(false);
348  await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); // cascades everything
349  return NoContent();
350  }
351 
360  [HttpPost]
361  [TgsAuthorize(InstanceManagerRights.Relocate | InstanceManagerRights.Rename | InstanceManagerRights.SetAutoUpdate | InstanceManagerRights.SetConfiguration | InstanceManagerRights.SetOnline | InstanceManagerRights.SetChatBotLimit)]
362  [ProducesResponseType(typeof(Api.Models.Instance), 200)]
363  [ProducesResponseType(typeof(Api.Models.Instance), 202)]
364  [ProducesResponseType(410)]
365 #pragma warning disable CA1502 // TODO: Decomplexify
366  public async Task<IActionResult> Update([FromBody] Api.Models.Instance model, CancellationToken cancellationToken)
367  {
368  if (model == null)
369  throw new ArgumentNullException(nameof(model));
370 
371  IQueryable<Models.Instance> InstanceQuery() => DatabaseContext
372  .Instances
373  .AsQueryable()
374  .Where(x => x.Id == model.Id);
375 
376  var moveJob = await InstanceQuery()
377  .SelectMany(x => x.Jobs).
378 #pragma warning disable CA1307 // Specify StringComparison
379  Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix))
380 #pragma warning restore CA1307 // Specify StringComparison
381  .Select(x => new Models.Job
382  {
383  Id = x.Id
384  }).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
385 
386  if (moveJob != default)
387  await jobManager.CancelJob(moveJob, AuthenticationContext.User, true, cancellationToken).ConfigureAwait(false); // cancel it now
388 
389  var originalModel = await InstanceQuery()
390  .Include(x => x.RepositorySettings)
391  .Include(x => x.ChatSettings)
392  .ThenInclude(x => x.Channels)
393  .Include(x => x.DreamDaemonSettings) // need these for onlining
394  .FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
395  if (originalModel == default(Models.Instance))
396  return StatusCode((int)HttpStatusCode.Gone);
397 
398  var userRights = (InstanceManagerRights)AuthenticationContext.GetRight(RightsType.InstanceManager);
399  bool CheckModified<T>(Expression<Func<Api.Models.Instance, T>> expression, InstanceManagerRights requiredRight)
400  {
401  var memberSelectorExpression = (MemberExpression)expression.Body;
402  var property = (PropertyInfo)memberSelectorExpression.Member;
403 
404  var newVal = property.GetValue(model);
405  if (newVal == null)
406  return false;
407  if (!userRights.HasFlag(requiredRight) && property.GetValue(originalModel) != newVal)
408  return true;
409 
410  property.SetValue(originalModel, newVal);
411  return false;
412  }
413 
414  string originalModelPath = null;
415  string rawPath = null;
416  if (model.Path != null)
417  {
418  rawPath = NormalizePath(model.Path);
419 
420  if (model.Path != originalModel.Path)
421  {
422  if (!userRights.HasFlag(InstanceManagerRights.Relocate))
423  return Forbid();
424  if (originalModel.Online.Value && model.Online != true)
425  return Conflict(new ErrorMessage(ErrorCode.InstanceRelocateOnline));
426 
427  var dirExistsTask = ioManager.DirectoryExists(model.Path, cancellationToken);
428  if (await ioManager.FileExists(model.Path, cancellationToken).ConfigureAwait(false) || await dirExistsTask.ConfigureAwait(false))
429  return Conflict(new ErrorMessage(ErrorCode.InstanceAtExistingPath));
430 
431  originalModelPath = originalModel.Path;
432  originalModel.Path = model.Path;
433  }
434  }
435 
436  var oldAutoUpdateInterval = originalModel.AutoUpdateInterval.Value;
437  var originalOnline = originalModel.Online.Value;
438  var renamed = model.Name != null && originalModel.Name != model.Name;
439 
440  if (CheckModified(x => x.AutoUpdateInterval, InstanceManagerRights.SetAutoUpdate)
441  || CheckModified(x => x.ConfigurationType, InstanceManagerRights.SetConfiguration)
442  || CheckModified(x => x.Name, InstanceManagerRights.Rename)
443  || CheckModified(x => x.Online, InstanceManagerRights.SetOnline)
444  || CheckModified(x => x.ChatBotLimit, InstanceManagerRights.SetChatBotLimit))
445  return Forbid();
446 
447  if (model.ChatBotLimit.HasValue)
448  {
449  var countOfExistingChatBots = await DatabaseContext
450  .ChatBots
451  .AsQueryable()
452  .Where(x => x.InstanceId == originalModel.Id)
453  .CountAsync(cancellationToken)
454  .ConfigureAwait(false);
455 
456  if (countOfExistingChatBots > model.ChatBotLimit.Value)
457  return Conflict(new ErrorMessage(ErrorCode.ChatBotMax));
458  }
459 
460  // ensure the current user has write privilege on the instance
461  var usersInstanceUser = await InstanceQuery()
462  .SelectMany(x => x.InstanceUsers)
463  .Where(x => x.UserId == AuthenticationContext.User.Id)
464  .FirstOrDefaultAsync(cancellationToken)
465  .ConfigureAwait(false);
466  if (usersInstanceUser == default)
467  {
468  var instanceAdminUser = InstanceAdminUser();
469  instanceAdminUser.InstanceId = originalModel.Id;
470  DatabaseContext.InstanceUsers.Add(instanceAdminUser);
471  }
472  else
473  usersInstanceUser.InstanceUserRights |= InstanceUserRights.WriteUsers;
474 
475  await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
476 
477  if (renamed)
478  await instanceManager.GetInstance(originalModel).InstanceRenamed(originalModel.Name, cancellationToken).ConfigureAwait(false);
479 
480  var oldAutoStart = originalModel.DreamDaemonSettings.AutoStart;
481  try
482  {
483  if (originalOnline && model.Online == false)
484  await instanceManager.OfflineInstance(originalModel, AuthenticationContext.User, cancellationToken).ConfigureAwait(false);
485  else if (!originalOnline && model.Online == true)
486  {
487  // force autostart false here because we don't want any long running jobs right now
488  // remember to document this
489  originalModel.DreamDaemonSettings.AutoStart = false;
490  await instanceManager.OnlineInstance(originalModel, cancellationToken).ConfigureAwait(false);
491  }
492  }
493  catch (Exception e)
494  {
495  if(!(e is OperationCanceledException))
496  Logger.LogError("Error changing instance online state! Exception: {0}", e);
497  originalModel.Online = originalOnline;
498  originalModel.DreamDaemonSettings.AutoStart = oldAutoStart;
499  if (originalModelPath != null)
500  originalModel.Path = originalModelPath;
501  await DatabaseContext.Save(default).ConfigureAwait(false);
502  throw;
503  }
504 
505  var api = (AuthenticationContext.GetRight(RightsType.InstanceManager) & (ulong)InstanceManagerRights.Read) != 0 ? originalModel.ToApi() : new Api.Models.Instance
506  {
507  Id = originalModel.Id
508  };
509 
510  var moving = originalModelPath != null;
511  if (moving)
512  {
513  var job = new Models.Job
514  {
515  Description = String.Format(CultureInfo.InvariantCulture, MoveInstanceJobPrefix + "{0} from {1} to {2}", originalModel.Id, originalModel.Path, rawPath),
516  Instance = originalModel,
517  CancelRightsType = RightsType.InstanceManager,
518  CancelRight = (ulong)InstanceManagerRights.Relocate,
519  StartedBy = AuthenticationContext.User
520  };
521 
522  await jobManager.RegisterOperation(job, (paramJob, databaseContextFactory, progressHandler, ct) => instanceManager.MoveInstance(originalModel, rawPath, ct), cancellationToken).ConfigureAwait(false);
523  api.MoveJob = job.ToApi();
524  }
525 
526  if (originalModel.Online.Value && model.AutoUpdateInterval.HasValue && oldAutoUpdateInterval != model.AutoUpdateInterval)
527  await instanceManager.GetInstance(originalModel).SetAutoUpdateInterval(model.AutoUpdateInterval.Value).ConfigureAwait(false);
528 
529  return moving ? (IActionResult)Accepted(api) : Json(api);
530  }
531 #pragma warning restore CA1502
532 
539  [HttpGet(Routes.List)]
540  [TgsAuthorize(InstanceManagerRights.List | InstanceManagerRights.Read)]
541  [ProducesResponseType(typeof(IEnumerable<Api.Models.Instance>), 200)]
542  public async Task<IActionResult> List(CancellationToken cancellationToken)
543  {
544  IQueryable<Models.Instance> GetBaseQuery()
545  {
546  IQueryable<Models.Instance> query = DatabaseContext.Instances;
548  query = query
549  .Where(x => x.InstanceUsers.Any(y => y.UserId == AuthenticationContext.User.Id))
550  .Where(x => x.InstanceUsers.Any(instanceUser =>
551  instanceUser.ByondRights != ByondRights.None ||
552  instanceUser.ChatBotRights != ChatBotRights.None ||
553  instanceUser.ConfigurationRights != ConfigurationRights.None ||
554  instanceUser.DreamDaemonRights != DreamDaemonRights.None ||
555  instanceUser.DreamMakerRights != DreamMakerRights.None ||
556  instanceUser.InstanceUserRights != InstanceUserRights.None));
557 
558  // Hack for EF IAsyncEnumerable BS
559  return query.Select(x => x);
560  }
561 
562  var moveJobs = await GetBaseQuery()
563  .SelectMany(x => x.Jobs)
564 #pragma warning disable CA1307 // Specify StringComparison
565  .Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix))
566 #pragma warning restore CA1307 // Specify StringComparison
567  .Include(x => x.StartedBy).ThenInclude(x => x.CreatedBy)
568  .Include(x => x.Instance)
569  .ToListAsync(cancellationToken)
570  .ConfigureAwait(false);
571 
572  var instances = await GetBaseQuery()
573  .ToListAsync(cancellationToken)
574  .ConfigureAwait(false);
575 
576  var apis = instances.Select(x => x.ToApi());
577  foreach(var I in moveJobs)
578  apis.Where(x => x.Id == I.Instance.Id).First().MoveJob = I.ToApi(); // if this .First() fails i will personally murder kevinz000 because I just know he is somehow responsible
579  return Json(apis);
580  }
581 
590  [HttpGet("{id}")]
591  [TgsAuthorize(InstanceManagerRights.List | InstanceManagerRights.Read)]
592  [ProducesResponseType(typeof(Api.Models.Instance), 200)]
593  [ProducesResponseType(410)]
594  public async Task<IActionResult> GetId(long id, CancellationToken cancellationToken)
595  {
596  var cantList = !AuthenticationContext.User.InstanceManagerRights.Value.HasFlag(InstanceManagerRights.List);
597  IQueryable<Models.Instance> QueryForUser()
598  {
599  var query = DatabaseContext
600  .Instances
601  .AsQueryable()
602  .Where(x => x.Id == id);
603 
604  if (cantList)
605  query = query.Include(x => x.InstanceUsers);
606  return query;
607  }
608 
609  var instance = await QueryForUser().FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
610 
611  if (instance == null)
612  return StatusCode((int)HttpStatusCode.Gone);
613 
614  if (cantList && !instance.InstanceUsers.Any(instanceUser => instanceUser.UserId == AuthenticationContext.User.Id &&
615  (instanceUser.ByondRights != ByondRights.None ||
616  instanceUser.ChatBotRights != ChatBotRights.None ||
617  instanceUser.ConfigurationRights != ConfigurationRights.None ||
618  instanceUser.DreamDaemonRights != DreamDaemonRights.None ||
619  instanceUser.DreamMakerRights != DreamMakerRights.None ||
620  instanceUser.InstanceUserRights != InstanceUserRights.None)))
621  return Forbid();
622 
623  var api = instance.ToApi();
624 
625  var moveJob = await QueryForUser()
626  .SelectMany(x => x.Jobs)
627 #pragma warning disable CA1307 // Specify StringComparison
628  .Where(x => !x.StoppedAt.HasValue && x.Description.StartsWith(MoveInstanceJobPrefix))
629 #pragma warning restore CA1307 // Specify StringComparison
630  .Include(x => x.StartedBy).ThenInclude(x => x.CreatedBy)
631  .FirstOrDefaultAsync(cancellationToken)
632  .ConfigureAwait(false);
633  api.MoveJob = moveJob?.ToApi();
634  return Json(api);
635  }
636  }
637 }
string Name
The name of the User
Definition: User.cs:41
DbSet< ChatBot > ChatBots
The ChatBots in the DatabaseContext.
ConfigurationRights
Rights for Models.ConfigurationFile
DbSet< DualReattachInformation > WatchdogReattachInformations
The DualReattachInformations in the DatabaseContext.
async Task< IActionResult > GetId(long id, CancellationToken cancellationToken)
Get a specific Api.Models.Instance.
ErrorCode
Types of ErrorMessages that the API may return.
Definition: ErrorCode.cs:10
ByondRights
Rights for Models.Byond
Definition: ByondRights.cs:9
RightsType
The type of rights a model uses
Definition: RightsType.cs:6
InstanceUserRights
Rights for an Models.Instance
InstanceManagerRights InstanceManagerRights
The Rights.InstanceManagerRights for the User
Definition: User.cs:53
readonly IInstanceManager instanceManager
The IInstanceManager for the InstanceController
async Task< IActionResult > List(CancellationToken cancellationToken)
List Api.Models.Instances.
ConfigurationType
The type of configuration allowed on an Instance
readonly GeneralConfiguration generalConfiguration
The GeneralConfiguration for the InstanceController.
ulong GetRight(RightsType rightsType)
Get the value of a given rightsType
Task Save(CancellationToken cancellationToken)
Saves changes made to the IDatabaseContext
ApiController for managing Components.Instances
readonly IIOManager ioManager
The IIOManager for the InstanceController
Backend abstract implementation of IDatabaseContext
readonly IJobManager jobManager
The IJobManager for the InstanceController
readonly IAssemblyInformationProvider assemblyInformationProvider
The IAssemblyInformationProvider for the InstanceController
async Task< IActionResult > Delete(long id, CancellationToken cancellationToken)
Detach an Api.Models.Instance with the given id .
Routes to a server actions
Definition: Routes.cs:9
DreamDaemonRights
Rights for Models.DreamDaemon
const string CurrentDirectory
Path to the current working directory for the IIOManager.
InstanceManagerRights
Rights for managing Models.Instances
DbSet< Instance > Instances
The Instances in the DatabaseContext.
async Task< IActionResult > Update([FromBody] Api.Models.Instance model, CancellationToken cancellationToken)
Modify an Api.Models.Instance&#39;s settings.
DbSet< ReattachInformation > ReattachInformations
The ReattachInformations in the DatabaseContext.
DreamMakerRights
Rights for Models.DreamMaker
DbSet< InstanceUser > InstanceUsers
The InstanceUsers in the DatabaseContext.
RepositoryRights
Rights for a Models.Repository
InstanceController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IJobManager jobManager, IInstanceManager instanceManager, IIOManager ioManager, IAssemblyInformationProvider assemblyInformationProvider, IPlatformIdentifier platformIdentifier, IOptions< GeneralConfiguration > generalConfigurationOptions, ILogger< InstanceController > logger)
Construct a InstanceController
const string InstanceManager
The Models.Instance controller
Definition: Routes.cs:29
readonly IPlatformIdentifier platformIdentifier
The IPlatformIdentifier for the InstanceController
long Id
The ID of the User
Definition: User.cs:16
Metadata about a server instance
Definition: Instance.cs:9
Manages the runtime of Jobs
Definition: IJobManager.cs:13
Instance Instance
The parent Models.Instance
IIOManager that resolves paths to Environment.CurrentDirectory
DreamDaemonSecurity
DreamDaemon&#39;s security level
const string List
The postfix for list operations
Definition: Routes.cs:84
Interface for using filesystems
Definition: IIOManager.cs:11
async Task< IActionResult > Create([FromBody] Api.Models.Instance model, CancellationToken cancellationToken)
Create or attach an Api.Models.Instance.
ChatBotRights
Rights for Models.ChatBot
Definition: ChatBotRights.cs:9
For identifying the current platform
Represents an error message returned by the server
Definition: ErrorMessage.cs:9
const ushort DefaultChatBotLimit
Default for Api.Models.Instance.ChatBotLimit.
Definition: Instance.cs:13