Ejemplo n.º 1
0
        static Task <int> CleanAsync(
            StringLocalizer stringLocalizer,
            InvocationContext invocationContext,
            CancellationToken _)
        {
            var console  = invocationContext.Console;
            var reporter = new NvmeSmartAttributesReporter(stringLocalizer);

            try
            {
                try
                {
                    console.Out.Write(stringLocalizer["LOG_UNREGISTERING_PERFORMANCE_COUNTERS"]);
                    reporter.DeleteCategory();
                }
                finally
                {
                    console.Out.Write(stringLocalizer["LOG_QUITTING"]);
                }
            }
            catch (Exception exception)
            {
                console.Error.Write($"{stringLocalizer["ERROR"]}: {exception}\n");
                return(Task.FromResult(1));
            }
            return(Task.FromResult(0));
        }
Ejemplo n.º 2
0
        public static async Task <int> Main(string[] args)
        {
            using var globalMutex = new Mutex(false, $"Global\\Ydi.NvmeMate");

            var stringLocalizer = new StringLocalizer();

            if (!globalMutex.WaitOne(0, false))
            {
                throw new InvalidOperationException(stringLocalizer["ERROR_ALREADY_RUNNING"]);
            }
            if (!OperatingSystem.IsWindows())
            {
                throw new NotSupportedException(stringLocalizer["ERROR_UNSUPPORTED_OPERATING_SYSTEM"]);
            }
            if (!Environment.Is64BitOperatingSystem)
            {
                throw new NotSupportedException(stringLocalizer["ERROR_UNSUPPORTED_BECAUSE_NOT_X64"]);
            }

            var rootCommand = new RootCommand
            {
                new Option <string>("--lang", description: stringLocalizer["ARG_LANG_HELP"]),
                new Option <uint>("--interval", description: stringLocalizer["ARG_INTERVAL_HELP"]),
                new Option <bool>("--plot", stringLocalizer["ARG_PLOT_HELP"]),
                new Option <bool>("--scan", stringLocalizer["ARG_SCAN_HELP"]),
                new Option <byte>("--scan-range", () => 8, stringLocalizer["ARG_SCAN_RANGE_HELP"]),
                new Option <byte[]>("--skip", stringLocalizer["ARG_SKIP_HELP"]),
                new Option <bool>("--hydra", stringLocalizer["ARG_HYDRA_HELP"]),
                new Option <bool>("--clean", stringLocalizer["ARG_CLEAN_HELP"]),
            };

            rootCommand.Description = stringLocalizer["DESCRIPTION"];
            rootCommand.Handler     = CommandHandler.Create((
                                                                string lang,
                                                                uint interval,
                                                                bool plot,
                                                                bool scan,
                                                                byte scanRange,
                                                                byte[] skip,
                                                                bool hydra,
                                                                bool clean,
                                                                InvocationContext invocationContext,
                                                                CancellationToken terminationToken) =>
            {
                stringLocalizer = new StringLocalizer(lang);
                return(clean
                                                ? CleanAsync(stringLocalizer, invocationContext, terminationToken)
                                                : WatchAsync(stringLocalizer, invocationContext, terminationToken, interval, plot, scan, scanRange, skip, hydra));
            });
            return(await rootCommand.InvokeAsync(args));
        }
