/// <inheritdoc />
        public IInstance CreateInstance(Models.Instance metadata)
        {
            //Create the ioManager for the instance
            var instanceIoManager = new ResolvingIOManager(ioManager, metadata.Path);

            //various other ioManagers
            var repoIoManager          = new ResolvingIOManager(instanceIoManager, "Repository");
            var byondIOManager         = new ResolvingIOManager(instanceIoManager, "Byond");
            var gameIoManager          = new ResolvingIOManager(instanceIoManager, "Game");
            var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration");

            var configuration = new StaticFiles.Configuration(configurationIoManager, synchronousIOManager, symlinkFactory, processExecutor, postWriteHandler, loggerFactory.CreateLogger <StaticFiles.Configuration>());
            var eventConsumer = new EventConsumer(configuration);

            var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager, loggerFactory.CreateLogger <DmbFactory>(), metadata.CloneMetadata());

            try
            {
                var repoManager = new RepositoryManager(metadata.RepositorySettings, repoIoManager, eventConsumer, credentialsProvider, loggerFactory.CreateLogger <Repository.Repository>(), loggerFactory.CreateLogger <RepositoryManager>());
                try
                {
                    var byond = new ByondManager(byondIOManager, byondInstaller, eventConsumer, loggerFactory.CreateLogger <ByondManager>());

                    var commandFactory = new CommandFactory(application, byond, repoManager, databaseContextFactory, metadata);

                    var chat = chatFactory.CreateChat(instanceIoManager, commandFactory, metadata.ChatSettings);
                    try
                    {
                        var sessionControllerFactory = new SessionControllerFactory(processExecutor, byond, byondTopicSender, cryptographySuite, application, gameIoManager, chat, networkPromptReaper, loggerFactory, metadata.CloneMetadata());
                        var reattachInfoHandler      = new ReattachInfoHandler(databaseContextFactory, dmbFactory, loggerFactory.CreateLogger <ReattachInfoHandler>(), metadata.CloneMetadata());
                        var watchdog = watchdogFactory.CreateWatchdog(chat, dmbFactory, reattachInfoHandler, configuration, sessionControllerFactory, metadata.CloneMetadata(), metadata.DreamDaemonSettings);
                        eventConsumer.SetWatchdog(watchdog);
                        commandFactory.SetWatchdog(watchdog);
                        try
                        {
                            var dreamMaker = new DreamMaker(byond, gameIoManager, configuration, sessionControllerFactory, dmbFactory, application, eventConsumer, chat, processExecutor, watchdog, loggerFactory.CreateLogger <DreamMaker>());

                            return(new Instance(metadata.CloneMetadata(), repoManager, byond, dreamMaker, watchdog, chat, configuration, dmbFactory, databaseContextFactory, dmbFactory, jobManager, eventConsumer, gitHubClientFactory, loggerFactory.CreateLogger <Instance>()));
                        }
                        catch
                        {
                            watchdog.Dispose();
                            throw;
                        }
                    }
                    catch
                    {
                        chat.Dispose();
                        throw;
                    }
                }
                catch
                {
                    repoManager.Dispose();
                    throw;
                }
            }
            catch
            {
                dmbFactory.Dispose();
                throw;
            }
        }
Ejemplo n.º 2
0
        /// <inheritdoc />
