/// <inheritdoc />
        public async Task <ServerSideModifications> CopyDMFilesTo(string dmeFile, string destination, CancellationToken cancellationToken)
        {
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                await EnsureDirectories(cancellationToken).ConfigureAwait(false);

                //just assume no other fs race conditions here
                var dmeExistsTask      = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, dmeFile), cancellationToken);
                var headFileExistsTask = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, CodeModificationsHeadFile), cancellationToken);
                var tailFileExistsTask = ioManager.FileExists(ioManager.ConcatPath(CodeModificationsSubdirectory, CodeModificationsTailFile), cancellationToken);
                var copyTask           = ioManager.CopyDirectory(CodeModificationsSubdirectory, destination, null, cancellationToken);

                await Task.WhenAll(dmeExistsTask, headFileExistsTask, tailFileExistsTask, copyTask).ConfigureAwait(false);

                if (!dmeExistsTask.Result && !headFileExistsTask.Result && !tailFileExistsTask.Result)
                {
                    return(null);
                }

                if (dmeExistsTask.Result)
                {
                    return(new ServerSideModifications(null, null, true));
                }

                if (!headFileExistsTask.Result && !tailFileExistsTask.Result)
                {
                    return(null);
                }

                string IncludeLine(string filePath) => String.Format(CultureInfo.InvariantCulture, "#include \"{0}\"", filePath);

                return(new ServerSideModifications(headFileExistsTask.Result ? IncludeLine(CodeModificationsHeadFile) : null, tailFileExistsTask.Result ? IncludeLine(CodeModificationsTailFile) : null, false));
            }
        }
        /// <inheritdoc />
        public async Task <bool> HandleEvent(EventType eventType, IEnumerable <string> parameters, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            if (!EventTypeScriptFileNameMap.TryGetValue(eventType, out var scriptName))
            {
                return(true);
            }

            //always execute in serial
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                var files = await ioManager.GetFilesWithExtension(EventScriptsSubdirectory, SystemScriptFileExtension, cancellationToken).ConfigureAwait(false);

                var resolvedScriptsDir = ioManager.ResolvePath(EventScriptsSubdirectory);

                foreach (var I in files.Select(x => ioManager.GetFileName(x)).Where(x => x.StartsWith(scriptName, StringComparison.Ordinal)))
                {
                    using (var script = processExecutor.LaunchProcess(ioManager.ConcatPath(resolvedScriptsDir, I), resolvedScriptsDir, String.Join(' ', parameters), noShellExecute: true))
                        using (cancellationToken.Register(() => script.Terminate()))
                        {
                            var exitCode = await script.Lifetime.ConfigureAwait(false);

                            cancellationToken.ThrowIfCancellationRequested();
                            if (exitCode != 0)
                            {
                                return(false);
                            }
                        }
                }
            }
            return(true);
        }
Esempio n. 3
0
        /// <inheritdoc />
        public async Task <string> HandleChatCommand(string commandName, string arguments, Chat.User sender, CancellationToken cancellationToken)
        {
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (!Running)
                {
                    return("ERROR: Server offline!");
                }

                var commandObject = new ChatCommand
                {
                    Command    = commandName,
                    Parameters = arguments,
                    User       = sender
                };

                var json = JsonConvert.SerializeObject(commandObject, new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                });

                var command = String.Format(CultureInfo.InvariantCulture, "{0}&{1}={2}", byondTopicSender.SanitizeString(Constants.DMTopicChatCommand), byondTopicSender.SanitizeString(Constants.DMParameterData), byondTopicSender.SanitizeString(json));

                var activeServer = AlphaIsActive ? alphaServer : bravoServer;
                return(await activeServer.SendCommand(command, cancellationToken).ConfigureAwait(false) ?? "ERROR: Bad topic exchange!");
            }
        }
