tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
CommandPipeManager.cs
Go to the documentation of this file.
1using System;
2using System.IO;
3using System.IO.Pipes;
4using System.Text;
5using System.Threading;
6using System.Threading.Tasks;
7
8using Microsoft.Extensions.Hosting;
9using Microsoft.Extensions.Logging;
10using Microsoft.Extensions.Options;
11
15
17{
22 {
27
32
36 readonly ILogger<CommandPipeManager> logger;
37
42
53 IOptions<InternalConfiguration> internalConfigurationOptions,
54 ILogger<CommandPipeManager> logger)
55 {
56 this.serverControl = serverControl ?? throw new ArgumentNullException(nameof(serverControl));
57 this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
58 internalConfiguration = internalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(internalConfigurationOptions));
59 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
60 }
61
63 protected override async Task ExecuteAsync(CancellationToken cancellationToken)
64 {
65 logger.LogTrace("Starting...");
66
67 // grab both pipes asap so we can close them on error
68 var commandPipe = internalConfiguration.CommandPipe;
69 var supportsPipeCommands = !String.IsNullOrWhiteSpace(commandPipe);
70 await using var commandPipeClient = supportsPipeCommands
71 ? new AnonymousPipeClientStream(
72 PipeDirection.In,
73 commandPipe!)
74 : null;
75
76 if (!supportsPipeCommands)
77 logger.LogDebug("No command pipe name specified in configuration");
78
79 var readyPipe = internalConfiguration.ReadyPipe;
80 var supportsReadyNotification = !String.IsNullOrWhiteSpace(readyPipe);
81 if (supportsReadyNotification)
82 {
83 await using var readyPipeClient = new AnonymousPipeClientStream(
84 PipeDirection.Out,
85 readyPipe!);
86
87 logger.LogTrace("Waiting to send ready notification...");
88 await instanceManager.Ready.WaitAsync(cancellationToken);
89
90 using var streamWriter = new StreamWriter(readyPipeClient, Encoding.UTF8, leaveOpen: true);
91 await streamWriter.WriteLineAsync(PipeCommands.CommandStartupComplete.AsMemory(), cancellationToken);
92 }
93 else
94 logger.LogDebug("No ready pipe name specified in configuration");
95
96 if (!supportsPipeCommands)
97 return;
98
99 try
100 {
101 using var streamReader = new StreamReader(commandPipeClient!, Encoding.UTF8, leaveOpen: true);
102 while (!cancellationToken.IsCancellationRequested)
103 {
104 logger.LogTrace("Waiting to read command line...");
105 var line = await streamReader.ReadLineAsync(cancellationToken);
106
107 logger.LogInformation("Received pipe command: {command}", line);
108 switch (line)
109 {
111 await serverControl.Die(null);
112 break;
114 await serverControl.GracefulShutdown(false);
115 break;
118 break;
119 case null:
120 logger.LogError("Read null from pipe!");
121 return;
122 default:
123 logger.LogWarning("Unrecognized pipe command: {command}", line);
124 break;
125 }
126 }
127 }
128 catch (OperationCanceledException ex)
129 {
130 logger.LogTrace(ex, "Command read task cancelled!");
131 }
132 catch (Exception ex)
133 {
134 logger.LogError(ex, "Command read task errored!");
135 }
136 finally
137 {
138 logger.LogTrace("Command read task exiting...");
139 }
140 }
141 }
142}
Values able to be passed via the update file path.
const string CommandDetachingShutdown
Stops the server ASAP, detaching the watchdog for any running instances.
const string CommandStop
Stops the server ASAP, shutting down any running instances.
const string CommandGracefulShutdown
Stops the server eventually, waiting for the games in any running instances to reboot.
const string CommandStartupComplete
Indicates that the host has finished initializing.
Unstable configuration options used internally by TGS.
string? CommandPipe
The name of the pipe opened by the host watchdog for sending commands, if any.
string? ReadyPipe
The name of the pipe opened by the host watchdog for receiving commands, if any.
Reads from the command pipe opened by the host watchdog.
CommandPipeManager(IServerControl serverControl, IInstanceManager instanceManager, IOptions< InternalConfiguration > internalConfigurationOptions, ILogger< CommandPipeManager > logger)
Initializes a new instance of the CommandPipeManager class.
readonly InternalConfiguration internalConfiguration
The InternalConfiguration for the CommandPipeManager.
readonly IInstanceManager instanceManager
The IInstanceManager for the CommandPipeManager.
readonly ILogger< CommandPipeManager > logger
The ILogger for the CommandPipeManager.
override async Task ExecuteAsync(CancellationToken cancellationToken)
readonly IServerControl serverControl
The IServerControl for the CommandPipeManager.
Task Ready
Task that completes when the IInstanceManager finishes initializing.
Represents a service that may take an updated Host assembly and run it, stopping the current assembly...
ValueTask GracefulShutdown(bool detach)
Gracefully shutsdown the Host.
ValueTask Die(Exception? exception)
Kill the server with a fatal exception.