#pragma warning disable CA1506 // TODO: Decomplexify
        public async Task <IInstance> CreateInstance(IBridgeRegistrar bridgeRegistrar, Models.Instance metadata)
        {
            // Create the ioManager for the instance
            var instanceIoManager = new ResolvingIOManager(ioManager, metadata.Path);

            // various other ioManagers
            var repoIoManager          = new ResolvingIOManager(instanceIoManager, "Repository");
            var byondIOManager         = new ResolvingIOManager(instanceIoManager, "Byond");
            var gameIoManager          = new ResolvingIOManager(instanceIoManager, "Game");
            var diagnosticsIOManager   = new ResolvingIOManager(instanceIoManager, "Diagnostics");
            var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration");

            var configuration = new StaticFiles.Configuration(
                configurationIoManager,
                synchronousIOManager,
                symlinkFactory,
                processExecutor,
                postWriteHandler,
                platformIdentifier,
                fileTransferService,
                loggerFactory.CreateLogger <StaticFiles.Configuration>());
            var eventConsumer = new EventConsumer(configuration);
            var repoManager   = new RepositoryManager(
                repositoryFactory,
                repositoryCommands,
                repoIoManager,
                eventConsumer,
                gitRemoteFeaturesFactory,
                loggerFactory.CreateLogger <Repository.Repository>(),
                loggerFactory.CreateLogger <RepositoryManager>());

            try
            {
                var byond = new ByondManager(byondIOManager, byondInstaller, eventConsumer, loggerFactory.CreateLogger <ByondManager>());

                var commandFactory = new CommandFactory(assemblyInformationProvider, byond, repoManager, databaseContextFactory, metadata);

                var chatManager = chatFactory.CreateChatManager(instanceIoManager, commandFactory, metadata.ChatSettings);
                try
                {
                    var sessionControllerFactory = new SessionControllerFactory(
                        processExecutor,
                        byond,
                        topicClientFactory,
                        cryptographySuite,
                        assemblyInformationProvider,
                        gameIoManager,
                        chatManager,
                        networkPromptReaper,
                        platformIdentifier,
                        bridgeRegistrar,
                        serverPortProvider,
                        eventConsumer,
                        loggerFactory,
                        loggerFactory.CreateLogger <SessionControllerFactory>(),
                        metadata);

                    var dmbFactory = new DmbFactory(
                        databaseContextFactory,
                        gameIoManager,
                        remoteDeploymentManagerFactory,
                        loggerFactory.CreateLogger <DmbFactory>(),
                        metadata);
                    try
                    {
                        var reattachInfoHandler = new SessionPersistor(
                            databaseContextFactory,
                            dmbFactory,
                            processExecutor,
                            loggerFactory.CreateLogger <SessionPersistor>(),
                            metadata);
                        var watchdog = watchdogFactory.CreateWatchdog(
                            chatManager,
                            dmbFactory,
                            reattachInfoHandler,
                            sessionControllerFactory,
                            gameIoManager,
                            diagnosticsIOManager,
                            eventConsumer,
                            remoteDeploymentManagerFactory,
                            metadata,
                            metadata.DreamDaemonSettings);
                        eventConsumer.SetWatchdog(watchdog);
                        commandFactory.SetWatchdog(watchdog);
                        try
                        {
                            Instance instance   = null;
                            var      dreamMaker = new DreamMaker(
                                byond,
                                gameIoManager,
                                configuration,
                                sessionControllerFactory,
                                eventConsumer,
                                chatManager,
                                processExecutor,
                                dmbFactory,
                                repoManager,
                                remoteDeploymentManagerFactory,
                                loggerFactory.CreateLogger <DreamMaker>(),
                                metadata);

                            instance = new Instance(
                                metadata,
                                repoManager,
                                byond,
                                dreamMaker,
                                watchdog,
                                chatManager,
                                configuration,
                                dmbFactory,
                                jobManager,
                                eventConsumer,
                                remoteDeploymentManagerFactory,
                                loggerFactory.CreateLogger <Instance>());

                            return(instance);
                        }
                        catch
                        {
                            await watchdog.DisposeAsync().ConfigureAwait(false);

                            throw;
                        }
                    }
                    catch
                    {
                        dmbFactory.Dispose();
                        throw;
                    }
                }
                catch
                {
                    await chatManager.DisposeAsync().ConfigureAwait(false);

                    throw;
                }
            }
            catch
            {
                repoManager.Dispose();
                throw;
            }
        }