Esempio n. 4
0
        /// <inheritdoc />
        public async Task <WatchdogLaunchResult> Restart(bool graceful, CancellationToken cancellationToken)
        {
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (!graceful || !Running)
                {
                    Task chatTask;
                    if (Running)
                    {
                        chatTask = chat.SendWatchdogMessage("Manual restart triggered...", cancellationToken);
                        await TerminateNoLock(false, false, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        chatTask = Task.CompletedTask;
                    }
                    var result = await LaunchNoLock(true, !Running, false, cancellationToken).ConfigureAwait(false);

                    await chatTask.ConfigureAwait(false);

                    return(result);
                }
                var toReboot = AlphaIsActive ? alphaServer : bravoServer;
                var other    = AlphaIsActive ? bravoServer : alphaServer;
                if (toReboot != null)
                {
                    if (!await toReboot.SetRebootState(Components.Watchdog.RebootState.Restart, cancellationToken).ConfigureAwait(false))
                    {
                        logger.LogWarning("Unable to send reboot state change event!");
                    }
                }
                return(null);
            }
        }
Esempio n. 5
0
        /// <inheritdoc />
        public async Task ChangeVersion(Version version, Stream customVersionStream, CancellationToken cancellationToken)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }

            var versionKey = await InstallVersion(version, customVersionStream, cancellationToken).ConfigureAwait(false);

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(versionKey), cancellationToken).ConfigureAwait(false);

                await eventConsumer.HandleEvent(
                    EventType.ByondActiveVersionChange,
                    new List <string>
                {
                    ActiveVersion != null
                                                        ? VersionKey(ActiveVersion, true)
                                                        : null,
                    versionKey
                },
                    cancellationToken)
                .ConfigureAwait(false);

                // We reparse the version key because it could be changed after a custom install.
                ActiveVersion = Version.Parse(versionKey);
            }
        }
Esempio n. 6
0
        /// <inheritdoc />
        public async Task TrustDmbPath(string fullDmbPath, CancellationToken cancellationToken)
        {
            if (fullDmbPath == null)
            {
                throw new ArgumentNullException(nameof(fullDmbPath));
            }

            using (await SemaphoreSlimContext.Lock(trustedFileSemaphore, cancellationToken).ConfigureAwait(false))
            {
                string trustedFileText;

                if (await ioManager.FileExists(trustedFilePath, cancellationToken).ConfigureAwait(false))
                {
                    var trustedFileBytes = await ioManager.ReadAllBytes(trustedFilePath, cancellationToken).ConfigureAwait(false);

                    trustedFileText = Encoding.UTF8.GetString(trustedFileBytes);
                    trustedFileText = $"{trustedFileText.Trim()}{Environment.NewLine}";
                }
                else
                {
                    trustedFileText = String.Empty;
                }

                if (trustedFileText.Contains(fullDmbPath, StringComparison.Ordinal))
                {
                    return;
                }

                trustedFileText = $"{trustedFileText}{fullDmbPath}{Environment.NewLine}";

                var newTrustedFileBytes = Encoding.UTF8.GetBytes(trustedFileText);
                await ioManager.WriteAllBytes(trustedFilePath, newTrustedFileBytes, cancellationToken).ConfigureAwait(false);
            }
        }
Esempio n. 7
0
 /// <inheritdoc />
 public async Task <bool> ApplyUpdate(byte[] updateZipData, IIOManager ioManager, CancellationToken cancellationToken)
 {
     if (updatePath == null)
     {
         return(false);
     }
     using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
     {
         if (updated)
         {
             throw new InvalidOperationException("ApplyUpdate has already been called!");
         }
         updated = true;
         try
         {
             await ioManager.ZipToDirectory(updatePath, updateZipData, cancellationToken).ConfigureAwait(false);
         }
         catch
         {
             try
             {
                 //important to not leave this directory around if possible
                 await ioManager.DeleteDirectory(updatePath, default).ConfigureAwait(false);
             }
             catch { }
             updated = false;
             throw;
         }
         Restart();
         return(true);
     }
 }
