/// <summary> /// Initializes a new instance of the <see cref="BasicWatchdog"/> <see langword="class"/>. /// </summary> /// <param name="chat">The <see cref="IChatManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionControllerFactory">The <see cref="ISessionControllerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="dmbFactory">The <see cref="IDmbFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionPersistor">The <see cref="ISessionPersistor"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="jobManager">The <see cref="IJobManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="serverControl">The <see cref="IServerControl"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="diagnosticsIOManager">The <see cref="IIOManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="eventConsumer">The <see cref="IEventConsumer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="remoteDeploymentManagerFactory">The <see cref="IRemoteDeploymentManagerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="initialLaunchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="instance">The <see cref="Api.Models.Instance"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="autoStart">The autostart value for the <see cref="WatchdogBase"/>.</param> public BasicWatchdog( IChatManager chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, ISessionPersistor sessionPersistor, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, IIOManager diagnosticsIOManager, IEventConsumer eventConsumer, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, ILogger <BasicWatchdog> logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) : base( chat, sessionControllerFactory, dmbFactory, sessionPersistor, jobManager, serverControl, asyncDelayer, diagnosticsIOManager, eventConsumer, remoteDeploymentManagerFactory, logger, initialLaunchParameters, instance, autoStart) { }
/// <summary> /// Initializes a new instance of the <see cref="BasicWatchdog"/> <see langword="class"/>. /// </summary> /// <param name="chat">The <see cref="IChatManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionControllerFactory">The <see cref="ISessionControllerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="dmbFactory">The <see cref="IDmbFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="reattachInfoHandler">The <see cref="IReattachInfoHandler"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="databaseContextFactory">The <see cref="IDatabaseContextFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="jobManager">The <see cref="IJobManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="serverControl">The <see cref="IServerControl"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="initialLaunchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="instance">The <see cref="Api.Models.Instance"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="autoStart">The autostart value for the <see cref="WatchdogBase"/>.</param> public BasicWatchdog( IChatManager chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILogger <BasicWatchdog> logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) : base( chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, databaseContextFactory, jobManager, serverControl, asyncDelayer, logger, initialLaunchParameters, instance, autoStart) { }
/// <summary> /// Initializes a new instance of the <see cref="DreamMaker"/> class. /// </summary> /// <param name="byond">The value of <see cref="byond"/>.</param> /// <param name="ioManager">The value of <see cref="ioManager"/>.</param> /// <param name="configuration">The value of <see cref="configuration"/>.</param> /// <param name="sessionControllerFactory">The value of <see cref="sessionControllerFactory"/>.</param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/>.</param> /// <param name="chatManager">The value of <see cref="chatManager"/>.</param> /// <param name="processExecutor">The value of <see cref="processExecutor"/>.</param> /// <param name="compileJobConsumer">The value of <see cref="compileJobConsumer"/>.</param> /// <param name="repositoryManager">The value of <see cref="repositoryManager"/>.</param> /// <param name="remoteDeploymentManagerFactory">The value of <see cref="remoteDeploymentManagerFactory"/>.</param> /// <param name="logger">The value of <see cref="logger"/>.</param> /// <param name="metadata">The value of <see cref="metadata"/>.</param> public DreamMaker( IByondManager byond, IIOManager ioManager, StaticFiles.IConfiguration configuration, ISessionControllerFactory sessionControllerFactory, IEventConsumer eventConsumer, IChatManager chatManager, IProcessExecutor processExecutor, ICompileJobSink compileJobConsumer, IRepositoryManager repositoryManager, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, ILogger <DreamMaker> logger, Api.Models.Instance metadata) { this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.chatManager = chatManager ?? throw new ArgumentNullException(nameof(chatManager)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer)); this.repositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); deploymentLock = new object(); }
/// <inheritdoc /> protected override IWatchdog CreateNonExperimentalWatchdog( IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, IIOManager ioManager, Api.Models.Instance instance, DreamDaemonSettings settings) => new WindowsWatchdog( chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, DatabaseContextFactory, ByondTopicSender, eventConsumer, JobManager, ServerControl, AsyncDelayer, ioManager, symlinkFactory, LoggerFactory.CreateLogger <WindowsWatchdog>(), settings, instance, settings.AutoStart.Value);
/// <summary> /// Construct a <see cref="ReattachInfoHandler"/> /// </summary> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param> /// <param name="logger">The value of <see cref="logger"/></param> /// <param name="metadata">The value of <see cref="metadata"/></param> public ReattachInfoHandler(IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory, ILogger <ReattachInfoHandler> logger, Api.Models.Instance metadata) { this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); }
/// <summary> /// Construct a <see cref="SessionControllerFactory"/> /// </summary> /// <param name="processExecutor">The value of <see cref="processExecutor"/></param> /// <param name="byond">The value of <see cref="byond"/></param> /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param> /// <param name="cryptographySuite">The value of <see cref="cryptographySuite"/></param> /// <param name="application">The value of <see cref="application"/></param> /// <param name="instance">The value of <see cref="instance"/></param> /// <param name="ioManager">The value of <see cref="ioManager"/></param> /// <param name="chat">The value of <see cref="chat"/></param> /// <param name="networkPromptReaper">The value of <see cref="networkPromptReaper"/></param> /// <param name="platformIdentifier">The value of <see cref="platformIdentifier"/></param> /// <param name="loggerFactory">The value of <see cref="loggerFactory"/></param> public SessionControllerFactory( IProcessExecutor processExecutor, IByondManager byond, IByondTopicSender byondTopicSender, ICryptographySuite cryptographySuite, IApplication application, IIOManager ioManager, IChat chat, INetworkPromptReaper networkPromptReaper, IPlatformIdentifier platformIdentifier, ILoggerFactory loggerFactory, Api.Models.Instance instance) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.byond = byond ?? throw new ArgumentNullException(nameof(byond)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.cryptographySuite = cryptographySuite ?? throw new ArgumentNullException(nameof(cryptographySuite)); this.application = application ?? throw new ArgumentNullException(nameof(application)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.networkPromptReaper = networkPromptReaper ?? throw new ArgumentNullException(nameof(networkPromptReaper)); this.platformIdentifier = platformIdentifier ?? throw new ArgumentNullException(nameof(platformIdentifier)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); }
/// <summary> /// Construct a <see cref="IWatchdog"/> /// </summary> /// <param name="chat">The value of <see cref="chat"/></param> /// <param name="sessionControllerFactory">The value of <see cref="sessionControllerFactory"/></param> /// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param> /// <param name="serverUpdater">The <see cref="IServerControl"/> for the <see cref="Watchdog"/></param> /// <param name="logger">The value of <see cref="logger"/></param> /// <param name="reattachInfoHandler">The value of <see cref="reattachInfoHandler"/></param> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param> /// <param name="initialLaunchParameters">The initial value of <see cref="ActiveLaunchParameters"/></param> /// <param name="instance">The value of <see cref="instance"/></param> /// <param name="autoStart">The value of <see cref="autoStart"/></param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param> public Watchdog(IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IServerControl serverUpdater, ILogger <Watchdog> logger, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) { this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); this.autoStart = autoStart; if (serverUpdater == null) { throw new ArgumentNullException(nameof(serverUpdater)); } serverUpdater.RegisterForRestart(() => releaseServers = true); chat.RegisterCommandHandler(this); AlphaIsActive = true; ActiveLaunchParameters = initialLaunchParameters; releaseServers = false; semaphore = new SemaphoreSlim(1); activeParametersUpdated = new TaskCompletionSource <object>(); }
/// <summary> /// Construct an <see cref="Instance"/> /// </summary> /// <param name="metadata">The value of <see cref="metadata"/></param> /// <param name="repositoryManager">The value of <see cref="RepositoryManager"/></param> /// <param name="byondManager">The value of <see cref="ByondManager"/></param> /// <param name="dreamMaker">The value of <see cref="dreamMaker"/></param> /// <param name="watchdog">The value of <see cref="Watchdog"/></param> /// <param name="chat">The value of <see cref="Chat"/></param> /// <param name="configuration">The value of <see cref="Configuration"/></param> /// <param name="compileJobConsumer">The value of <see cref="compileJobConsumer"/></param> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param> /// <param name="jobManager">The value of <see cref="jobManager"/></param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param> /// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/></param> /// <param name="logger">The value of <see cref="logger"/></param> public Instance( Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByondManager byondManager, IDreamMaker dreamMaker, IWatchdog watchdog, IChat chat, StaticFiles.IConfiguration configuration, ICompileJobConsumer compileJobConsumer, IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory, IJobManager jobManager, IEventConsumer eventConsumer, IGitHubClientFactory gitHubClientFactory, ILogger <Instance> logger) { this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); ByondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); this.dreamMaker = dreamMaker ?? throw new ArgumentNullException(nameof(dreamMaker)); Watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); Chat = chat ?? throw new ArgumentNullException(nameof(chat)); Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); }
/// <inheritdoc /> public IWatchdog CreateWatchdog( IChat chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IEventConsumer eventConsumer, ISessionControllerFactory sessionControllerFactory, IIOManager ioManager, Api.Models.Instance instance, DreamDaemonSettings settings) { if (GeneralConfiguration.UseExperimentalWatchdog) { return(new ExperimentalWatchdog( chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, DatabaseContextFactory, ByondTopicSender, eventConsumer, JobManager, ServerControl, AsyncDelayer, LoggerFactory.CreateLogger <ExperimentalWatchdog>(), settings, instance, settings.AutoStart.Value)); } return(CreateNonExperimentalWatchdog(chat, dmbFactory, reattachInfoHandler, eventConsumer, sessionControllerFactory, ioManager, instance, settings)); }
/// <summary> /// Construct an <see cref="Instance"/> /// </summary> /// <param name="metadata">The value of <see cref="metadata"/></param> /// <param name="repositoryManager">The value of <see cref="RepositoryManager"/></param> /// <param name="byondManager">The value of <see cref="ByondManager"/></param> /// <param name="dreamMaker">The value of <see cref="DreamMaker"/></param> /// <param name="watchdog">The value of <see cref="Watchdog"/></param> /// <param name="chat">The value of <see cref="Chat"/></param> /// <param name="configuration">The value of <see cref="Configuration"/></param> /// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param> /// <param name="jobManager">The value of <see cref="jobManager"/></param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param> /// <param name="remoteDeploymentManagerFactory">The value of <see cref="remoteDeploymentManagerFactory"/>.</param> /// <param name="logger">The value of <see cref="logger"/></param> public Instance( Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByondManager byondManager, IDreamMaker dreamMaker, IWatchdog watchdog, IChatManager chat, StaticFiles.IConfiguration configuration, IDmbFactory dmbFactory, IJobManager jobManager, IEventConsumer eventConsumer, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, ILogger <Instance> logger) { this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager)); ByondManager = byondManager ?? throw new ArgumentNullException(nameof(byondManager)); DreamMaker = dreamMaker ?? throw new ArgumentNullException(nameof(dreamMaker)); Watchdog = watchdog ?? throw new ArgumentNullException(nameof(watchdog)); Chat = chat ?? throw new ArgumentNullException(nameof(chat)); Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.remoteDeploymentManagerFactory = remoteDeploymentManagerFactory ?? throw new ArgumentNullException(nameof(remoteDeploymentManagerFactory)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); timerLock = new object(); }
/// <summary> /// Initializes a new instance of the <see cref="GitHubRemoteDeploymentManager"/> <see langword="class"/>. /// </summary> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/>.</param> /// <param name="gitHubClientFactory">The value of <see cref="gitHubClientFactory"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param> /// <param name="metadata">The <see cref="Api.Models.Instance"/> for the <see cref="BaseRemoteDeploymentManager"/>.</param> public GitHubRemoteDeploymentManager( IDatabaseContextFactory databaseContextFactory, IGitHubClientFactory gitHubClientFactory, ILogger <GitHubRemoteDeploymentManager> logger, Api.Models.Instance metadata) : base(logger, metadata) { this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); }
/// <inheritdoc /> public virtual IWatchdog CreateWatchdog( IChatManager chat, IDmbFactory dmbFactory, ISessionPersistor sessionPersistor, ISessionControllerFactory sessionControllerFactory, IIOManager gameIOManager, IIOManager diagnosticsIOManager, IEventConsumer eventConsumer, Api.Models.Instance instance, DreamDaemonSettings settings) => new BasicWatchdog(
/// <summary> /// Construct a <see cref="DmbFactory"/> /// </summary> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="ioManager">The value of <see cref="ioManager"/></param> /// <param name="logger">The value of <see cref="logger"/></param> /// <param name="instance">The value of <see cref="instance"/></param> public DmbFactory(IDatabaseContextFactory databaseContextFactory, IIOManager ioManager, ILogger <DmbFactory> logger, Api.Models.Instance instance) { this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); cleanupTask = Task.CompletedTask; newerDmbTcs = new TaskCompletionSource <object>(); cleanupCts = new CancellationTokenSource(); jobLockCounts = new Dictionary <long, int>(); }
/// <inheritdoc /> public override IWatchdog CreateWatchdog( IChatManager chat, IDmbFactory dmbFactory, ISessionPersistor sessionPersistor, ISessionControllerFactory sessionControllerFactory, IIOManager gameIOManager, IIOManager diagnosticsIOManager, IEventConsumer eventConsumer, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, Api.Models.Instance instance, DreamDaemonSettings settings) => new WindowsWatchdog(
/// <summary> /// Construct a <see cref="WatchdogFactory"/> /// </summary> /// <param name="chat">The value of <see cref="chat"/></param> /// <param name="sessionControllerFactory">The value of <see cref="sessionControllerFactory"/></param> /// <param name="serverUpdater">The value of <see cref="serverUpdater"/></param> /// <param name="loggerFactory">The value of <see cref="loggerFactory"/></param> /// <param name="reattachInfoHandler">The value of <see cref="reattachInfoHandler"/></param> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param> /// <param name="instance">The value of <see cref="instance"/></param> public WatchdogFactory(IChat chat, ISessionControllerFactory sessionControllerFactory, IServerControl serverUpdater, ILoggerFactory loggerFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, Api.Models.Instance instance) { this.chat = chat ?? throw new ArgumentNullException(nameof(chat)); this.sessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); }
/// <summary> /// Initializes a new instance of the <see cref="WatchdogBase"/> <see langword="class"/>. /// </summary> /// <param name="chat">The value of <see cref="Chat"/></param> /// <param name="sessionControllerFactory">The value of <see cref="SessionControllerFactory"/></param> /// <param name="dmbFactory">The value of <see cref="DmbFactory"/></param> /// <param name="reattachInfoHandler">The value of <see cref="reattachInfoHandler"/></param> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param> /// <param name="eventConsumer">The value of <see cref="eventConsumer"/></param> /// <param name="jobManager">The value of <see cref="jobManager"/></param> /// <param name="serverControl">The <see cref="IServerControl"/> to populate <see cref="restartRegistration"/> with</param> /// <param name="asyncDelayer">The value of <see cref="AsyncDelayer"/>.</param> /// <param name="logger">The value of <see cref="Logger"/></param> /// <param name="initialLaunchParameters">The initial value of <see cref="ActiveLaunchParameters"/>. May be modified</param> /// <param name="instance">The value of <see cref="instance"/></param> /// <param name="autoStart">The value of <see cref="autoStart"/></param> protected WatchdogBase( IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, ILogger logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) { Chat = chat ?? throw new ArgumentNullException(nameof(chat)); SessionControllerFactory = sessionControllerFactory ?? throw new ArgumentNullException(nameof(sessionControllerFactory)); DmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); AsyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.reattachInfoHandler = reattachInfoHandler ?? throw new ArgumentNullException(nameof(reattachInfoHandler)); this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.byondTopicSender = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender)); this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); ActiveLaunchParameters = initialLaunchParameters ?? throw new ArgumentNullException(nameof(initialLaunchParameters)); this.instance = instance ?? throw new ArgumentNullException(nameof(instance)); this.autoStart = autoStart; if (serverControl == null) { throw new ArgumentNullException(nameof(serverControl)); } chat.RegisterCommandHandler(this); ActiveLaunchParameters = initialLaunchParameters; releaseServers = false; ActiveParametersUpdated = new TaskCompletionSource <object>(); restartRegistration = serverControl.RegisterForRestart(this); try { Semaphore = new SemaphoreSlim(1); } catch { restartRegistration.Dispose(); throw; } }
/// <summary> /// Construct a <see cref="SessionPersistor"/> /// </summary> /// <param name="databaseContextFactory">The value of <see cref="databaseContextFactory"/></param> /// <param name="dmbFactory">The value of <see cref="dmbFactory"/></param> /// <param name="processExecutor">The value of <see cref="processExecutor"/></param> /// <param name="logger">The value of <see cref="logger"/></param> /// <param name="metadata">The value of <see cref="metadata"/></param> public SessionPersistor( IDatabaseContextFactory databaseContextFactory, IDmbFactory dmbFactory, IProcessExecutor processExecutor, ILogger <SessionPersistor> logger, Api.Models.Instance metadata) { this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory)); this.dmbFactory = dmbFactory ?? throw new ArgumentNullException(nameof(dmbFactory)); this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); }
/// <summary> /// Get the most recent <see cref="CompileJob"/> for a given <paramref name="instance"/> from a given <paramref name="databaseContext"/>. /// </summary> /// <param name="databaseContext">The <see cref="IDatabaseContext"/>.</param> /// <param name="instance">The <see cref="Instance"/> to search for <see cref="CompileJob"/>s.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param> /// <returns>A <see cref="Task{TResult}"/> resulting in the most recent <see cref="CompileJob"/> associated with the given <paramref name="instance"/> from the <paramref name="databaseContext"/>.</returns> public static Task <CompileJob> MostRecentCompletedCompileJobOrDefault( this IDatabaseContext databaseContext, Api.Models.Instance instance, CancellationToken cancellationToken) { if (databaseContext == null) { throw new ArgumentNullException(nameof(databaseContext)); } return(databaseContext .CompileJobs .AsQueryable() .Where(x => x.Job.Instance.Id == instance.Id) .OrderByDescending(x => x.Job.StoppedAt) .FirstOrDefaultAsync(cancellationToken)); }
/// <inheritdoc /> public IInstanceReference GetInstanceReference(Api.Models.Instance metadata) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } lock (instances) { if (!instances.TryGetValue(metadata.Id.Value, out var instance)) { logger.LogTrace("Cannot reference instance {0} as it is not online or on this node!", metadata.Id); return(null); } return(instance.AddReference()); } }
void NormalizeModelPath(Api.Models.Instance model, out string absolutePath) { if (model.Path == null) { absolutePath = null; return; } absolutePath = ioManager.ResolvePath(model.Path); if (platformIdentifier.IsWindows) { model.Path = absolutePath.ToUpperInvariant(); } else { model.Path = absolutePath; } }
/// <summary> /// Initializes a new instance of the <see cref="WindowsWatchdog"/> class. /// </summary> /// <param name="chat">The <see cref="IChatManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionControllerFactory">The <see cref="ISessionControllerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="dmbFactory">The <see cref="IDmbFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionPersistor">The <see cref="ISessionPersistor"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="jobManager">The <see cref="IJobManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="serverControl">The <see cref="IServerControl"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="diagnosticsIOManager">The <see cref="IIOManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="eventConsumer">The <see cref="IEventConsumer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="remoteDeploymentManagerFactory">The <see cref="IRemoteDeploymentManagerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="gameIOManager">The value of <see cref="GameIOManager"/>.</param> /// <param name="symlinkFactory">The value of <see cref="symlinkFactory"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="initialLaunchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="instance">The <see cref="Api.Models.Instance"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="autoStart">The autostart value for the <see cref="WatchdogBase"/>.</param> public WindowsWatchdog( IChatManager chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, ISessionPersistor sessionPersistor, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, IIOManager diagnosticsIOManager, IEventConsumer eventConsumer, IRemoteDeploymentManagerFactory remoteDeploymentManagerFactory, IIOManager gameIOManager, ISymlinkFactory symlinkFactory, ILogger <WindowsWatchdog> logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) : base( chat, sessionControllerFactory, dmbFactory, sessionPersistor, jobManager, serverControl, asyncDelayer, diagnosticsIOManager, eventConsumer, remoteDeploymentManagerFactory, logger, initialLaunchParameters, instance, autoStart) { try { GameIOManager = gameIOManager ?? throw new ArgumentNullException(nameof(gameIOManager)); this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory)); } catch { _ = DisposeAsync(); throw; } }
/// <summary> /// Initializes a new instance of the <see cref="RuntimeInformation"/> <see langword="class"/>. /// </summary> /// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> to use.</param> /// <param name="serverPortProvider">The <see cref="IServerPortProvider"/> used to set the value of <see cref="ServerPort"/>.</param> /// <param name="testMerges">An <see cref="IEnumerable{T}"/> used to construct the value of <see cref="TestMerges"/>.</param> /// <param name="chatChannels">The <see cref="Chat.ChannelRepresentation"/>s for the <see cref="ChatUpdate"/>.</param> /// <param name="instance">The <see cref="Instance"/> used to set <see cref="InstanceName"/>.</param> /// <param name="revision">The value of <see cref="RevisionInformation"/>.</param> /// <param name="securityLevel">The value of <see cref="SecurityLevel"/>.</param> /// <param name="apiValidateOnly">The value of <see cref="ApiValidateOnly"/>.</param> public RuntimeInformation( IAssemblyInformationProvider assemblyInformationProvider, IServerPortProvider serverPortProvider, IEnumerable <TestMergeInformation> testMerges, IEnumerable <Chat.ChannelRepresentation> chatChannels, Api.Models.Instance instance, Api.Models.Internal.RevisionInformation revision, DreamDaemonSecurity?securityLevel, bool apiValidateOnly) : base(chatChannels) { ServerVersion = assemblyInformationProvider?.Version ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); ServerPort = serverPortProvider?.HttpApiPort ?? throw new ArgumentNullException(nameof(serverPortProvider)); TestMerges = testMerges?.ToList() ?? throw new ArgumentNullException(nameof(testMerges)); InstanceName = instance?.Name ?? throw new ArgumentNullException(nameof(instance)); Revision = revision ?? throw new ArgumentNullException(nameof(revision)); SecurityLevel = securityLevel; ApiValidateOnly = apiValidateOnly; }
/// <summary> /// Initializes a new instance of the <see cref="WindowsWatchdog"/> <see langword="class"/>. /// </summary> /// <param name="chat">The <see cref="IChat"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="sessionControllerFactory">The <see cref="ISessionControllerFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="dmbFactory">The <see cref="IDmbFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="reattachInfoHandler">The <see cref="IReattachInfoHandler"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="databaseContextFactory">The <see cref="IDatabaseContextFactory"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="byondTopicSender">The <see cref="IByondTopicSender"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="eventConsumer">The <see cref="IEventConsumer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="jobManager">The <see cref="IJobManager"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="serverControl">The <see cref="IServerControl"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="asyncDelayer">The <see cref="IAsyncDelayer"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="ioManager">The value of <see cref="ioManager"/>.</param> /// <param name="symlinkFactory">The value of <see cref="symlinkFactory"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="initialLaunchParameters">The <see cref="DreamDaemonLaunchParameters"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="instance">The <see cref="Api.Models.Instance"/> for the <see cref="WatchdogBase"/>.</param> /// <param name="autoStart">The autostart value for the <see cref="WatchdogBase"/>.</param> public WindowsWatchdog( IChat chat, ISessionControllerFactory sessionControllerFactory, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, IDatabaseContextFactory databaseContextFactory, IByondTopicSender byondTopicSender, IEventConsumer eventConsumer, IJobManager jobManager, IServerControl serverControl, IAsyncDelayer asyncDelayer, IIOManager ioManager, ISymlinkFactory symlinkFactory, ILogger <WindowsWatchdog> logger, DreamDaemonLaunchParameters initialLaunchParameters, Api.Models.Instance instance, bool autoStart) : base( chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, databaseContextFactory, byondTopicSender, eventConsumer, jobManager, serverControl, asyncDelayer, logger, initialLaunchParameters, instance, autoStart) { try { this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); this.symlinkFactory = symlinkFactory ?? throw new ArgumentNullException(nameof(symlinkFactory)); } catch { Dispose(); throw; } }
Models.Instance CreateDefaultInstance(Api.Models.Instance initialSettings) => new Models.Instance { ConfigurationType = initialSettings.ConfigurationType ?? ConfigurationType.Disallowed, DreamDaemonSettings = new DreamDaemonSettings { AllowWebClient = false, AutoStart = false, Port = 1337, SecurityLevel = DreamDaemonSecurity.Safe, StartupTimeout = 60, HeartbeatSeconds = 60, TopicRequestTimeout = generalConfiguration.ByondTopicTimeout }, DreamMakerSettings = new DreamMakerSettings { ApiValidationPort = 1339, ApiValidationSecurityLevel = DreamDaemonSecurity.Safe, RequireDMApiValidation = true }, Name = initialSettings.Name, Online = false, Path = initialSettings.Path, AutoUpdateInterval = initialSettings.AutoUpdateInterval ?? 0, ChatBotLimit = initialSettings.ChatBotLimit ?? Models.Instance.DefaultChatBotLimit, RepositorySettings = new RepositorySettings { CommitterEmail = Components.Repository.Repository.DefaultCommitterEmail, CommitterName = Components.Repository.Repository.DefaultCommitterName, PushTestMergeCommits = false, ShowTestMergeCommitters = false, AutoUpdatesKeepTestMerges = false, AutoUpdatesSynchronize = false, PostTestMergeComment = false, CreateGitHubDeployments = false }, InstanceUsers = new List <Models.InstanceUser> // give this user full privileges on the instance { InstanceAdminUser(null) } };
/// <summary> /// Create a <see cref="IWatchdog"/> that isn't the <see cref="ExperimentalWatchdog"/>. /// </summary> /// <param name="chat">The <see cref="IChatManager"/> for the <see cref="IWatchdog"/></param> /// <param name="dmbFactory">The <see cref="IDmbFactory"/> for the <see cref="IWatchdog"/> with</param> /// <param name="reattachInfoHandler">The <see cref="IReattachInfoHandler"/> for the <see cref="IWatchdog"/></param> /// <param name="sessionControllerFactory">The <see cref="ISessionControllerFactory"/> for the <see cref="IWatchdog"/></param> /// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="IWatchdog"/>.</param> /// <param name="instance">The <see cref="Instance"/> for the <see cref="IWatchdog"/></param> /// <param name="settings">The initial <see cref="DreamDaemonSettings"/> for the <see cref="IWatchdog"/></param> /// <returns>A new <see cref="IWatchdog"/></returns> protected virtual IWatchdog CreateNonExperimentalWatchdog( IChatManager chat, IDmbFactory dmbFactory, IReattachInfoHandler reattachInfoHandler, ISessionControllerFactory sessionControllerFactory, IIOManager ioManager, Api.Models.Instance instance, DreamDaemonSettings settings) => new BasicWatchdog( chat, sessionControllerFactory, dmbFactory, reattachInfoHandler, DatabaseContextFactory, JobManager, ServerControl, AsyncDelayer, LoggerFactory.CreateLogger <BasicWatchdog>(), settings, instance, settings.AutoStart.Value);
/// <inheritdoc /> public IRemoteDeploymentManager CreateRemoteDeploymentManager(Api.Models.Instance metadata, RemoteGitProvider remoteGitProvider) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } logger.LogTrace("Creating remote deployment manager for remote git provider {0}...", remoteGitProvider); return(remoteGitProvider switch { RemoteGitProvider.GitHub => new GitHubRemoteDeploymentManager( databaseContextFactory, gitHubClientFactory, loggerFactory.CreateLogger <GitHubRemoteDeploymentManager>(), metadata), RemoteGitProvider.GitLab => new GitLabRemoteDeploymentManager( loggerFactory.CreateLogger <GitLabRemoteDeploymentManager>(), metadata), RemoteGitProvider.Unknown => new NoOpRemoteDeploymentManager(), _ => throw new InvalidOperationException($"Invalid RemoteGitProvider: {remoteGitProvider}!"), });
/// <summary> /// Corrects discrepencies between the <see cref="Api.Models.Instance.Online"/> status of <see cref="IInstance"/>s in the database vs the service. /// </summary> /// <param name="instanceManager">The <see cref="IInstanceManager"/> to use.</param> /// <param name="logger">The <see cref="ILogger"/> to use.</param> /// <param name="metadata">The <see cref="Api.Models.Instance"/> to check.</param> /// <returns><see langword="true"/> if an unsaved DB update was made, <see langword="false"/> otherwise.</returns> public static bool ValidateInstanceOnlineStatus(IInstanceManager instanceManager, ILogger logger, Api.Models.Instance metadata) { if (instanceManager == null) { throw new ArgumentNullException(nameof(instanceManager)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } bool online; using (var instanceReferenceCheck = instanceManager.GetInstanceReference(metadata)) online = instanceReferenceCheck != null; if (metadata.Online.Value == online) { return(false); } const string OfflineWord = "offline"; const string OnlineWord = "online"; logger.LogWarning( "Instance {0} is says it's {1} in the database, but it is actually {2} in the service. Updating the database to reflect this...", metadata.Id, online ? OfflineWord : OnlineWord, online ? OnlineWord : OfflineWord); metadata.Online = online; return(true); }
public async Task RunPostTest(CancellationToken cancellationToken) { var instances = await instanceManagerClient.List(cancellationToken); var firstTest = instances.Single(x => x.Name == TestInstanceName); var instanceClient = instanceManagerClient.CreateClient(firstTest); //can regain permissions on instance without instance user var ourInstanceUser = await instanceClient.Users.Read(cancellationToken).ConfigureAwait(false); await instanceClient.Users.Delete(ourInstanceUser, cancellationToken).ConfigureAwait(false); await Assert.ThrowsExceptionAsync <InsufficientPermissionsException>(() => instanceClient.Users.Read(cancellationToken)).ConfigureAwait(false); await instanceManagerClient.GrantPermissions(new Api.Models.Instance { Id = firstTest.Id }, cancellationToken).ConfigureAwait(false); ourInstanceUser = await instanceClient.Users.Read(cancellationToken).ConfigureAwait(false); Assert.AreEqual(RightsHelper.AllRights <DreamDaemonRights>(), ourInstanceUser.DreamDaemonRights.Value); //can't detach online instance await ApiAssert.ThrowsException <ConflictException>(() => instanceManagerClient.Detach(firstTest, cancellationToken), ErrorCode.InstanceDetachOnline).ConfigureAwait(false); firstTest.Online = false; firstTest = await instanceManagerClient.Update(firstTest, cancellationToken).ConfigureAwait(false); await instanceManagerClient.Detach(firstTest, cancellationToken).ConfigureAwait(false); var attachPath = Path.Combine(firstTest.Path, InstanceController.InstanceAttachFileName); Assert.IsTrue(File.Exists(attachPath)); //can recreate detached instance firstTest = await instanceManagerClient.CreateOrAttach(firstTest, cancellationToken).ConfigureAwait(false); // Test updating only with SetChatBotLimit works var current = await usersClient.Read(cancellationToken); var update = new UserUpdate { Id = current.Id, InstanceManagerRights = InstanceManagerRights.SetChatBotLimit }; await usersClient.Update(update, cancellationToken); var update2 = new Api.Models.Instance { Id = firstTest.Id, ChatBotLimit = 77 }; var newThing = await instanceManagerClient.Update(update2, cancellationToken); update.InstanceManagerRights |= InstanceManagerRights.Delete | InstanceManagerRights.Create | InstanceManagerRights.List; await usersClient.Update(update, cancellationToken); //but only if the attach file exists await instanceManagerClient.Detach(firstTest, cancellationToken).ConfigureAwait(false); File.Delete(attachPath); await ApiAssert.ThrowsException <ConflictException>(() => instanceManagerClient.CreateOrAttach(firstTest, cancellationToken), ErrorCode.InstanceAtExistingPath).ConfigureAwait(false); }
public async Task <IActionResult> Create([FromBody] Api.Models.Instance model, CancellationToken cancellationToken) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (String.IsNullOrWhiteSpace(model.Name)) { return(BadRequest(new ErrorMessage(ErrorCode.InstanceWhitespaceName))); } var unNormalizedPath = model.Path; var targetInstancePath = NormalizePath(unNormalizedPath); model.Path = targetInstancePath; var installationDirectoryPath = NormalizePath(DefaultIOManager.CurrentDirectory); bool InstanceIsChildOf(string otherPath) { if (!targetInstancePath.StartsWith(otherPath, StringComparison.Ordinal)) { return(false); } bool sameLength = targetInstancePath.Length == otherPath.Length; char dirSeparatorChar = targetInstancePath.ToCharArray()[Math.Min(otherPath.Length, targetInstancePath.Length - 1)]; return(sameLength || dirSeparatorChar == Path.DirectorySeparatorChar || dirSeparatorChar == Path.AltDirectorySeparatorChar); } if (InstanceIsChildOf(installationDirectoryPath)) { return(Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath))); } // Validate it's not a child of any other instance IActionResult earlyOut = null; ulong countOfOtherInstances = 0; using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { var newCancellationToken = cts.Token; try { await DatabaseContext .Instances .AsQueryable() .Select(x => new Models.Instance { Path = x.Path }) .ForEachAsync( otherInstance => { if (++countOfOtherInstances >= generalConfiguration.InstanceLimit) { earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceLimitReached)); } else if (InstanceIsChildOf(otherInstance.Path)) { earlyOut ??= Conflict(new ErrorMessage(ErrorCode.InstanceAtConflictingPath)); } if (earlyOut != null && !newCancellationToken.IsCancellationRequested) { cts.Cancel(); } }, newCancellationToken) .ConfigureAwait(false); } catch (OperationCanceledException) { cancellationToken.ThrowIfCancellationRequested(); } } if (earlyOut != null) { return(earlyOut); } // Last test, ensure it's in the list of valid paths if (!(generalConfiguration.ValidInstancePaths? .Select(path => NormalizePath(path)) .Any(path => InstanceIsChildOf(path)) ?? true)) { return(BadRequest(new ErrorMessage(ErrorCode.InstanceNotAtWhitelistedPath))); } async Task <bool> DirExistsAndIsNotEmpty() { if (!await ioManager.DirectoryExists(model.Path, cancellationToken).ConfigureAwait(false)) { return(false); } var filesTask = ioManager.GetFiles(model.Path, cancellationToken); var dirsTask = ioManager.GetDirectories(model.Path, cancellationToken); var files = await filesTask.ConfigureAwait(false); var dirs = await dirsTask.ConfigureAwait(false); return(files.Concat(dirs).Any()); } var dirExistsTask = DirExistsAndIsNotEmpty(); bool attached = false; if (await ioManager.FileExists(model.Path, cancellationToken).ConfigureAwait(false) || await dirExistsTask.ConfigureAwait(false)) { if (!await ioManager.FileExists(ioManager.ConcatPath(model.Path, InstanceAttachFileName), cancellationToken).ConfigureAwait(false)) { return(Conflict(new ErrorMessage(ErrorCode.InstanceAtExistingPath))); } else { attached = true; } } var newInstance = CreateDefaultInstance(model); DatabaseContext.Instances.Add(newInstance); try { await DatabaseContext.Save(cancellationToken).ConfigureAwait(false); try { // actually reserve it now await ioManager.CreateDirectory(unNormalizedPath, cancellationToken).ConfigureAwait(false); await ioManager.DeleteFile(ioManager.ConcatPath(targetInstancePath, InstanceAttachFileName), cancellationToken).ConfigureAwait(false); } catch { // oh shit delete the model DatabaseContext.Instances.Remove(newInstance); // DCT: Operation must always run await DatabaseContext.Save(default).ConfigureAwait(false);
public ByondTest(IByondClient byondClient, IJobsClient jobsClient, Api.Models.Instance metadata) : base(jobsClient) { this.byondClient = byondClient ?? throw new ArgumentNullException(nameof(byondClient)); this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata)); }