Ejemplo n.º 3
0
        static async Task <int> WatchAsync(
            StringLocalizer stringLocalizer,
            InvocationContext invocationContext,
            CancellationToken terminationToken,
            uint interval,
            bool plot,
            bool scan,
            byte scanRange,
            byte[] skip,
            bool hydra)
        {
            var console  = new VirtualTerminal(invocationContext.Console, VirtualTerminalMode.TryEnable());
            var reporter = new NvmeSmartAttributesReporter(stringLocalizer);
            var attributesProviderMap = new Dictionary <int, NvmeSmartAttributesProvider>();

            try
            {
                try
                {
                    if (!scan)
                    {
                        console.Out.Write(stringLocalizer["LOG_REGISTERING_PERFORMANCE_COUNTERS"]);
                        reporter.CreateCategory();
                    }

                    console.Out.Write(stringLocalizer["LOG_DETECTING_NVME_DRIVES"]);
                    for (ushort driveNumber = 0; driveNumber < scanRange; ++driveNumber)
                    {
                        if (skip.Contains((byte)driveNumber))
                        {
                            continue;
                        }
                        var attributesProvider = NvmeSmartAttributesProvider.Create((byte)driveNumber);
                        if (attributesProvider == null)
                        {
                            continue;
                        }
                        if (attributesProvider.Query(out var _))
                        {
                            attributesProviderMap.Add(driveNumber, attributesProvider);
                            if (!scan)
                            {
                                reporter.AddInstance(attributesProvider.Moniker, attributesProvider.Model, attributesProvider.SerialNumber);
                            }
                            console.Out.Write($"\t{attributesProvider.Moniker.Replace("_", string.Empty)}: {attributesProvider.Model ?? stringLocalizer["NOT_AVAILABLE"]} (S/N: {attributesProvider.SerialNumber ?? stringLocalizer["NOT_AVAILABLE"]})\r\n");
                        }
                        else
                        {
                            attributesProvider.Dispose();
                        }
                    }
                    if (attributesProviderMap.Count == 0)
                    {
                        console.Out.Write(stringLocalizer["LOG_CANNOT_DETECT_ANY_NVME_DRIVES"]);
                        return(1);
                    }
                    if (scan)
                    {
                        return(0);
                    }

                    console.Out.Write(stringLocalizer["LOG_START_MONITORING"]);
                    if (plot)
                    {
                        if (console is ITerminal terminal)
                        {
                            terminal.Clear();
                            terminal.SetCursorPosition(0, 0);
                            terminal.HideCursor();
                        }

                        var renderer = new ConsoleRenderer(console, invocationContext.BindingContext.OutputMode(), true);

                        var table = new TableView <NvmeSmartAttributesReporterInstance>()
                        {
                            Items = reporter.Instances
                        };
                        table.AddColumn(item => item.Moniker.Replace("_", string.Empty), new ContentView("#".Underline()));
                        table.AddColumn(item => item.Model, new ContentView("Model".Underline()));
                        table.AddColumn(item => item.SerialNumber, new ContentView("S/N".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.PercentageUsedEstimate, value => $"{value}%"), new ContentView("PUE".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.TemperatureDegCelsius, value => $"{value}°C"), new ContentView("CTemp".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.WarningCompositeTemperatureTime, value => $"{value} mins."), new ContentView("WCTemp".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.CriticalCompositeTemperatureTime, value => $"{value} mins."), new ContentView("CCTemp".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.HostReadCommands), new ContentView("HRC".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.HostWriteCommands), new ContentView("HWC".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.DataUnitsRead), new ContentView("DUR".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.DataUnitsWrite), new ContentView("DUW".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.MediaErrors), new ContentView("ME".Underline()));
                        table.AddColumn(item => ContentView.FromObservable(item.NumberOfErrorInformationLogEntries), new ContentView("EE".Underline()));

                        var screen = new ScreenView(renderer, console)
                        {
                            Child = table
                        };
                        var region = new Region(0, 0, Console.WindowWidth, Console.WindowHeight, true);
                        screen.Render(region);
                    }
                    while (!terminationToken.IsCancellationRequested)
                    {
                        foreach (var driveNumber in attributesProviderMap.Keys)
                        {
                            var attributesProvider = attributesProviderMap[driveNumber];
                            if (!attributesProvider.Query(out var attributes))
                            {
                                console.Error.Write($"\t{attributesProvider.Moniker}: {stringLocalizer["LOG_FAILED_TO_QUERY_SMART"]}\n");
                                continue;
                            }
                            reporter.Next(attributesProvider.Moniker, attributes);
                        }
                        await Task.Delay((int)interval, terminationToken);
                    }
                }
                finally
                {
                    if (plot)
                    {
                        if (console is ITerminal terminal)
                        {
                            terminal.Clear();
                            terminal.SetCursorPosition(0, 0);
                            terminal.ShowCursor();
                        }
                    }
                    console.Out.Write(stringLocalizer["LOG_QUITTING"]);
                    if (!hydra)
                    {
                        reporter.DeleteCategory();
                    }
                    reporter.Dispose();
                    foreach (var attributesProvider in attributesProviderMap.Values)
                    {
                        attributesProvider.Dispose();
                    }
                }
            }
            catch (TaskCanceledException)
            {
            }
            return(0);
        }