Esempio n. 8
0
        /// <inheritdoc />
        public async Task Restart(bool graceful, CancellationToken cancellationToken)
        {
            Logger.LogTrace("Begin Restart. Graceful: {0}", graceful);
            using (await SemaphoreSlimContext.Lock(Semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (!graceful || !Running)
                {
                    Task chatTask;
                    if (Running)
                    {
                        chatTask = Chat.SendWatchdogMessage("Manual restart triggered...", cancellationToken);
                        await TerminateNoLock(false, false, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        chatTask = Task.CompletedTask;
                    }
                    await LaunchImplNoLock(true, !Running, null, cancellationToken).ConfigureAwait(false);

                    await chatTask.ConfigureAwait(false);
                }

                var toReboot = GetActiveController();
                if (toReboot != null)
                {
                    if (!await toReboot.SetRebootState(Watchdog.RebootState.Restart, cancellationToken).ConfigureAwait(false))
                    {
                        Logger.LogWarning("Unable to send reboot state change event!");
                    }
                }
            }
        }
Esempio n. 9
0
 /// <inheritdoc />
 public async Task SetChannels(IEnumerable <Channel> channels, CancellationToken cancellationToken)
 {
     using (await SemaphoreSlimContext.Lock(channelsSemaphore, cancellationToken).ConfigureAwait(false))
         await ioManager.WriteAllBytes(channelsPath, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(channels, Formatting.Indented, new JsonSerializerSettings
         {
             ContractResolver = new CamelCasePropertyNamesContractResolver()
         })), cancellationToken).ConfigureAwait(false);
 }
        /// <inheritdoc />
        public async Task Initialize(CancellationToken cancellationToken)
        {
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (modulesAndEnabledStatus != null)
                {
                    return;
                }

                modulesAndEnabledStatus = new Dictionary <IModule, bool>();

                var tasks = new List <Task <IModule> >();

                async Task <KeyValuePair <IModule, bool> > InitPlugin(IModule plugin)
                {
                    var type = plugin.GetType();

                    logger.LogTrace("Plugin {0}.Name: {1}", type, plugin.Name);
                    logger.LogTrace("Plugin {0}.Description: {1}", type, plugin.Description);
                    logger.LogTrace("Plugin {0}.Uid: {1}", type, plugin.Uid);

                    var query  = databaseContext.ModuleMetadatas.Where(x => x.Id == plugin.Uid);
                    var result = await query.ToAsyncEnumerable().FirstOrDefault().ConfigureAwait(false);

                    bool enabled;

                    if (result == default(ModuleMetadata))
                    {
                        enabled = true;
                        await databaseContext.ModuleMetadatas.AddAsync(new ModuleMetadata { Id = plugin.Uid, Enabled = true }).ConfigureAwait(false);
                    }
                    else
                    {
                        enabled = result.Enabled;
                    }

                    logger.LogTrace("Plugin {0}.Enabled: {1}", type, enabled);

                    return(new KeyValuePair <IModule, bool>(plugin, enabled));
                };

                using (logger.BeginScope("Loading plugins..."))
                {
                    var tasks2 = new List <Task <KeyValuePair <IModule, bool> > >();
                    tasks2.AddRange(allModules.Select(x => InitPlugin(x)));
                    await Task.WhenAll(tasks2).ConfigureAwait(false);

                    await databaseContext.Save(cancellationToken).ConfigureAwait(false);

                    foreach (var I in tasks2.Select(x => x.Result))
                    {
                        modulesAndEnabledStatus.Add(I);
                        I.Key.SetEnabled(I.Value);
                    }
                }
            }
        }
Esempio n. 11
0
 /// <inheritdoc />
 public async Task DeleteRepository(CancellationToken cancellationToken)
 {
     logger.LogInformation("Deleting repository...");
     using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
     {
         logger.LogTrace("Semaphore acquired, deleting Repository directory...");
         await ioManager.DeleteDirectory(ioManager.ResolvePath(), cancellationToken).ConfigureAwait(false);
     }
 }
Esempio n. 12
0
        /// <inheritdoc />
        public async Task ChangeVersion(Version version, CancellationToken cancellationToken)
        {
            await InstallVersion(version, cancellationToken).ConfigureAwait(false);

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(version.ToString()), cancellationToken).ConfigureAwait(false);

                ActiveVersion = version;
            }
        }
