Esempio n. 1
0
        /// <inheritdoc />
        protected override async Task InitControllers(
            Task chatTask,
            ReattachInformation reattachInfo,
            CancellationToken cancellationToken)
        {
            // don't need a new dmb if reattaching
            var reattachInProgress = reattachInfo != null;
            var dmbToUse           = reattachInProgress ? null : DmbFactory.LockNextDmb(1);

            // if this try catches something, both servers are killed
            try
            {
                // start the alpha server task, either by launch a new process or attaching to an existing one
                // The tasks returned are mainly for writing interop files to the directories among other things and should generally never fail
                // The tasks pertaining to server startup times are in the ISessionControllers
                Task <ISessionController> serverLaunchTask;
                if (!reattachInProgress)
                {
                    dmbToUse = await PrepServerForLaunch(dmbToUse, cancellationToken).ConfigureAwait(false);

                    serverLaunchTask = SessionControllerFactory.LaunchNew(
                        dmbToUse,
                        null,
                        ActiveLaunchParameters,
                        false,
                        cancellationToken);
                }
                else
                {
                    serverLaunchTask = SessionControllerFactory.Reattach(reattachInfo, cancellationToken);
                }

                // retrieve the session controller
                Server = await serverLaunchTask.ConfigureAwait(false);

                // failed reattaches will return null
                Server?.SetHighPriority();

                // possiblity of null servers due to failed reattaches
                if (Server == null)
                {
                    await ReattachFailure(
                        chatTask,
                        cancellationToken)
                    .ConfigureAwait(false);

                    return;
                }

                await CheckLaunchResult(Server, "Server", cancellationToken).ConfigureAwait(false);

                Server.EnableCustomChatCommands();
            }
            catch
            {
                // kill the controllers
                bool serverWasActive = Server != null;

                // DCT: Operation must always run
                await DisposeAndNullControllers(default).ConfigureAwait(false);
Esempio n. 2
0
        /// <inheritdoc />
        protected override async Task InitControllers(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken)
        {
            try
            {
                await base.InitControllers(chatTask, reattachInfo, cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                // Then we move it back and apply the symlink
                if (directoryHardLinked)
                {
                    Logger.LogTrace("Unhardlinking compile job...");
                    Server?.Suspend();
                    await GameIOManager.MoveDirectory(
                        ActiveSwappable.Directory,
                        ActiveSwappable.CompileJob.DirectoryName.ToString(),
                        default)
                    .ConfigureAwait(false);

                    directoryHardLinked = false;
                }
            }

            if (reattachInfo != null)
            {
                Logger.LogTrace("Skipping symlink due to reattach");
                return;
            }

            Logger.LogTrace("Symlinking compile job...");
            await ActiveSwappable.MakeActive(cancellationToken).ConfigureAwait(false);

            Server.Resume();
        }
Esempio n. 3
0
        /// <summary>
        /// Construct a <see cref="SessionController"/>
        /// </summary>
        /// <param name="reattachInformation">The value of <see cref="reattachInformation"/></param>
        /// <param name="process">The value of <see cref="process"/></param>
        /// <param name="byondLock">The value of <see cref="byondLock"/></param>
        /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param>
        /// <param name="interopContext">The value of <see cref="interopContext"/></param>
        /// <param name="chat">The value of <see cref="chat"/></param>
        /// <param name="chatJsonTrackingContext">The value of <see cref="chatJsonTrackingContext"/></param>
        /// <param name="logger">The value of <see cref="logger"/></param>
        /// <param name="launchSecurityLevel">The value of <see cref="launchSecurityLevel"/></param>
        /// <param name="startupTimeout">The optional time to wait before failing the <see cref="LaunchResult"/></param>
        public SessionController(
            ReattachInformation reattachInformation,
            IProcess process,
            IByondExecutableLock byondLock,
            IByondTopicSender byondTopicSender,
            IJsonTrackingContext chatJsonTrackingContext,
            ICommContext interopContext,
            IChat chat,
            ILogger <SessionController> logger,
            DreamDaemonSecurity?launchSecurityLevel,
            uint?startupTimeout)
        {
            this.chatJsonTrackingContext = chatJsonTrackingContext;             // null valid
            this.reattachInformation     = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
            this.byondTopicSender        = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
            this.process        = process ?? throw new ArgumentNullException(nameof(process));
            this.byondLock      = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
            this.interopContext = interopContext ?? throw new ArgumentNullException(nameof(interopContext));
            this.chat           = chat ?? throw new ArgumentNullException(nameof(chat));
            this.logger         = logger ?? throw new ArgumentNullException(nameof(logger));

            this.launchSecurityLevel = launchSecurityLevel;

            interopContext.RegisterHandler(this);

            portClosedForReboot = false;
            disposed            = false;
            apiValidationStatus = ApiValidationStatus.NeverValidated;
            released            = false;

            rebootTcs = new TaskCompletionSource <object>();

            process.Lifetime.ContinueWith(x => chatJsonTrackingContext.Active = false, TaskScheduler.Current);

            async Task <LaunchResult> GetLaunchResult()
            {
                var  startTime = DateTimeOffset.Now;
                Task toAwait   = process.Startup;

                if (startupTimeout.HasValue)
                {
                    toAwait = Task.WhenAny(process.Startup, Task.Delay(startTime.AddSeconds(startupTimeout.Value) - startTime));
                }

                await toAwait.ConfigureAwait(false);

                var result = new LaunchResult
                {
                    ExitCode    = process.Lifetime.IsCompleted ? (int?)await process.Lifetime.ConfigureAwait(false) : null,
                    StartupTime = process.Startup.IsCompleted ? (TimeSpan?)(DateTimeOffset.Now - startTime) : null
                };

                return(result);
            }

            LaunchResult = GetLaunchResult();

            logger.LogDebug("Created session controller. Primary: {0}, CommsKey: {1}, Port: {2}", IsPrimary, reattachInformation.AccessIdentifier, Port);
        }
Esempio n. 4
0
                #pragma warning restore CA1506

        /// <inheritdoc />
        public async Task <ISessionController> Reattach(ReattachInformation reattachInformation, CancellationToken cancellationToken)
        {
            if (reattachInformation == null)
            {
                throw new ArgumentNullException(nameof(reattachInformation));
            }

            SessionController result    = null;
            var basePath                = reattachInformation.IsPrimary ? reattachInformation.Dmb.PrimaryDirectory : reattachInformation.Dmb.SecondaryDirectory;
            var chatJsonTrackingContext = await chat.TrackJsons(basePath, reattachInformation.ChatChannelsJson, reattachInformation.ChatCommandsJson, cancellationToken).ConfigureAwait(false);

            try
            {
                var byondLock = await byond.UseExecutables(Version.Parse(reattachInformation.Dmb.CompileJob.ByondVersion), cancellationToken).ConfigureAwait(false);

                try
                {
                    var context = new CommContext(ioManager, loggerFactory.CreateLogger <CommContext>(), basePath, reattachInformation.ServerCommandsJson);
                    try
                    {
                        var process = processExecutor.GetProcess(reattachInformation.ProcessId);

                        if (process != null)
                        {
                            try
                            {
                                networkPromptReaper.RegisterProcess(process);
                                result = new SessionController(reattachInformation, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger <SessionController>(), null, null);

                                process   = null;
                                context   = null;
                                byondLock = null;
                                chatJsonTrackingContext = null;
                            }
                            finally
                            {
                                process?.Dispose();
                            }
                        }
                    }
                    finally
                    {
                        context?.Dispose();
                    }
                }
                finally
                {
                    byondLock?.Dispose();
                }
            }
            finally
            {
                chatJsonTrackingContext?.Dispose();
            }

            return(result);
        }
Esempio n. 5
0
 /// <summary>
 /// Construct a <see cref="WatchdogReattachInformation"/> from a given <paramref name="copy"/> with a given <paramref name="dmbAlpha"/> and <paramref name="dmbBravo"/>
 /// </summary>
 /// <param name="copy">The <see cref="WatchdogReattachInformationBase"/> to copy information from</param>
 /// <param name="dmbAlpha">The <see cref="IDmbProvider"/> used to build <see cref="Alpha"/></param>
 /// <param name="dmbBravo">The <see cref="IDmbProvider"/> used to build <see cref="Bravo"/></param>
 public WatchdogReattachInformation(Models.WatchdogReattachInformation copy, IDmbProvider dmbAlpha, IDmbProvider dmbBravo) : base(copy)
 {
     if (copy.Alpha != null)
     {
         Alpha = new ReattachInformation(copy.Alpha, dmbAlpha);
     }
     if (copy.Bravo != null)
     {
         Bravo = new ReattachInformation(copy.Bravo, dmbBravo);
     }
 }
Esempio n. 6
0
        /// <inheritdoc />
        protected override async Task InitControllers(Task chatTask, ReattachInformation reattachInfo, CancellationToken cancellationToken)
        {
            try
            {
                await base.InitControllers(chatTask, reattachInfo, cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                // Then we move it back and apply the symlink
                if (hardLinkedDmb != null)
                {
                    try
                    {
                        Logger.LogTrace("Unhardlinking compile job...");
                        Server?.Suspend();
                        var hardLink         = hardLinkedDmb.Directory;
                        var originalPosition = hardLinkedDmb.CompileJob.DirectoryName.ToString();
                        await GameIOManager.MoveDirectory(
                            hardLink,
                            originalPosition,
                            default)
                        .ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogError(
                            ex,
                            "Failed to un-hard link compile job #{0} ({1})",
                            hardLinkedDmb.CompileJob.Id,
                            hardLinkedDmb.CompileJob.DirectoryName);
                    }

                    hardLinkedDmb = null;
                }
            }

            if (reattachInfo != null)
            {
                Logger.LogTrace("Skipping symlink due to reattach");
                return;
            }

            Logger.LogTrace("Symlinking compile job...");
            await ActiveSwappable.MakeActive(cancellationToken).ConfigureAwait(false);

            Server.Resume();
        }
        /// <summary>
        /// Construct a <see cref="SessionController"/>
        /// </summary>
        /// <param name="reattachInformation">The value of <see cref="reattachInformation"/></param>
        /// <param name="process">The value of <see cref="process"/></param>
        /// <param name="byondLock">The value of <see cref="byondLock"/></param>
        /// <param name="byondTopicSender">The value of <see cref="byondTopicSender"/></param>
        /// <param name="interopContext">The value of <see cref="interopContext"/></param>
        /// <param name="chat">The value of <see cref="chat"/></param>
        /// <param name="chatJsonTrackingContext">The value of <see cref="chatJsonTrackingContext"/></param>
        /// <param name="logger">The value of <see cref="logger"/></param>
        /// <param name="startupTimeout">The optional time to wait before failing the <see cref="LaunchResult"/></param>
        public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, ICommContext interopContext, IChat chat, ILogger <SessionController> logger, uint?startupTimeout)
        {
            this.chatJsonTrackingContext = chatJsonTrackingContext;             //null valid
            this.reattachInformation     = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
            this.byondTopicSender        = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
            this.process        = process ?? throw new ArgumentNullException(nameof(process));
            this.byondLock      = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
            this.interopContext = interopContext ?? throw new ArgumentNullException(nameof(interopContext));
            this.chat           = chat ?? throw new ArgumentNullException(nameof(chat));
            this.logger         = logger ?? throw new ArgumentNullException(nameof(logger));

            interopContext.RegisterHandler(this);

            portClosedForReboot = false;
            disposed            = false;
            apiValidated        = false;
            released            = false;

            rebootTcs = new TaskCompletionSource <object>();

            async Task <LaunchResult> GetLaunchResult()
            {
                var  startTime = DateTimeOffset.Now;
                Task toAwait   = process.Startup;

                if (startupTimeout.HasValue)
                {
                    toAwait = Task.WhenAny(process.Startup, Task.Delay(startTime.AddSeconds(startupTimeout.Value) - startTime));
                }

                await toAwait.ConfigureAwait(false);

                var result = new LaunchResult
                {
                    ExitCode    = process.Lifetime.IsCompleted ? (int?)await process.Lifetime.ConfigureAwait(false) : null,
                    StartupTime = process.Startup.IsCompleted ? (TimeSpan?)(DateTimeOffset.Now - startTime) : null
                };

                return(result);
            };
            LaunchResult = GetLaunchResult();
        }