/// <summary> /// Initializes a new instance of the <see cref="ConnectedCommand" /> class. /// </summary> /// <param name="connectionGuid">The connection unique identifier.</param> /// <param name="service">The service.</param> /// <param name="connection">The connection.</param> /// <param name="request">The request.</param> /// <param name="token">The cancellation token.</param> public ConnectedCommand( Guid connectionGuid, [NotNull] BaseService service, [NotNull] NamedPipeConnection connection, [NotNull] CommandRequest request, CancellationToken token = default(CancellationToken)) { ConnectionGuid = connectionGuid; _connection = connection; _request = request; _cancellationTokenSource = token.ToCancelable(); ID = _request.ID; token = _cancellationTokenSource.Token; Task.Run( async () => { try { do { // ReSharper disable once PossibleNullReferenceException await Task.Delay(250, token).ConfigureAwait(false); if (token.IsCancellationRequested) return; await Flush(0, token).ConfigureAwait(false); } while (true); } catch (TaskCanceledException) { } }, token); // Kick of task to run command. Task.Run( async () => { Exception exception = null; bool cancelled = false; try { await service.ExecuteAsync(ConnectionGuid, _request.CommandLine, this, token) .ConfigureAwait(false); if (!token.IsCancellationRequested) await Flush(-1, token).ConfigureAwait(false); else cancelled = true; } catch (OperationCanceledException) { cancelled = true; } catch (Exception e) { exception = e; } if (cancelled) using (await _flushLock.LockAsync(token).ConfigureAwait(false)) { try { using (CancellationTokenSource cts = Constants.FireAndForgetTokenSource) await connection.Send( new CommandCancelResponse( _cancelRequest != null ? _cancelRequest.ID : Guid.Empty, ID), cts.Token) .ConfigureAwait(false); } catch (OperationCanceledException) { } return; } if (exception != null) try { await Flush(0, token).ConfigureAwait(false); _builder.Append(exception.Message); await Flush(-2, token).ConfigureAwait(false); } // ReSharper disable once EmptyGeneralCatchClause catch { } Dispose(true); }, token); }
public IObservable<string> Execute( [CanBeNull] string commandLine, out Guid commandGuid, CancellationToken token = default(CancellationToken)) { if (_clientTask == null || State != PipeState.Connected || string.IsNullOrWhiteSpace(commandLine)) { commandGuid = Guid.Empty; // ReSharper disable once AssignNullToNotNullAttribute return Observable.Empty<string>(); } // We intercept disconnect commands and convert to a proper disconnect request for a cleaner disconnect. // This isn't technically necessary, but it means that the connection requests the disconnect rather than // the server disconnecting the connection - which is how the command works. if (_disconnectCommands.Contains(commandLine.Trim())) { DisconnectRequest disconnect = new DisconnectRequest(); commandGuid = disconnect.ID; // ReSharper disable once AssignNullToNotNullAttribute return Send(disconnect, token) .Select(c => string.Empty) .IgnoreElements(); } // ReSharper disable once AssignNullToNotNullAttribute CommandRequest command = new CommandRequest(commandLine); commandGuid = command.ID; // ReSharper disable once AssignNullToNotNullAttribute return Send(command, token) .Cast<CommandResponse>() // ReSharper disable once PossibleNullReferenceException .Select(r => r.Chunk) .Where(c => !string.IsNullOrEmpty(c)); }