Esempio n. 13
0
        /// <inheritdoc />
        public async Task <bool> HandleEvent(EventType eventType, IEnumerable <string> parameters, CancellationToken cancellationToken)
        {
            if (!Running)
            {
                return(true);
            }

            string results;

            using (await SemaphoreSlimContext.Lock(Semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (!Running)
                {
                    return(true);
                }

                var builder = new StringBuilder(Constants.DMTopicEvent);
                builder.Append('&');
                var notification = new EventNotification
                {
                    Type       = eventType,
                    Parameters = parameters
                };
                var json = JsonConvert.SerializeObject(notification);
                builder.Append(byondTopicSender.SanitizeString(Constants.DMParameterData));
                builder.Append('=');
                builder.Append(byondTopicSender.SanitizeString(json));

                var activeServer = GetActiveController();
                results = await activeServer.SendCommand(builder.ToString(), cancellationToken).ConfigureAwait(false);
            }

            if (results == Constants.DMResponseSuccess)
            {
                return(true);
            }

            List <Response> responses;

            try
            {
                responses = JsonConvert.DeserializeObject <List <Response> >(results);
            }
            catch
            {
                Logger.LogInformation("Recieved invalid response from DD when parsing event {0}:{1}{2}", eventType, Environment.NewLine, results);
                return(true);
            }

            await Task.WhenAll(responses.Select(x => Chat.SendMessage(x.Message, x.ChannelIds, cancellationToken))).ConfigureAwait(false);

            return(true);
        }
Esempio n. 14
0
 /// <inheritdoc />
 public async Task ChangeSettings(DreamDaemonLaunchParameters launchParameters, CancellationToken cancellationToken)
 {
     using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
     {
         ActiveLaunchParameters = launchParameters;
         if (Running)
         {
             //queue an update
             activeParametersUpdated.TrySetResult(null);
         }
     }
 }
Esempio n. 15
0
        /// <inheritdoc />
        public override async Task InstallByond(string path, Version version, CancellationToken cancellationToken)
        {
            async Task SetNoPromptTrusted()
            {
                var configPath = IOManager.ConcatPath(path, ByondConfigDir);
                await IOManager.CreateDirectory(configPath, cancellationToken).ConfigureAwait(false);

                await IOManager.WriteAllBytes(IOManager.ConcatPath(configPath, ByondDDConfig), Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken).ConfigureAwait(false);
            }

            var setNoPromptTrustedModeTask = SetNoPromptTrusted();

            // after this version lummox made DD depend of directx lol
            // but then he became amazing and not only fixed it but also gave us 30s compiles \[T]/
            // then he readded it again so -_-
            if (!installedDirectX)
            {
                using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                    if (!installedDirectX)
                    {
                        // ^check again because race conditions
                        // always install it, it's pretty fast and will do better redundancy checking than us
                        var rbdx = IOManager.ConcatPath(path, ByondDXDir);

                        // noShellExecute because we aren't doing runas shennanigans
                        IProcess directXInstaller;
                        try
                        {
                            directXInstaller = processExecutor.LaunchProcess(IOManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", noShellExecute: true);
                        }
                        catch (Exception e)
                        {
                            throw new JobException("Unable to start DirectX installer process! Is the server running with admin privileges?", e);
                        }

                        using (directXInstaller)
                        {
                            int exitCode;
                            using (cancellationToken.Register(() => directXInstaller.Terminate()))
                                exitCode = await directXInstaller.Lifetime.ConfigureAwait(false);
                            cancellationToken.ThrowIfCancellationRequested();

                            if (exitCode != 0)
                            {
                                throw new JobException(String.Format(CultureInfo.InvariantCulture, "Failed to install included DirectX! Exit code: {0}", exitCode));
                            }
                            installedDirectX = true;
                        }
                    }
            }

            await setNoPromptTrustedModeTask.ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task <IReadOnlyList <ConfigurationFile> > ListDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            var path = ValidateConfigRelativePath(configurationRelativePath);

            if (configurationRelativePath == null)
            {
                configurationRelativePath = "/";
            }

            List <ConfigurationFile> result = new List <ConfigurationFile>();

            void ListImpl()
            {
                var enumerator = synchronousIOManager.GetDirectories(path, cancellationToken);

                try
                {
                    result.AddRange(enumerator.Select(x => new ConfigurationFile
                    {
                        IsDirectory = true,
                        Path        = ioManager.ConcatPath(configurationRelativePath, x),
                    }).OrderBy(file => file.Path));
                }
                catch (IOException e)
                {
                    logger.LogDebug("IOException while writing {0}: {1}", path, e);
                    result = null;
                    return;
                }

                enumerator = synchronousIOManager.GetFiles(path, cancellationToken);
                result.AddRange(enumerator.Select(x => new ConfigurationFile
                {
                    IsDirectory = false,
                    Path        = ioManager.ConcatPath(configurationRelativePath, x),
                }).OrderBy(file => file.Path));
            }

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                if (systemIdentity == null)
                {
                    ListImpl();
                }
                else
                {
                    await systemIdentity.RunImpersonated(ListImpl, cancellationToken).ConfigureAwait(false);
                }

            return(result);
        }
Esempio n. 17
0
 /// <summary>
 /// Sets <see cref="knownUser"/> if it is <see langword="null"/>
 /// </summary>
 /// <returns>A <see cref="Task"/> representing the running operation</returns>
 async Task CheckUser(bool doLock, CancellationToken cancellationToken)
 {
     if (!doLock)
     {
         if (knownUser == null)
         {
             knownUser = await gitHubClient.User.Current().ConfigureAwait(false);
         }
         return;
     }
     using (SemaphoreSlimContext.Lock(semaphore, cancellationToken))
         await CheckUser(false, cancellationToken).ConfigureAwait(false);
 }
Esempio n. 18
0
        /// <inheritdoc />
        public async Task <bool> ApplyUpdate(Version version, byte[] updateZipData, IIOManager ioManager, CancellationToken cancellationToken)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }
            if (updateZipData == null)
            {
                throw new ArgumentNullException(nameof(updateZipData));
            }
            if (ioManager == null)
            {
                throw new ArgumentNullException(nameof(ioManager));
            }

            if (updatePath == null)
            {
                return(false);
            }
            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                if (updated)
                {
                    throw new InvalidOperationException("ApplyUpdate has already been called!");
                }
                updated = true;
                try
                {
                    await ioManager.ZipToDirectory(updatePath, updateZipData, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    updated = false;
                    try
                    {
                        //important to not leave this directory around if possible
                        await ioManager.DeleteDirectory(updatePath, default).ConfigureAwait(false);
                    }
                    catch (Exception e2)
                    {
                        throw new AggregateException(e, e2);
                    }
                    throw;
                }
                await Restart(version).ConfigureAwait(false);

                return(true);
            }
        }
