Наследование: WebApplications.Utilities.Formatting.ResolvableWriteable
Пример #1
0
        /// <summary>
        /// Writes the prompt.
        /// </summary>
        private static void WritePrompt([CanBeNull] NamedPipeServerInfo server)
        {
            if (Console.CursorLeft != 0)
            {
                ConsoleTextWriter.Default.WriteLine();
            }
            _promptBuilder.WriteToConsole(
                null,
                (_, c) =>
            {
                Debug.Assert(c != null);
                Debug.Assert(c.Tag != null);
                switch (c.Tag.ToLowerInvariant())
                {
                case "time":
                    return(DateTime.Now);

                case "server":
                    return(server);

                default:
                    return(Resolution.Unknown);
                }
            });
        }
Пример #2
0
        public static IEnumerable <NamedPipeServerInfo> GetServices()
        {
            // Note: Directory.GetFiles() can fail if there are pipes on the system with invalid characters,
            // to be safe we use the underlying kernel methods instead.
            IntPtr invalid = new IntPtr(-1);
            IntPtr handle  = IntPtr.Zero;

            try
            {
                WIN32_FIND_DATA data;
                handle = FindFirstFile(@"\\.\pipe\*", out data);
                if (handle == invalid)
                {
                    yield break;
                }

                do
                {
                    NamedPipeServerInfo nps = new NamedPipeServerInfo(@"\\.\pipe\" + data.cFileName);
                    if (nps.IsValid)
                    {
                        yield return(nps);
                    }
                } while (FindNextFile(handle, out data) != 0);
                FindClose(handle);
                handle = invalid;
            }
            finally
            {
                if (handle != invalid)
                {
                    FindClose(handle);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Runs the client, optionally connecting to the given service.
        /// If no service is given, or the service is invalid, the user will be prompted to select a service to connect to.
        /// </summary>
        /// <param name="description">The description.</param>
        /// <param name="server">The server.</param>
        public static void Run([NotNull] string description, [CanBeNull] NamedPipeServerInfo server = null)
        {
            if (!ConsoleHelper.IsConsole)
            {
                return;
            }

            RunAsync(description, server).Wait();
        }
Пример #4
0
        public static Task <NamedPipeClient> Connect(
            [NotNull] string description,
            [CanBeNull] string pipe,
            [NotNull] Action <Message> onReceive,
            CancellationToken token = default(CancellationToken))
        {
            NamedPipeServerInfo server = FindService(pipe);

            if (server == null ||
                !server.IsValid)
            {
                return(null);
            }

            return(Connect(description, server, onReceive, token));
        }
Пример #5
0
        public static Task <NamedPipeClient> Connect(
            [NotNull] string description,
            [CanBeNull] NamedPipeServerInfo server,
            [NotNull] Action <Message> onReceive,
            CancellationToken token = default(CancellationToken))
        {
            if (server == null ||
                !server.IsValid)
            {
                return(TaskResult <NamedPipeClient> .Default);
            }

            NamedPipeClient npc = new NamedPipeClient(description, server, onReceive, token);
            TaskCompletionSource <NamedPipeClient> ccs = npc._connectionCompletionSource;

            // ReSharper disable once AssignNullToNotNullAttribute
            return(ccs != null ? ccs.Task : Task.FromResult(npc));
        }
Пример #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NamedPipeClient" /> class.
        /// </summary>
        /// <param name="description">The client description.</param>
        /// <param name="server">The server.</param>
        /// <param name="onReceive">The action to call on receipt of a message.</param>
        /// <param name="token">The token.</param>
        private NamedPipeClient(
            [NotNull] string description,
            [NotNull] NamedPipeServerInfo server,
            [NotNull] Action <Message> onReceive,
            CancellationToken token = default(CancellationToken))
        {
            if (description == null)
            {
                throw new ArgumentNullException("description");
            }
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }
            if (onReceive == null)
            {
                throw new ArgumentNullException("onReceive");
            }

            _server = server;

            _cancellationTokenSource = new CancellationTokenSource();
            CancellationToken disposeToken = _cancellationTokenSource.Token;

            _clientTask = Task.Run(
                async() =>
            {
                try
                {
                    using (ITokenSource tokenSource = token.CreateLinked(disposeToken))
                        using (
                            OverlappingPipeClientStream stream = new OverlappingPipeClientStream(
                                _server.Host,
                                _server.FullName,
                                PipeTransmissionMode.Message))
                        {
                            _state = PipeState.Open;

                            token = tokenSource.Token;

                            // We need to support cancelling the connect.
                            await stream.Connect(token).ConfigureAwait(false);

                            ConnectResponse connectResponse       = null;
                            DisconnectResponse disconnectResponse = null;

                            if (!token.IsCancellationRequested)
                            {
                                // Set the stream.
                                _stream = stream;
                                _state  = PipeState.AwaitingConnect;

                                // Kick off a connect request, but don't wait for it's result as we're the task that will receive it!
                                ConnectRequest connectRequest = new ConnectRequest(description);
                                await stream.WriteAsync(connectRequest.Serialize(), token).ConfigureAwait(false);

                                // Keep going as long as we're connected.
                                try
                                {
                                    while (stream.IsConnected &&
                                           !disposeToken.IsCancellationRequested)
                                    {
                                        // Read data in.
                                        byte[] data = await stream.ReadAsync(disposeToken).ConfigureAwait(false);

                                        if (data == null)
                                        {
                                            break;
                                        }

                                        // Deserialize the incoming message.
                                        Message message = Message.Deserialize(data);

                                        if (connectResponse == null)
                                        {
                                            // We require a connect response to start
                                            connectResponse = message as ConnectResponse;
                                            if (connectResponse == null ||
                                                connectResponse.ID != connectRequest.ID)
                                            {
                                                break;
                                            }

                                            _state       = PipeState.Connected;
                                            _serviceName = connectResponse.ServiceName;

                                            Log.Add(
                                                LoggingLevel.Notification,
                                                () => ClientResources.Not_NamedPipeClient_Connection,
                                                connectResponse.ServiceName);

                                            TaskCompletionSource <NamedPipeClient> ccs =
                                                Interlocked.Exchange(ref _connectionCompletionSource, null);
                                            if (ccs != null)
                                            {
                                                ccs.TrySetResult(this);
                                            }

                                            // Observer the message.
                                            onReceive(message);
                                            continue;
                                        }

                                        // Check for disconnect, we don't observe the message until the disconnect is complete.
                                        disconnectResponse = message as DisconnectResponse;
                                        if (disconnectResponse != null)
                                        {
                                            break;
                                        }

                                        // Observe the message.
                                        onReceive(message);

                                        Response response = message as Response;
                                        if (response == null)
                                        {
                                            continue;
                                        }

                                        ConnectedCommand connectedCommand;

                                        // Check for cancellation responses.
                                        CommandCancelResponse cancelResponse = response as CommandCancelResponse;
                                        if (cancelResponse != null)
                                        {
                                            // Cancel the associated request
                                            if (_commandRequests.TryGetValue(
                                                    cancelResponse.CancelledCommandId,
                                                    out connectedCommand))
                                            {
                                                // ReSharper disable once PossibleNullReferenceException
                                                connectedCommand.Cancel(cancelResponse);
                                            }
                                        }

                                        // And fall through to complete the response...

                                        // Find command the response is related to, and notify it of the response.
                                        if (!_commandRequests.TryGetValue(response.ID, out connectedCommand))
                                        {
                                            continue;
                                        }

                                        Debug.Assert(connectedCommand != null);
                                        if (connectedCommand.Received(response))
                                        {
                                            _commandRequests.TryRemove(response.ID, out connectedCommand);
                                        }
                                    }
                                }
                                catch (TaskCanceledException)
                                {
                                }
                            }

                            // If we're still connected, and we haven't received a disconnect response, try to send a disconnect request.
                            if (stream.IsConnected &&
                                disconnectResponse == null)
                            {
                                CancellationTokenSource cts = token.IsCancellationRequested
                                    ? new CancellationTokenSource(500)
                                    : null;
                                try
                                {
                                    CancellationToken t = cts != null
                                        ? cts.Token
                                        : token;

                                    // Try to send disconnect request.
                                    // ReSharper disable once PossibleNullReferenceException
                                    await Send(new DisconnectRequest(), t)
                                    .ToTask(t)
                                    .ConfigureAwait(false);
                                }
                                catch (TaskCanceledException)
                                {
                                }
                                finally
                                {
                                    if (cts != null)
                                    {
                                        cts.Dispose();
                                    }
                                }
                            }

                            // Remove the stream.
                            _stream      = null;
                            _state       = PipeState.Closed;
                            _serviceName = null;

                            // If we had a disconnect message observe it now that the disconnect has been actioned,
                            // this prevents the receiver thinking the connection is still active.
                            if (disconnectResponse != null)
                            {
                                onReceive(disconnectResponse);
                                ConnectedCommand connectedCommand;
                                if (_commandRequests.TryGetValue(disconnectResponse.ID, out connectedCommand))
                                {
                                    Debug.Assert(connectedCommand != null);
                                    if (connectedCommand.Received(disconnectResponse))
                                    {
                                        _commandRequests.TryRemove(disconnectResponse.ID, out connectedCommand);
                                    }
                                }
                            }
                        }
                }
                catch (IOException ioe)
                {
                    if (!token.IsCancellationRequested)
                    {
                        // Common exception caused by sudden disconnect, lower level
                        Log.Add(
                            ioe,
                            LoggingLevel.Information,
                            () => ClientResources.Err_NamedPipeClient_Failed);
                    }
                }
                catch (Exception exception)
                {
                    TaskCanceledException tce = exception as TaskCanceledException;
                    TaskCompletionSource <NamedPipeClient> ccs = Interlocked.Exchange(
                        ref _connectionCompletionSource,
                        null);
                    if (ccs != null)
                    {
                        if (tce != null)
                        {
                            ccs.TrySetCanceled();
                        }
                        else
                        {
                            ccs.TrySetException(exception);
                        }
                    }

                    // We only log if this wasn't a cancellation exception.
                    if (tce == null &&
                        !token.IsCancellationRequested)
                    {
                        Log.Add(
                            exception,
                            LoggingLevel.Error,
                            () => ClientResources.Err_NamedPipeClient_Failed);
                    }
                }
                finally
                {
                    Dispose();
                }
            },
                disposeToken);
        }
Пример #7
0
        public static async Task RunAsync(
            [NotNull] string description,
            [CanBeNull] NamedPipeServerInfo service = null,
            CancellationToken token = default(CancellationToken))
        {
            if (description == null)
            {
                throw new ArgumentNullException("description");
            }

            if (!ConsoleHelper.IsConsole)
            {
                return;
            }

            try
            {
                Log.SetTrace(validLevels: LoggingLevels.None);
                Log.SetConsole(_logFormatBuilder);

                Console.Title = description;
                NamedPipeClient client = null;
                while (client == null)
                {
                    token.ThrowIfCancellationRequested();
                    while (service == null ||
                           !service.IsValid)
                    {
                        Console.Clear();
                        NamedPipeServerInfo[] services = null;
                        await Log.Flush(token).ConfigureAwait(false);

                        // ReSharper disable once AssignNullToNotNullAttribute
                        ConsoleTextWriter.Default.WriteLine(ClientResources.ConsoleClient_RunAsync_ScanningForService);
                        while (services == null ||
                               services.Length < 1)
                        {
                            services = NamedPipeClient.GetServices().ToArray();
                            if (Console.KeyAvailable)
                            {
                                return;
                            }
                            // ReSharper disable once PossibleNullReferenceException
                            await Task.Delay(500, token).ConfigureAwait(false);

                            token.ThrowIfCancellationRequested();
                        }

                        if (services.Length > 0)
                        {
                            WriteServerList(services);
                        }

                        // ReSharper disable once AssignNullToNotNullAttribute
                        ConsoleTextWriter.Default.WriteLine(ClientResources.ConsoleClient_RunAsync_EnterServiceName);
                        string serviceName = Console.ReadLine();
                        service = !string.IsNullOrWhiteSpace(serviceName)
                            ? NamedPipeClient.FindService(serviceName)
                            : NamedPipeClient.GetServices().FirstOrDefault();
                    }

                    Console.Clear();
                    // ReSharper disable once AssignNullToNotNullAttribute
                    ConsoleTextWriter.Default.WriteLine(
                        ClientResources.ConsoleClient_RunAsync_ConnectingToService,
                        service.Name);

                    try
                    {
                        // TODO Remove constant timeout
                        using (ITokenSource tokenSource = token.WithTimeout(10000))
                            client =
                                await
                                NamedPipeClient.Connect(
                                    description,
                                    service,
                                    OnReceive,
                                    tokenSource.Token)
                                .ConfigureAwait(false);
                    }
                    catch (TaskCanceledException)
                    {
                        // ReSharper disable once AssignNullToNotNullAttribute
                        ConsoleTextWriter.Default.WriteLine(
                            ClientResources.ConsoleClient_RunAsync_TimedOut,
                            service.Name);
                        // ReSharper disable once AssignNullToNotNullAttribute
                        ConsoleTextWriter.Default.WriteLine(ClientResources.ConsoleClient_RunAsync_PressAnyKeyContinue);
                        client  = null;
                        service = null;
                        Console.ReadKey(true);
                    }
                }

                // ReSharper disable once AssignNullToNotNullAttribute
                Console.Title = string.Format(
                    ClientResources.ConsoleClient_RunAsync_ConnectedTitle,
                    description,
                    service.Name);
                _connected.WriteToConsole(
                    null,
                    new Dictionary <string, object>
                {
                    { "ServiceName", client.ServiceName }
                });

                // ReSharper disable once PossibleNullReferenceException
                await Task.Delay(1100, token).ConfigureAwait(false);

                await Log.Flush(token).ConfigureAwait(false);

                while (client.State != PipeState.Closed)
                {
                    token.ThrowIfCancellationRequested();
                    WritePrompt(service);
                    string command = Console.ReadLine();

                    if (!string.IsNullOrWhiteSpace(command))
                    {
                        Guid commandGuid;
                        bool completed = false;
                        client.Execute(command, out commandGuid, token)
                        .Subscribe(
                            c => new FormatBuilder(c).WriteToConsole(),
                            e =>
                        {
                            Debug.Assert(e != null);
                            if (!(e is TaskCanceledException))
                            {
                                new FormatBuilder()
                                .AppendForegroundColor(ConsoleColor.Red)
                                .AppendLine(e.Message)
                                .AppendResetForegroundColor()
                                .WriteToConsole();
                            }
                            completed = true;
                        },
                            () => { completed = true; },
                            token);

                        if (commandGuid != Guid.Empty)
                        {
                            do
                            {
                                if (Console.KeyAvailable &&
                                    Console.ReadKey(true).Key == ConsoleKey.Escape)
                                {
                                    // Cancel command
                                    ConsoleTextWriter.Default.Write(ClientResources.ConsoleClient_RunAsync_Cancelling);
                                    await client.CancelCommand(commandGuid, token).ConfigureAwait(false);

                                    break;
                                }
                                // ReSharper disable once PossibleNullReferenceException
                                await Task.Delay(100, token).ConfigureAwait(false);
                            } while (!completed);
                        }
                    }

                    // Wait to allow any disconnects or logs to come through.
                    // ReSharper disable once PossibleNullReferenceException
                    await Task.Delay(1100, token).ConfigureAwait(false);

                    await Log.Flush(token).ConfigureAwait(false);
                }
            }
            catch (TaskCanceledException)
            {
            }
            catch (Exception e)
            {
                if (!token.IsCancellationRequested)
                {
                    Log.Add(e);
                }
            }
            await Log.Flush(token).ConfigureAwait(false);

            // ReSharper disable once PossibleNullReferenceException
            await Task.Delay(200, token).ConfigureAwait(false);

            Console.WriteLine(ClientResources.ConsoleClient_RunAsync_PressAnyKeyExit);
            Console.ReadKey(true);
        }
Пример #8
0
        public static IEnumerable<NamedPipeServerInfo> GetServices()
        {
            // Note: Directory.GetFiles() can fail if there are pipes on the system with invalid characters,
            // to be safe we use the underlying kernel methods instead.
            IntPtr invalid = new IntPtr(-1);
            IntPtr handle = IntPtr.Zero;
            try
            {
                WIN32_FIND_DATA data;
                handle = FindFirstFile(@"\\.\pipe\*", out data);
                if (handle == invalid) yield break;

                do
                {
                    NamedPipeServerInfo nps = new NamedPipeServerInfo(@"\\.\pipe\" + data.cFileName);
                    if (nps.IsValid)
                        yield return nps;
                } while (FindNextFile(handle, out data) != 0);
                FindClose(handle);
                handle = invalid;
            }
            finally
            {
                if (handle != invalid)
                    FindClose(handle);
            }
        }
Пример #9
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NamedPipeClient" /> class.
        /// </summary>
        /// <param name="description">The client description.</param>
        /// <param name="server">The server.</param>
        /// <param name="onReceive">The action to call on receipt of a message.</param>
        /// <param name="token">The token.</param>
        private NamedPipeClient(
            [NotNull] string description,
            [NotNull] NamedPipeServerInfo server,
            [NotNull] Action<Message> onReceive,
            CancellationToken token = default(CancellationToken))
        {
            if (description == null) throw new ArgumentNullException("description");
            if (server == null) throw new ArgumentNullException("server");
            if (onReceive == null) throw new ArgumentNullException("onReceive");

            _server = server;

            _cancellationTokenSource = new CancellationTokenSource();
            CancellationToken disposeToken = _cancellationTokenSource.Token;

            _clientTask = Task.Run(
                async () =>
                {
                    try
                    {
                        using (ITokenSource tokenSource = token.CreateLinked(disposeToken))
                        using (
                            OverlappingPipeClientStream stream = new OverlappingPipeClientStream(
                                _server.Host,
                                _server.FullName,
                                PipeTransmissionMode.Message))
                        {
                            _state = PipeState.Open;

                            token = tokenSource.Token;

                            // We need to support cancelling the connect.
                            await stream.Connect(token).ConfigureAwait(false);

                            ConnectResponse connectResponse = null;
                            DisconnectResponse disconnectResponse = null;

                            if (!token.IsCancellationRequested)
                            {
                                // Set the stream.
                                _stream = stream;
                                _state = PipeState.AwaitingConnect;

                                // Kick off a connect request, but don't wait for it's result as we're the task that will receive it!
                                ConnectRequest connectRequest = new ConnectRequest(description);
                                await stream.WriteAsync(connectRequest.Serialize(), token).ConfigureAwait(false);

                                // Keep going as long as we're connected.
                                try
                                {
                                    while (stream.IsConnected &&
                                           !disposeToken.IsCancellationRequested)
                                    {
                                        // Read data in.
                                        byte[] data = await stream.ReadAsync(disposeToken).ConfigureAwait(false);

                                        if (data == null)
                                            break;

                                        // Deserialize the incoming message.
                                        Message message = Message.Deserialize(data);

                                        if (connectResponse == null)
                                        {
                                            // We require a connect response to start
                                            connectResponse = message as ConnectResponse;
                                            if (connectResponse == null ||
                                                connectResponse.ID != connectRequest.ID)
                                                break;

                                            _state = PipeState.Connected;
                                            _serviceName = connectResponse.ServiceName;

                                            Log.Add(
                                                LoggingLevel.Notification,
                                                () => ClientResources.Not_NamedPipeClient_Connection,
                                                connectResponse.ServiceName);

                                            TaskCompletionSource<NamedPipeClient> ccs =
                                                Interlocked.Exchange(ref _connectionCompletionSource, null);
                                            if (ccs != null)
                                                ccs.TrySetResult(this);

                                            // Observer the message.
                                            onReceive(message);
                                            continue;
                                        }

                                        // Check for disconnect, we don't observe the message until the disconnect is complete.
                                        disconnectResponse = message as DisconnectResponse;
                                        if (disconnectResponse != null)
                                            break;

                                        // Observe the message.
                                        onReceive(message);

                                        Response response = message as Response;
                                        if (response == null)
                                            continue;

                                        ConnectedCommand connectedCommand;

                                        // Check for cancellation responses.
                                        CommandCancelResponse cancelResponse = response as CommandCancelResponse;
                                        if (cancelResponse != null)
                                            // Cancel the associated request
                                            if (_commandRequests.TryGetValue(
                                                cancelResponse.CancelledCommandId,
                                                out connectedCommand))
                                                // ReSharper disable once PossibleNullReferenceException
                                                connectedCommand.Cancel(cancelResponse);

                                        // And fall through to complete the response...

                                        // Find command the response is related to, and notify it of the response.
                                        if (!_commandRequests.TryGetValue(response.ID, out connectedCommand))
                                            continue;

                                        Debug.Assert(connectedCommand != null);
                                        if (connectedCommand.Received(response))
                                            _commandRequests.TryRemove(response.ID, out connectedCommand);
                                    }
                                }
                                catch (TaskCanceledException)
                                {
                                }
                            }

                            // If we're still connected, and we haven't received a disconnect response, try to send a disconnect request.
                            if (stream.IsConnected &&
                                disconnectResponse == null)
                            {
                                CancellationTokenSource cts = token.IsCancellationRequested
                                    ? new CancellationTokenSource(500)
                                    : null;
                                try
                                {
                                    CancellationToken t = cts != null
                                        ? cts.Token
                                        : token;

                                    // Try to send disconnect request.
                                    // ReSharper disable once PossibleNullReferenceException
                                    await Send(new DisconnectRequest(), t)
                                        .ToTask(t)
                                        .ConfigureAwait(false);
                                }
                                catch (TaskCanceledException)
                                {
                                }
                                finally
                                {
                                    if (cts != null)
                                        cts.Dispose();
                                }
                            }

                            // Remove the stream.
                            _stream = null;
                            _state = PipeState.Closed;
                            _serviceName = null;

                            // If we had a disconnect message observe it now that the disconnect has been actioned,
                            // this prevents the receiver thinking the connection is still active.
                            if (disconnectResponse != null)
                            {
                                onReceive(disconnectResponse);
                                ConnectedCommand connectedCommand;
                                if (_commandRequests.TryGetValue(disconnectResponse.ID, out connectedCommand))
                                {
                                    Debug.Assert(connectedCommand != null);
                                    if (connectedCommand.Received(disconnectResponse))
                                        _commandRequests.TryRemove(disconnectResponse.ID, out connectedCommand);
                                }
                            }
                        }
                    }
                    catch (IOException ioe)
                    {
                        if (!token.IsCancellationRequested)
                            // Common exception caused by sudden disconnect, lower level
                            Log.Add(
                                ioe,
                                LoggingLevel.Information,
                                () => ClientResources.Err_NamedPipeClient_Failed);
                    }
                    catch (Exception exception)
                    {
                        TaskCanceledException tce = exception as TaskCanceledException;
                        TaskCompletionSource<NamedPipeClient> ccs = Interlocked.Exchange(
                            ref _connectionCompletionSource,
                            null);
                        if (ccs != null)
                            if (tce != null)
                                ccs.TrySetCanceled();
                            else
                                ccs.TrySetException(exception);

                        // We only log if this wasn't a cancellation exception.
                        if (tce == null &&
                            !token.IsCancellationRequested)
                            Log.Add(
                                exception,
                                LoggingLevel.Error,
                                () => ClientResources.Err_NamedPipeClient_Failed);
                    }
                    finally
                    {
                        Dispose();
                    }
                },
                disposeToken);
        }