/// <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="bridgeRegistrar">The <see cref="IBridgeRegistrar"/> used to populate <see cref="bridgeRegistration"/>.</param>
        /// <param name="chat">The value of <see cref="chat"/></param>
        /// <param name="chatTrackingContext">The value of <see cref="chatTrackingContext"/></param>
        /// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="SessionController"/>.</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>
        /// <param name="reattached">If this is a reattached session.</param>
        public SessionController(
            ReattachInformation reattachInformation,
            IProcess process,
            IByondExecutableLock byondLock,
            ITopicClient byondTopicSender,
            IChatTrackingContext chatTrackingContext,
            IBridgeRegistrar bridgeRegistrar,
            IChatManager chat,
            IAssemblyInformationProvider assemblyInformationProvider,
            ILogger <SessionController> logger,
            uint?startupTimeout,
            bool reattached)
        {
            this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
            this.process             = process ?? throw new ArgumentNullException(nameof(process));
            this.byondLock           = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
            this.byondTopicSender    = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
            this.chatTrackingContext = chatTrackingContext ?? throw new ArgumentNullException(nameof(chatTrackingContext));
            bridgeRegistration       = bridgeRegistrar?.RegisterHandler(this) ?? throw new ArgumentNullException(nameof(bridgeRegistrar));
            this.chat   = chat ?? throw new ArgumentNullException(nameof(chat));
            this.logger = logger ?? throw new ArgumentNullException(nameof(logger));

            this.chatTrackingContext.SetChannelSink(this);

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

            rebootTcs           = new TaskCompletionSource <object>();
            primeTcs            = new TaskCompletionSource <object>();
            reattachTopicCts    = new CancellationTokenSource();
            synchronizationLock = new object();

            _ = process.Lifetime.ContinueWith(
                x =>
            {
                if (!disposed)
                {
                    reattachTopicCts.Cancel();
                }
                chatTrackingContext.Active = false;
            },
                TaskScheduler.Current);

            LaunchResult = GetLaunchResult(
                assemblyInformationProvider,
                startupTimeout,
                reattached);

            logger.LogDebug("Created session controller. Primary: {0}, CommsKey: {1}, Port: {2}", IsPrimary, reattachInformation.AccessIdentifier, Port);
        }
Beispiel #2
0
        /// <summary>
        /// Construct a <see cref="SessionController"/>
        /// </summary>
        /// <param name="reattachInformation">The value of <see cref="reattachInformation"/></param>
        /// <param name="metadata">The owning <see cref="Instance"/>.</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="bridgeRegistrar">The <see cref="IBridgeRegistrar"/> used to populate <see cref="bridgeRegistration"/>.</param>
        /// <param name="chat">The value of <see cref="chat"/></param>
        /// <param name="chatTrackingContext">The value of <see cref="chatTrackingContext"/></param>
        /// <param name="assemblyInformationProvider">The <see cref="IAssemblyInformationProvider"/> for the <see cref="SessionController"/>.</param>
        /// <param name="logger">The value of <see cref="logger"/></param>
        /// <param name="postLifetimeCallback">The <see cref="Func{TResult}"/> returning a <see cref="Task"/> to be run after the <paramref name="process"/> ends.</param>
        /// <param name="startupTimeout">The optional time to wait before failing the <see cref="LaunchResult"/></param>
        /// <param name="reattached">If this is a reattached session.</param>
        /// <param name="apiValidate">If this is a DMAPI validation session.</param>
        public SessionController(
            ReattachInformation reattachInformation,
            Api.Models.Instance metadata,
            IProcess process,
            IByondExecutableLock byondLock,
            ITopicClient byondTopicSender,
            IChatTrackingContext chatTrackingContext,
            IBridgeRegistrar bridgeRegistrar,
            IChatManager chat,
            IAssemblyInformationProvider assemblyInformationProvider,
            ILogger <SessionController> logger,
            Func <Task> postLifetimeCallback,
            uint?startupTimeout,
            bool reattached,
            bool apiValidate)
        {
            this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
            this.metadata            = metadata ?? throw new ArgumentNullException(nameof(metadata));
            this.process             = process ?? throw new ArgumentNullException(nameof(process));
            this.byondLock           = byondLock ?? throw new ArgumentNullException(nameof(byondLock));
            this.byondTopicSender    = byondTopicSender ?? throw new ArgumentNullException(nameof(byondTopicSender));
            this.chatTrackingContext = chatTrackingContext ?? throw new ArgumentNullException(nameof(chatTrackingContext));
            if (bridgeRegistrar == null)
            {
                throw new ArgumentNullException(nameof(bridgeRegistrar));
            }
            this.chat   = chat ?? throw new ArgumentNullException(nameof(chat));
            this.logger = logger ?? throw new ArgumentNullException(nameof(logger));

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

            rebootTcs = new TaskCompletionSource <object>();
            primeTcs  = new TaskCompletionSource <object>();
            initialBridgeRequestTcs = new TaskCompletionSource <object>();
            reattachTopicCts        = new CancellationTokenSource();
            synchronizationLock     = new object();

            if (apiValidate || DMApiAvailable)
            {
                bridgeRegistration = bridgeRegistrar.RegisterHandler(this);
                this.chatTrackingContext.SetChannelSink(this);
            }
            else
            {
                logger.LogTrace(
                    "Not registering session with {0} DMAPI version for interop!",
                    reattachInformation.Dmb.CompileJob.DMApiVersion == null
                                                ? "no"
                                                : $"incompatible ({reattachInformation.Dmb.CompileJob.DMApiVersion})");
            }

            async Task <int> WrapLifetime()
            {
                var exitCode = await process.Lifetime.ConfigureAwait(false);

                await postLifetimeCallback().ConfigureAwait(false);

                return(exitCode);
            }

            Lifetime = WrapLifetime();

            LaunchResult = GetLaunchResult(
                assemblyInformationProvider,
                startupTimeout,
                reattached,
                apiValidate);

            logger.LogDebug(
                "Created session controller. CommsKey: {0}, Port: {1}",
                reattachInformation.AccessIdentifier,
                reattachInformation.Port);
        }