Esempio n. 19
0
 /// <inheritdoc />
 public async Task ResetRebootState(CancellationToken cancellationToken)
 {
     using (await SemaphoreSlimContext.Lock(Semaphore, cancellationToken).ConfigureAwait(false))
     {
         if (!Running)
         {
             return;
         }
         var toClear = GetActiveController();
         if (toClear != null)
         {
             toClear.ResetRebootState();
         }
     }
 }
Esempio n. 20
0
        /// <inheritdoc />
        public async Task <User> GetUserLogin(string accessToken, CancellationToken cancellationToken)
        {
            logger.LogTrace("GetUserLogin. accessToken: {0}", accessToken);

            if (accessToken == null)
            {
                using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                {
                    await CheckUser(false, cancellationToken).ConfigureAwait(false);

                    return(knownUser);
                }
            }

            return(await gitHubClientFactory.CreateGitHubClient(accessToken).User.Current().ConfigureAwait(false));
        }
        /// <inheritdoc />
        public async Task SymlinkStaticFilesTo(string destination, CancellationToken cancellationToken)
        {
            async Task SymlinkBase(bool files)
            {
                Task <IReadOnlyList <string> > task;

                if (files)
                {
                    task = ioManager.GetFiles(GameStaticFilesSubdirectory, cancellationToken);
                }
                else
                {
                    task = ioManager.GetDirectories(GameStaticFilesSubdirectory, cancellationToken);
                }
                var entries = await task.ConfigureAwait(false);

                await Task.WhenAll(task.Result.Select(async x =>
                {
                    var destPath = ioManager.ConcatPath(destination, ioManager.GetFileName(x));
                    logger.LogTrace("Symlinking {0} to {1}...", x, destPath);
                    var fileExistsTask = ioManager.FileExists(destPath, cancellationToken);
                    if (await ioManager.DirectoryExists(destPath, cancellationToken).ConfigureAwait(false))
                    {
                        await ioManager.DeleteDirectory(destPath, cancellationToken).ConfigureAwait(false);
                    }
                    var fileExists = await fileExistsTask.ConfigureAwait(false);
                    if (fileExists)
                    {
                        await ioManager.DeleteFile(destPath, cancellationToken).ConfigureAwait(false);
                    }
                    await symlinkFactory.CreateSymbolicLink(ioManager.ResolvePath(x), ioManager.ResolvePath(destPath), cancellationToken).ConfigureAwait(false);
                })).ConfigureAwait(false);
            }

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                await EnsureDirectories(cancellationToken).ConfigureAwait(false);

                await Task.WhenAll(SymlinkBase(true), SymlinkBase(false)).ConfigureAwait(false);
            }
        }
