/// <inheritdoc /> public override Task InstallByond(string path, Version version, CancellationToken cancellationToken) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (version == null) { throw new ArgumentNullException(nameof(version)); } // write the scripts for running the ting // need to add $ORIGIN to LD_LIBRARY_PATH const string StandardScript = "#!/bin/sh\nexport LD_LIBRARY_PATH=\"\\$ORIGIN:$LD_LIBRARY_PATH\"\nBASEDIR=$(dirname \"$0\")\nexec \"$BASEDIR/{0}\" \"$@\"\n"; var dreamDaemonScript = String.Format(CultureInfo.InvariantCulture, StandardScript, DreamDaemonExecutableName); var dreamMakerScript = String.Format(CultureInfo.InvariantCulture, StandardScript, DreamMakerExecutableName); async Task WriteAndMakeExecutable(string pathToScript, string script) { Logger.LogTrace("Writing script {0}:{1}{2}", pathToScript, Environment.NewLine, script); await IOManager.WriteAllBytes(pathToScript, Encoding.ASCII.GetBytes(script), cancellationToken).ConfigureAwait(false); postWriteHandler.HandleWrite(IOManager.ResolvePath(pathToScript)); } var basePath = IOManager.ConcatPath(path, ByondManager.BinPath); var task = Task.WhenAll(WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamDaemonName), dreamDaemonScript), WriteAndMakeExecutable(IOManager.ConcatPath(basePath, DreamMakerName), dreamMakerScript)); postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamDaemonExecutableName)); postWriteHandler.HandleWrite(IOManager.ConcatPath(basePath, DreamMakerExecutableName)); return(task); }
/// <summary> /// Construct a <see cref="WindowsByondInstaller"/> /// </summary> /// <param name="processExecutor">The value of <see cref="processExecutor"/></param> /// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="ByondInstallerBase"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="ByondInstallerBase"/>.</param> public WindowsByondInstaller(IProcessExecutor processExecutor, IIOManager ioManager, ILogger <WindowsByondInstaller> logger) : base(ioManager, logger) { this.processExecutor = processExecutor ?? throw new ArgumentNullException(nameof(processExecutor)); PathToUserByondFolder = IOManager.ResolvePath(IOManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "BYOND")); semaphore = new SemaphoreSlim(1); installedDirectX = false; }
/// <summary> /// Construct a <see cref="WindowsByondInstaller"/> /// </summary> /// <param name="postWriteHandler">The value of <see cref="postWriteHandler"/></param> /// <param name="ioManager">The <see cref="IIOManager"/> for the <see cref="ByondInstallerBase"/>.</param> /// <param name="logger">The <see cref="ILogger"/> for the <see cref="ByondInstallerBase"/>.</param> public PosixByondInstaller(IPostWriteHandler postWriteHandler, IIOManager ioManager, ILogger <PosixByondInstaller> logger) : base(ioManager, logger) { this.postWriteHandler = postWriteHandler ?? throw new ArgumentNullException(nameof(postWriteHandler)); PathToUserByondFolder = IOManager.ResolvePath( IOManager.ConcatPath( Environment.GetFolderPath( Environment.SpecialFolder.UserProfile), "./byond/cache")); }
/// <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); }
/// <summary> /// Creates the BYOND cfg file that prevents the trusted mode dialog from appearing when launching DreamDaemon. /// </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 SetNoPromptTrusted(string path, CancellationToken cancellationToken) { var configPath = IOManager.ConcatPath(path, ByondConfigDir); await IOManager.CreateDirectory(configPath, cancellationToken).ConfigureAwait(false); var configFilePath = IOManager.ConcatPath(configPath, ByondDDConfig); Logger.LogTrace("Disabling trusted prompts in {0}...", configFilePath); await IOManager.WriteAllBytes( configFilePath, Encoding.UTF8.GetBytes(ByondNoPromptTrustedMode), cancellationToken) .ConfigureAwait(false); }
/// <inheritdoc /> public override async Task CleanCache(CancellationToken cancellationToken) { try { await IOManager.DeleteDirectory(IOManager.ConcatPath(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "byond/cache"), cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception e) { Logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e); } }
/// <inheritdoc /> public async Task CleanCache(CancellationToken cancellationToken) { try { Logger.LogDebug("Cleaning BYOND cache..."); await IOManager.DeleteDirectory( IOManager.ConcatPath( PathToUserByondFolder, CacheDirectoryName), cancellationToken) .ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception e) { Logger.LogWarning("Error deleting BYOND cache! Exception: {0}", e); } }
/// <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); } }
/// <summary> /// Attempt to add the DreamDaemon executable as an exception to the Windows firewall. /// </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 AddDreamDaemonToFirewall(string path, CancellationToken cancellationToken) { var dreamDaemonPath = IOManager.ResolvePath( IOManager.ConcatPath( path, ByondManager.BinPath, DreamDaemonName)); try { using var netshProcess = processExecutor.LaunchProcess( "netsh.exe", IOManager.ResolvePath(), $"advfirewall firewall add rule name=\"TGS DreamDaemon\" program=\"{dreamDaemonPath}\" protocol=tcp dir=in enable=yes action=allow", true, true, true); int exitCode; using (cancellationToken.Register(() => netshProcess.Terminate())) exitCode = await netshProcess.Lifetime.ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); Logger.LogDebug( "netsh.exe output:{0}{1}", Environment.NewLine, await netshProcess.GetCombinedOutput(cancellationToken).ConfigureAwait(false)); if (exitCode != 0) { throw new JobException(ErrorCode.ByondDreamDaemonFirewallFail, new JobException($"Invalid exit code: {exitCode}")); } } catch (Exception ex) { throw new JobException(ErrorCode.ByondDreamDaemonFirewallFail, ex); } }