ExecuteAsync() private method

private ExecuteAsync ( System.Guid id, [ commandLine, [ writer, CancellationToken token = default(CancellationToken) ) : Task
id System.Guid
commandLine [
writer [
token System.Threading.CancellationToken
return Task
        /// <summary>
        /// Runs the specified service using the command console as a user interface.
        /// </summary>
        /// <param name="service">The service.</param>
        /// <param name="runMode">The run mode.</param>
        /// <param name="defaultLogFormat">The default log format.</param>
        /// <param name="defaultLoggingLevels">The default logging levels.</param>
        /// <param name="token">The token.</param>
        /// <returns>
        /// An awaitable task.
        /// </returns>
        // ReSharper disable once CodeAnnotationAnalyzer
        public static async Task RunAsync(
            [NotNull] BaseService service,
            RunMode runMode = RunMode.Default,
            [CanBeNull] FormatBuilder defaultLogFormat = null,
            LoggingLevels defaultLoggingLevels         = LoggingLevels.All,
            CancellationToken token = default(CancellationToken))
        {
            if (service == null)
            {
                throw new ArgumentNullException("service");
            }

            if (!ConsoleHelper.IsConsole)
            {
                return;
            }
            Console.Clear();
            Log.SetTrace(validLevels: LoggingLevels.None);
            Log.SetConsole(defaultLogFormat ?? _logFormatBuilder, defaultLoggingLevels);
            await Log.Flush(token).ConfigureAwait(false);

            Impersonator impersonator = null;

            try
            {
                if (runMode.HasFlag(RunMode.Prompt))
                {
                    Debug.Assert(service.ServiceName != null);

                    // Whether we start will depend on the selected option in prompt.
                    runMode = runMode.Clear(RunMode.Start, true);

                    Console.Title = ServiceResources.ConsoleConnection_RunAsync_ConfigureTitle + service.ServiceName;
                    bool done = false;

                    do
                    {
                        if (token.IsCancellationRequested)
                        {
                            return;
                        }

                        Dictionary <string, string> options = new Dictionary <string, string>
                        {
                            { "I", ServiceResources.ConsoleConnection_RunAsync_OptionInstall },
                            { "U", ServiceResources.ConsoleConnection_RunAsync_OptionUninstall },
                            { "S", ServiceResources.ConsoleConnection_RunAsync_OptionStart },
                            { "R", ServiceResources.ConsoleConnection_RunAsync_OptionRestart },
                            { "T", ServiceResources.ConsoleConnection_RunAsync_OptionStop },
                            { "P", ServiceResources.ConsoleConnection_RunAsync_OptionPause },
                            { "C", ServiceResources.ConsoleConnection_RunAsync_OptionContinue },
                            { "Y", ServiceResources.ConsoleConnection_RunAsync_OptionRunCmd },
                            { "V", ServiceResources.ConsoleConnection_RunAsync_OptionStartCmd },
                            { "W", ServiceResources.ConsoleConnection_RunAsync_OptionRunCmdNewCredentials },
                            { "Z", ServiceResources.ConsoleConnection_RunAsync_OptionRunNoInteraction },
                            { "X", ServiceResources.ConsoleConnection_RunAsync_OptionExit }
                        };

                        if (!runMode.HasFlag(RunMode.Interactive))
                        {
                            options.Remove("V");
                            options.Remove("Y");
                            options.Remove("W");
                        }

                        bool   isAdmin;
                        string currentUser;
                        try
                        {
                            WindowsIdentity identity = WindowsIdentity.GetCurrent();
                            currentUser = identity.Name;
                            Debug.Assert(identity != null);
                            WindowsPrincipal principal = new WindowsPrincipal(identity);
                            isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
                        }
                        catch
                        {
                            isAdmin     = false;
                            currentUser = null;
                        }

                        if (!string.IsNullOrEmpty(currentUser))
                        {
                            FormatBuilder fb = new FormatBuilder()
                                               .AppendForegroundColor(ConsoleColor.Cyan)
                                               .Append("Current User: "******" [Admin]");
                            }
                            fb.AppendLine().WriteToConsole();
                        }

                        if (!isAdmin)
                        {
                            options.Remove("I");
                            options.Remove("U");
                        }

                        if (Controller.ServiceIsInstalled(service.ServiceName))
                        {
                            ServiceControllerStatus state = Controller.GetServiceStatus(service.ServiceName);
                            new FormatBuilder()
                            .AppendForegroundColor(ConsoleColor.White)
                            .AppendFormatLine(
                                ServiceResources.ConsoleConnection_RunAsync_ServiceInstalledState,
                                service.ServiceName,
                                state)
                            .AppendResetForegroundColor()
                            .WriteToConsole();

                            options.Remove("I");

                            switch (state)
                            {
                            case ServiceControllerStatus.StopPending:
                            case ServiceControllerStatus.Stopped:
                                // Service is stopped or stopping.
                                options.Remove("C");
                                options.Remove("R");
                                options.Remove("T");
                                break;

                            case ServiceControllerStatus.StartPending:
                            case ServiceControllerStatus.ContinuePending:
                            case ServiceControllerStatus.Running:
                                // Service is starting or running.
                                options.Remove("S");
                                options.Remove("C");
                                break;

                            case ServiceControllerStatus.PausePending:
                            case ServiceControllerStatus.Paused:
                                // Service is paused or pausing.
                                options.Remove("S");
                                options.Remove("R");
                                options.Remove("T");
                                options.Remove("P");
                                break;

                            default:
                                // Service is not installed - shouldn't happen.
                                options.Remove("U");
                                options.Remove("S");
                                options.Remove("R");
                                options.Remove("T");
                                options.Remove("C");
                                options.Remove("P");
                                break;
                            }
                            options.Remove("V");
                            options.Remove("Y");
                            options.Remove("Z");
                        }
                        else
                        {
                            // No service installed.
                            options.Remove("U");
                            options.Remove("S");
                            options.Remove("R");
                            options.Remove("T");
                            options.Remove("P");
                            options.Remove("C");
                        }

                        _promptInstall.WriteToConsole(
                            null,
                            // ReSharper disable once PossibleNullReferenceException
                            (_, c) => !string.Equals(c.Tag, "options", StringComparison.CurrentCultureIgnoreCase)
                                ? Resolution.Unknown
                                : options);

                        string key;
                        do
                        {
                            key = Char.ToUpperInvariant(Console.ReadKey(true).KeyChar)
                                  .ToString(CultureInfo.InvariantCulture);
                        } while (!options.ContainsKey(key));

                        try
                        {
                            string userName;
                            string password;

                            switch (key)
                            {
                            case "I":
                                GetUserNamePassword(out userName, out password);

                                service.Install(ConsoleTextWriter.Default, userName, password);

                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_WaitInstall);
                                while (!Controller.ServiceIsInstalled(service.ServiceName))
                                {
                                    await Task.Delay(250, token).ConfigureAwait(false);

                                    Console.Write('.');
                                }
                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "U":
                                await service.Uninstall(ConsoleTextWriter.Default, token).ConfigureAwait(false);

                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_WaitUninstall);
                                while (Controller.ServiceIsInstalled(service.ServiceName))
                                {
                                    await Task.Delay(250, token).ConfigureAwait(false);

                                    Console.Write('.');
                                }
                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "R":
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingStop);
                                await Controller.StopService(service.ServiceName, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingStart);
                                await
                                Controller.StartService(service.ServiceName, null, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "S":
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingStart);
                                await
                                Controller.StartService(service.ServiceName, null, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "T":
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingStop);
                                await Controller.StopService(service.ServiceName, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "P":
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingPause);
                                await Controller.PauseService(service.ServiceName, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                break;

                            case "C":
                                Console.Write(ServiceResources.ConsoleConnection_RunAsync_AttemptingContinue);
                                await Controller.ContinueService(service.ServiceName, token).ConfigureAwait(false);

                                Console.WriteLine(ServiceResources.Done);
                                Console.WriteLine();
                                break;

                            case "V":
                                runMode = runMode.Set(RunMode.Start, true).Set(RunMode.Interactive, true);
                                done    = true;
                                break;

                            case "Y":
                                runMode = runMode.Set(RunMode.Interactive, true);
                                done    = true;
                                break;

                            case "W":
                                GetUserNamePassword(out userName, out password);
                                if (userName == null)
                                {
                                    break;
                                }
                                Debug.Assert(password != null);

                                Impersonator ei = impersonator;
                                impersonator = null;
                                if (ei != null)
                                {
                                    ei.Dispose();
                                }
                                // Run in new security context.
                                impersonator = new Impersonator(userName, password);
                                break;

                            case "Z":
                                runMode = runMode.Set(RunMode.Start, true).Clear(RunMode.Interactive, true);
                                done    = true;
                                Console.WriteLine(ServiceResources.ConsoleConnection_RunAsync_RunningNonInteractive);
                                Console.WriteLine(
                                    ServiceResources.ConsoleConnection_RunAsync_RunningNonInteractive2);
                                Console.WriteLine();
                                break;

                            default:
                                return;
                            }
                        }
                        catch (TaskCanceledException)
                        {
                            return;
                        }
                        catch (Exception e)
                        {
                            if (!token.IsCancellationRequested)
                            {
                                Log.Add(e);
                            }
                        }
                    } while (!done);
                }
                else if (!runMode.HasFlag(RunMode.Interactive))
                {
                    // If we don't show prompt and we're not interactive we should always start the service.
                    runMode = runMode.Set(RunMode.Start, true);
                }

                // Create connection
                Console.Title = ServiceResources.ConsoleConnection_RunAsync_RunningTitle + service.ServiceName;
                ConsoleConnection connection = new ConsoleConnection(defaultLogFormat, defaultLoggingLevels, token);
                Guid id = service.Connect(connection);

                // Combined cancellation tokens.
                ITokenSource tSource = token.CreateLinked(connection._cancellationTokenSource.Token);
                try
                {
                    CancellationToken t = tSource.Token;

                    if (t.IsCancellationRequested)
                    {
                        return;
                    }

                    if (runMode.HasFlag(RunMode.Start))
                    {
                        // Start the service
                        await service.StartService(ConsoleTextWriter.Default, null, t).ConfigureAwait(false);

                        if (t.IsCancellationRequested)
                        {
                            return;
                        }
                    }

                    if (!runMode.HasFlag(RunMode.Interactive))
                    {
                        // Wait to be cancelled as nothing to do.
                        await t.WaitHandle;
                        return;
                    }

                    do
                    {
                        // Flush logs
                        await Log.Flush(t).ConfigureAwait(false);

                        if (t.IsCancellationRequested)
                        {
                            break;
                        }

                        WritePrompt(service);
                        try
                        {
                            string commandLine = await Console.In.ReadLineAsync().ConfigureAwait(false);

                            if (!string.IsNullOrWhiteSpace(commandLine))
                            {
                                bool completed = false;
                                ICancelableTokenSource commandCancellationSource = t.ToCancelable();
                                CancellationToken      commandToken = commandCancellationSource.Token;

#pragma warning disable 4014
                                service.ExecuteAsync(id, commandLine, ConsoleTextWriter.Default, commandToken)
                                .ContinueWith(
                                    task =>
                                {
                                    Debug.Assert(task != null);

                                    completed = true;

                                    if (task.IsCompleted ||
                                        task.IsCanceled)
                                    {
                                        return;
                                    }

                                    if (task.IsFaulted)
                                    {
                                        Debug.Assert(task.Exception != null);
                                        _errorFormat.WriteToConsoleInstance(null, task.Exception);
                                    }
                                },
                                    TaskContinuationOptions.ExecuteSynchronously);
#pragma warning restore 4014

                                while (!completed)
                                {
                                    if (!commandCancellationSource.IsCancellationRequested &&
                                        Console.KeyAvailable &&
                                        Console.ReadKey(true).Key == ConsoleKey.Escape)
                                    {
                                        // Cancel command
                                        Console.Write(ServiceResources.ConsoleConnection_RunAsync_Cancelling);
                                        commandCancellationSource.Cancel();
                                        break;
                                    }
                                    await Task.Delay(100, token).ConfigureAwait(false);
                                }
                            }
                        }
                        catch (TaskCanceledException)
                        {
                            throw;
                        }
                        catch (Exception e)
                        {
                            if (!t.IsCancellationRequested)
                            {
                                _errorFormat.WriteToConsoleInstance(null, e);
                            }
                        }

                        // Let any async stuff done by the command have a bit of time, also throttle commands.
                        await Task.Delay(500, t).ConfigureAwait(false);
                    } while (!t.IsCancellationRequested);
                }
                catch (TaskCanceledException)
                {
                }
                finally
                {
                    tSource.Dispose();

                    // ReSharper disable MethodSupportsCancellation
                    Log.Flush().Wait();
                    // ReSharper restore MethodSupportsCancellation
                    service.Disconnect(id);
                    Console.WriteLine(ServiceResources.ConsoleConnection_RunAsync_PressKeyToExit);
                    Console.ReadKey(true);
                }
            }
            finally
            {
                if (impersonator != null)
                {
                    impersonator.Dispose();
                }
            }
        }
Example #2
0
            /// <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);
            }