Esempio n. 22
0
        /// <inheritdoc />
        public async Task ChangeVersion(Version version, CancellationToken cancellationToken)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }
            var versionKey = VersionKey(version);

            await InstallVersion(version, cancellationToken).ConfigureAwait(false);

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                await ioManager.WriteAllBytes(ActiveVersionFileName, Encoding.UTF8.GetBytes(versionKey), cancellationToken).ConfigureAwait(false);

                await eventConsumer.HandleEvent(EventType.ByondActiveVersionChange, new List <string> {
                    ActiveVersion != null ? VersionKey(ActiveVersion) : null, versionKey
                }, cancellationToken).ConfigureAwait(false);

                ActiveVersion = version;
            }
        }
        /// <summary>
        /// Attempt to install the DirectX redistributable included with BYOND.
        /// </summary>
        /// <param name="path">The path to the BYOND installation.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
        /// <returns>A <see cref="Task"/> representing the running operation.</returns>
        async Task InstallDirectX(string path, CancellationToken cancellationToken)
        {
            using var lockContext = await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false);

            if (installedDirectX)
            {
                Logger.LogTrace("DirectX already installed.");
                return;
            }

            Logger.LogTrace("Installing DirectX redistributable...");

            // always install it, it's pretty fast and will do better redundancy checking than us
            var rbdx = IOManager.ConcatPath(path, ByondDXDir);

            try
            {
                // noShellExecute because we aren't doing runas shennanigans
                using var directXInstaller = processExecutor.LaunchProcess(
                          IOManager.ConcatPath(rbdx, "DXSETUP.exe"),
                          rbdx,
                          "/silent",
                          noShellExecute: true);

                int exitCode;
                using (cancellationToken.Register(() => directXInstaller.Terminate()))
                    exitCode = await directXInstaller.Lifetime.ConfigureAwait(false);
                cancellationToken.ThrowIfCancellationRequested();

                if (exitCode != 0)
                {
                    throw new JobException(ErrorCode.ByondDirectXInstallFail, new JobException($"Invalid exit code: {exitCode}"));
                }
                installedDirectX = true;
            }
            catch (Exception e)
            {
                throw new JobException(ErrorCode.ByondDirectXInstallFail, e);
            }
        }
        /// <inheritdoc />
        public async Task InstallByond(string path, Version version, CancellationToken cancellationToken)
        {
            async Task SetNoPromptTrusted()
            {
                var configPath = ioManager.ConcatPath(path, ByondConfigDir);
                await ioManager.CreateDirectory(configPath, cancellationToken).ConfigureAwait(false);

                await ioManager.WriteAllBytes(ioManager.ConcatPath(configPath, ByondDDConfig), Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken).ConfigureAwait(false);
            };

            var setNoPromptTrustedModeTask = SetNoPromptTrusted();

            //after this version lummox made DD depend of directx lol
            if (version.Major >= 512 && version.Minor >= 1427 && !installedDirectX)
            {
                using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                    if (!installedDirectX)
                    {
                        //always install it, it's pretty fast and will do better redundancy checking than us
                        var rbdx = ioManager.ConcatPath(path, ByondDXDir);
                        //noShellExecute because we aren't doing runas shennanigans
                        using (var p = processExecutor.LaunchProcess(ioManager.ConcatPath(rbdx, "DXSETUP.exe"), rbdx, "/silent", noShellExecute: true))
                        {
                            int exitCode;
                            using (cancellationToken.Register(() => p.Terminate()))
                                exitCode = await p.Lifetime.ConfigureAwait(false);
                            cancellationToken.ThrowIfCancellationRequested();

                            if (exitCode != 0)
                            {
                                throw new JobException(String.Format(CultureInfo.InvariantCulture, "Failed to install included DirectX! Exit code: {0}", exitCode));
                            }
                            installedDirectX = true;
                        }
                    }
            }

            await setNoPromptTrustedModeTask.ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task <bool> CreateDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            var path = ValidateConfigRelativePath(configurationRelativePath);

            bool?result = null;

            void DoCreate() => result = synchronousIOManager.CreateDirectory(path, cancellationToken);

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                if (systemIdentity == null)
                {
                    await Task.Factory.StartNew(DoCreate, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false);
                }
                else
                {
                    await systemIdentity.RunImpersonated(DoCreate, cancellationToken).ConfigureAwait(false);
                }

            return(result.Value);
        }
        /// <inheritdoc />
        public async Task <bool> DeleteDirectory(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            var path = ValidateConfigRelativePath(configurationRelativePath);

            var result = false;

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
            {
                void CheckDeleteImpl() => result = synchronousIOManager.DeleteDirectory(path);

                if (systemIdentity != null)
                {
                    await systemIdentity.RunImpersonated(CheckDeleteImpl, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    CheckDeleteImpl();
                }
            }
            return(result);
        }
Esempio n. 27
0
        /// <inheritdoc />
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            var reattachInfo = await reattachInfoHandler.Load(cancellationToken).ConfigureAwait(false);

            if (!autoStart && reattachInfo == null)
            {
                return;
            }

            long?adminUserId = null;

            await databaseContextFactory.UseContext(async db => adminUserId = await db.Users
                                                    .Where(x => x.CanonicalName == Api.Models.User.AdminName.ToUpperInvariant())
                                                    .Select(x => x.Id)
                                                    .FirstAsync(cancellationToken).ConfigureAwait(false)).ConfigureAwait(false);

            var job = new Models.Job
            {
                StartedBy = new Models.User
                {
                    Id = adminUserId.Value
                },
                Instance = new Models.Instance
                {
                    Id = instance.Id
                },
                Description      = "Instance startup watchdog launch",
                CancelRight      = (ulong)DreamDaemonRights.Shutdown,
                CancelRightsType = RightsType.DreamDaemon
            };
            await jobManager.RegisterOperation(job, async (j, databaseContext, progressFunction, ct) =>
            {
                using (await SemaphoreSlimContext.Lock(Semaphore, ct).ConfigureAwait(false))
                    await LaunchImplNoLock(true, true, reattachInfo, ct).ConfigureAwait(false);
            }, cancellationToken).ConfigureAwait(false);
        }
        /// <inheritdoc />
        public async Task <ConfigurationFile> Write(string configurationRelativePath, ISystemIdentity systemIdentity, byte[] data, string previousHash, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            var path = ValidateConfigRelativePath(configurationRelativePath);

            ConfigurationFile result = null;

            void WriteImpl()
            {
                lock (this)
                    try
                    {
                        var fileHash = previousHash;
                        var success  = synchronousIOManager.WriteFileChecked(path, data, ref fileHash, cancellationToken);
                        if (!success)
                        {
                            return;
                        }
                        result = new ConfigurationFile
                        {
                            Content      = data,
                            IsDirectory  = false,
                            LastReadHash = fileHash,
                            AccessDenied = false,
                            Path         = configurationRelativePath
                        };
                    }
                    catch (UnauthorizedAccessException)
                    {
                        //this happens on windows, dunno about linux
                        bool isDirectory;
                        try
                        {
                            isDirectory = synchronousIOManager.IsDirectory(path);
                        }
                        catch
                        {
                            isDirectory = false;
                        }

                        result = new ConfigurationFile
                        {
                            Path = configurationRelativePath
                        };
                        if (!isDirectory)
                        {
                            result.AccessDenied = true;
                        }
                        else
                        {
                            result.IsDirectory = true;
                        }
                    }
            }

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                if (systemIdentity == null)
                {
                    await Task.Factory.StartNew(WriteImpl, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false);
                }
                else
                {
                    await systemIdentity.RunImpersonated(WriteImpl, cancellationToken).ConfigureAwait(false);
                }

            return(result);
        }
 /// <inheritdoc />
 public async Task <IRepository> CloneRepository(Uri url, string initialBranch, string username, string password, Action <int> progressReporter, CancellationToken cancellationToken)
 {
     lock (this)
     {
         if (CloneInProgress)
         {
             throw new InvalidOperationException("The repository is already being cloned!");
         }
         CloneInProgress = true;
     }
     try
     {
         using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
             if (!await ioManager.DirectoryExists(".", cancellationToken).ConfigureAwait(false))
             {
                 try
                 {
                     await Task.Factory.StartNew(() =>
                     {
                         string path = null;
                         try
                         {
                             path = LibGit2Sharp.Repository.Clone(url.ToString(), ioManager.ResolvePath("."), new CloneOptions
                             {
                                 OnProgress         = (a) => !cancellationToken.IsCancellationRequested,
                                 OnTransferProgress = (a) =>
                                 {
                                     var percentage = 100 * (((float)a.IndexedObjects + a.ReceivedObjects) / (a.TotalObjects * 2));
                                     progressReporter((int)percentage);
                                     return(!cancellationToken.IsCancellationRequested);
                                 },
                                 RecurseSubmodules           = true,
                                 OnUpdateTips                = (a, b, c) => !cancellationToken.IsCancellationRequested,
                                 RepositoryOperationStarting = (a) => !cancellationToken.IsCancellationRequested,
                                 BranchName          = initialBranch,
                                 CredentialsProvider = (a, b, c) => username != null ? (Credentials) new UsernamePasswordCredentials
                                 {
                                     Username = username,
                                     Password = password
                                 } : new DefaultCredentials()
                             });
                         }
                         catch (UserCancelledException) { }
                         cancellationToken.ThrowIfCancellationRequested();
                     }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false);
                 }
                 catch
                 {
                     try
                     {
                         await ioManager.DeleteDirectory(".", default).ConfigureAwait(false);
                     }
                     catch { }
                     throw;
                 }
             }
             else
             {
                 return(null);
             }
     }
     finally
     {
         CloneInProgress = false;
     }
     return(await LoadRepository(cancellationToken).ConfigureAwait(false));
 }
        /// <inheritdoc />
        public async Task <ConfigurationFile> Read(string configurationRelativePath, ISystemIdentity systemIdentity, CancellationToken cancellationToken)
        {
            await EnsureDirectories(cancellationToken).ConfigureAwait(false);

            var path = ValidateConfigRelativePath(configurationRelativePath);

            ConfigurationFile result = null;

            void ReadImpl()
            {
                lock (this)
                    try
                    {
                        var    content = synchronousIOManager.ReadFile(path);
                        string sha1String;
#pragma warning disable CA5350                                                                                       // Do not use insecure cryptographic algorithm SHA1.
                        using (var sha1 = new SHA1Managed())
                                                                                      #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1.
                            sha1String = String.Join("", sha1.ComputeHash(content).Select(b => b.ToString("x2", CultureInfo.InvariantCulture)));
                        result = new ConfigurationFile
                        {
                            Content      = content,
                            IsDirectory  = false,
                            LastReadHash = sha1String,
                            AccessDenied = false,
                            Path         = configurationRelativePath
                        };
                    }
                    catch (UnauthorizedAccessException)
                    {
                        //this happens on windows, dunno about linux
                        bool isDirectory;
                        try
                        {
                            isDirectory = synchronousIOManager.IsDirectory(path);
                        }
                        catch
                        {
                            isDirectory = false;
                        }

                        result = new ConfigurationFile
                        {
                            Path = configurationRelativePath
                        };
                        if (!isDirectory)
                        {
                            result.AccessDenied = true;
                        }
                        else
                        {
                            result.IsDirectory = true;
                        }
                    }
            }

            using (await SemaphoreSlimContext.Lock(semaphore, cancellationToken).ConfigureAwait(false))
                if (systemIdentity == null)
                {
                    await Task.Factory.StartNew(ReadImpl, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false);
                }
                else
                {
                    await systemIdentity.RunImpersonated(ReadImpl, cancellationToken).ConfigureAwait(false);
                }

            return(result);
        }