Ejemplo n.º 3
0
        /// <inheritdoc />
                #pragma warning disable CA1506 // TODO: Decomplexify
        public async Task <ISessionController> LaunchNew(DreamDaemonLaunchParameters launchParameters, IDmbProvider dmbProvider, IByondExecutableLock currentByondLock, bool primaryPort, bool primaryDirectory, bool apiValidate, CancellationToken cancellationToken)
        {
            var portToUse = primaryPort ? launchParameters.PrimaryPort : launchParameters.SecondaryPort;

            if (!portToUse.HasValue)
            {
                throw new InvalidOperationException("Given port is null!");
            }
            var accessIdentifier = cryptographySuite.GetSecureString();

            const string JsonPostfix = "tgs.json";

            var basePath = primaryDirectory ? dmbProvider.PrimaryDirectory : dmbProvider.SecondaryDirectory;

            // delete all previous tgs json files
            var files = await ioManager.GetFilesWithExtension(basePath, JsonPostfix, cancellationToken).ConfigureAwait(false);

            await Task.WhenAll(files.Select(x => ioManager.DeleteFile(x, cancellationToken))).ConfigureAwait(false);

            // i changed this back from guids, hopefully i don't regret that
            string JsonFile(string name) => String.Format(CultureInfo.InvariantCulture, "{0}.{1}", name, JsonPostfix);

            var securityLevelToUse = launchParameters.SecurityLevel.Value;

            switch (dmbProvider.CompileJob.MinimumSecurityLevel)
            {
            case DreamDaemonSecurity.Ultrasafe:
                break;

            case DreamDaemonSecurity.Safe:
                if (securityLevelToUse == DreamDaemonSecurity.Ultrasafe)
                {
                    securityLevelToUse = DreamDaemonSecurity.Safe;
                }
                break;

            case DreamDaemonSecurity.Trusted:
                securityLevelToUse = DreamDaemonSecurity.Trusted;
                break;

            default:
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid DreamDaemonSecurity value: {0}", dmbProvider.CompileJob.MinimumSecurityLevel));
            }

            // setup interop files
            var interopInfo = new JsonFile
            {
                AccessIdentifier   = accessIdentifier,
                ApiValidateOnly    = apiValidate,
                ChatChannelsJson   = JsonFile("chat_channels"),
                ChatCommandsJson   = JsonFile("chat_commands"),
                ServerCommandsJson = JsonFile("server_commands"),
                InstanceName       = instance.Name,
                SecurityLevel      = securityLevelToUse,
                Revision           = new Api.Models.Internal.RevisionInformation
                {
                    CommitSha       = dmbProvider.CompileJob.RevisionInformation.CommitSha,
                    OriginCommitSha = dmbProvider.CompileJob.RevisionInformation.OriginCommitSha
                }
            };

            interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).Select(x => new Interop.TestMerge(x, interopInfo.Revision)));

            var interopJsonFile = JsonFile("interop");

            var interopJson = JsonConvert.SerializeObject(interopInfo, new JsonSerializerSettings
            {
                ContractResolver      = new CamelCasePropertyNamesContractResolver(),
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            var localIoManager = new ResolvingIOManager(ioManager, basePath);

            var chatJsonTrackingTask = chat.TrackJsons(basePath, interopInfo.ChatChannelsJson, interopInfo.ChatCommandsJson, cancellationToken);

            await localIoManager.WriteAllBytes(interopJsonFile, Encoding.UTF8.GetBytes(interopJson), cancellationToken).ConfigureAwait(false);

            var chatJsonTrackingContext = await chatJsonTrackingTask.ConfigureAwait(false);

            try
            {
                // get the byond lock
                var byondLock = currentByondLock ?? await byond.UseExecutables(Version.Parse(dmbProvider.CompileJob.ByondVersion), cancellationToken).ConfigureAwait(false);

                try
                {
                    // create interop context
                    var context = new CommContext(ioManager, loggerFactory.CreateLogger <CommContext>(), basePath, interopInfo.ServerCommandsJson);
                    try
                    {
                        // set command line options
                        // more sanitization here cause it uses the same scheme
                        var parameters = String.Format(CultureInfo.InvariantCulture, "{2}={0}&{3}={1}", byondTopicSender.SanitizeString(application.Version.ToString()), byondTopicSender.SanitizeString(interopJsonFile), byondTopicSender.SanitizeString(Constants.DMParamHostVersion), byondTopicSender.SanitizeString(Constants.DMParamInfoJson));

                        // important to run on all ports to allow port changing
                        var arguments = String.Format(CultureInfo.InvariantCulture, "{0} -port {1} -ports 1-65535 {2}-close -{3} -verbose -public -params \"{4}\"",
                                                      dmbProvider.DmbName,
                                                      primaryPort ? launchParameters.PrimaryPort : launchParameters.SecondaryPort,
                                                      launchParameters.AllowWebClient.Value ? "-webclient " : String.Empty,
                                                      SecurityWord(securityLevelToUse),
                                                      parameters);

                        // See https://github.com/tgstation/tgstation-server/issues/719
                        var noShellExecute = !platformIdentifier.IsWindows;

                        // launch dd
                        var process = processExecutor.LaunchProcess(byondLock.DreamDaemonPath, basePath, arguments, noShellExecute: noShellExecute);
                        try
                        {
                            networkPromptReaper.RegisterProcess(process);

                            // return the session controller for it
                            var result = new SessionController(new ReattachInformation
                            {
                                AccessIdentifier = accessIdentifier,
                                Dmb                = dmbProvider,
                                IsPrimary          = primaryDirectory,
                                Port               = portToUse.Value,
                                ProcessId          = process.Id,
                                ChatChannelsJson   = interopInfo.ChatChannelsJson,
                                ChatCommandsJson   = interopInfo.ChatCommandsJson,
                                ServerCommandsJson = interopInfo.ServerCommandsJson,
                            }, process, byondLock, byondTopicSender, chatJsonTrackingContext, context, chat, loggerFactory.CreateLogger <SessionController>(), launchParameters.SecurityLevel, launchParameters.StartupTimeout);

                            // writeback launch parameter's fixed security level
                            launchParameters.SecurityLevel = securityLevelToUse;

                            return(result);
                        }
                        catch
                        {
                            process.Dispose();
                            throw;
                        }
                    }
                    catch
                    {
                        context.Dispose();
                        throw;
                    }
                }
                catch
                {
                    if (currentByondLock == null)
                    {
                        byondLock.Dispose();
                    }
                    throw;
                }
            }
            catch
            {
                chatJsonTrackingContext.Dispose();
                throw;
            }
        }