@@ -77,7 +77,7 @@ public static MaaAgentClient Create(MaaResource resource)
7777 protected override void Dispose ( bool disposing )
7878 {
7979 base . Dispose ( disposing ) ;
80- _agentServerProcess ? . Dispose ( ) ;
80+ KillAndDisposeAgentServerProcess ( ) ;
8181 }
8282
8383 /// <inheritdoc/>
@@ -135,23 +135,74 @@ public bool LinkStart()
135135 /// <remarks>
136136 /// Wrapper of <see cref="MaaAgentClientConnect"/>.
137137 /// </remarks>
138- public bool LinkStart ( ProcessStartInfo info )
138+ public bool LinkStart ( ProcessStartInfo info , CancellationToken cancellationToken = default )
139139 {
140- _agentServerProcess = Process . Start ( info ) ;
141- return LinkStart ( ) ;
140+ if ( _agentServerProcess is null or { HasExited : true } )
141+ {
142+ _agentServerProcess ? . Dispose ( ) ;
143+ _agentServerProcess = Process . Start ( info ) ;
144+
145+ if ( _agentServerProcess is null or { HasExited : true } )
146+ return false ;
147+ }
148+
149+ return LinkStartUnlessProcessExit ( _agentServerProcess , cancellationToken ) . GetAwaiter ( ) . GetResult ( ) ;
142150 }
143151
144152 /// <inheritdoc/>
145153 /// <remarks>
146154 /// Wrapper of <see cref="MaaAgentClientConnect"/>.
147155 /// </remarks>
148- public bool LinkStart ( IMaaAgentClient . AgentServerStartupMethod method )
156+ public bool LinkStart ( IMaaAgentClient . AgentServerStartupMethod method , CancellationToken cancellationToken = default )
149157 {
150- ArgumentException . ThrowIfNullOrEmpty ( Id ) ;
151- ArgumentException . ThrowIfNullOrEmpty ( NativeBindingInfo . NativeAssemblyDirectory ) ;
158+ if ( _agentServerProcess is null or { HasExited : true } )
159+ {
160+ if ( string . IsNullOrEmpty ( Id ) || string . IsNullOrEmpty ( NativeBindingInfo . NativeAssemblyDirectory ) )
161+ {
162+ throw new InvalidOperationException (
163+ $ "The { nameof ( Id ) } ({ Id ?? "<null>" } )" +
164+ $ " or { nameof ( NativeBindingInfo . NativeAssemblyDirectory ) } ({ NativeBindingInfo . NativeAssemblyDirectory ?? "<null>" } )" +
165+ $ " is invalid.") ;
166+ }
152167
153- _agentServerProcess = method . Invoke ( Id , NativeBindingInfo . NativeAssemblyDirectory ) ;
154- return LinkStart ( ) ;
168+ _agentServerProcess ? . Dispose ( ) ;
169+ _agentServerProcess = method . Invoke ( Id , NativeBindingInfo . NativeAssemblyDirectory ) ;
170+
171+ if ( _agentServerProcess is null or { HasExited : true } )
172+ return false ;
173+ }
174+
175+ return LinkStartUnlessProcessExit ( _agentServerProcess , cancellationToken ) . GetAwaiter ( ) . GetResult ( ) ;
176+ }
177+
178+ /// <inheritdoc/>
179+ public async Task < bool > LinkStartUnlessProcessExit ( Process process , CancellationToken cancellationToken )
180+ {
181+ ArgumentNullException . ThrowIfNull ( process ) ;
182+ using var cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
183+ if ( process . HasExited )
184+ return false ;
185+
186+ var serverExitTask = process . WaitForExitAsync ( cts . Token ) ;
187+ var linkStartTask = Task . Run ( LinkStart , cts . Token ) ;
188+ var completedTask = await Task . WhenAny ( linkStartTask , serverExitTask ) . ConfigureAwait ( false ) ;
189+
190+ try
191+ {
192+ cts . Token . ThrowIfCancellationRequested ( ) ;
193+ if ( completedTask == serverExitTask )
194+ return false ;
195+
196+ return linkStartTask . Result ;
197+ }
198+ finally
199+ {
200+ #if NET8_0_OR_GREATER
201+ await cts . CancelAsync ( ) ;
202+ #else
203+ cts . Cancel ( ) ;
204+ #endif
205+ }
155206 }
156207
157208 /// <inheritdoc/>
@@ -175,5 +226,20 @@ public bool LinkStop()
175226
176227 /// <inheritdoc/>
177228 public Process AgentServerProcess => _agentServerProcess
178- ?? throw new InvalidOperationException ( $ "The agent server process is unavailable or not managed by { nameof ( MaaAgentClient ) } .") ;
229+ ?? throw new InvalidOperationException ( $ "The agent server process is unavailable or not managed by { nameof ( MaaAgentClient ) } .") ;
230+
231+ private void KillAndDisposeAgentServerProcess ( )
232+ {
233+ if ( _agentServerProcess is null )
234+ return ;
235+
236+ if ( ! _agentServerProcess . HasExited )
237+ {
238+ _agentServerProcess . Kill ( entireProcessTree : true ) ;
239+ _agentServerProcess . WaitForExit ( ) ;
240+ }
241+
242+ _agentServerProcess . Dispose ( ) ;
243+ _agentServerProcess = null ;
244+ }
179245}
0 commit comments