feat: GSS2.Test refactor + ComputeResourcesService

This commit is contained in:
2026-01-26 13:54:29 +03:00
parent d4e7c300f4
commit 58f307c444
25 changed files with 798 additions and 87 deletions
+33
View File
@@ -0,0 +1,33 @@
using GSS2.Core.Hardware;
using LibCameraSharp;
namespace GSS2.Test.ViewModels;
public class CameraViewModel : ViewModelBase
{
private readonly CameraService _cameraService;
private readonly ILogger<CameraViewModel> _logger;
public CameraViewModel(CameraService cameraService, ILogger<CameraViewModel> logger)
{
_cameraService = cameraService;
_logger = logger;
_logger.LogInformation("Initialized");
}
public async Task<(FrameBuffer, StreamConfiguration)?> CaptureImage(int bufferId)
{
(FrameBuffer, StreamConfiguration)? result = null;
try
{
result = await _cameraService.CaptureViewFinderBuffer(bufferId, CancellationToken.None);
}
catch (Exception e)
{
_logger.LogError(e, "Error while image capture");
}
return result;
}
}
+18
View File
@@ -0,0 +1,18 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace GSS2.Test.ViewModels;
public partial class MainViewModel : ViewModelBase
{
private readonly ILogger<MainViewModel> _logger;
[ObservableProperty] private CameraViewModel _cameraViewModel;
[ObservableProperty] private ResourcesViewModel _resourcesViewModel;
public MainViewModel(ILogger<MainViewModel> logger, ResourcesViewModel resourcesViewModel)
{
_logger = logger;
// CameraViewModel = cameraViewModel;
ResourcesViewModel = resourcesViewModel;
_logger.LogInformation("{} initialized", nameof(MainViewModel));
}
}
@@ -0,0 +1,18 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace GSS2.Test.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
[ObservableProperty] private string _title;
[ObservableProperty] private MainViewModel _mainViewModel;
private readonly ILogger<MainWindowViewModel> _logger;
public MainWindowViewModel(ILogger<MainWindowViewModel> logger, MainViewModel mainViewModel)
{
_logger = logger;
MainViewModel = mainViewModel;
Title = "GSS2.Test";
_logger.LogInformation("{} initialized", nameof(MainWindowViewModel));
}
}
+458
View File
@@ -0,0 +1,458 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using Avalonia.Threading;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using LiveChartsCore.SkiaSharpView.Painting;
using SkiaSharp;
using GSS2.Core.Hardware;
using LiveChartsCore.SkiaSharpView.Avalonia;
using LiveChartsCore.Defaults;
namespace GSS2.Test.ViewModels;
public partial class ResourcesViewModel : ViewModelBase, IDisposable
{
private bool _disposedValue;
private readonly ComputeResourcesService _computeResourcesService;
private readonly ILogger<ResourcesViewModel> _logger;
[ObservableProperty] private ObservableCollection<ISeries> _cpuUsageSeries;
[ObservableProperty] private ObservableCollection<Axis> _cpuUsageSeriesYAxes;
[ObservableProperty] private ObservableCollection<Axis> _cpuUsageSeriesXAxes;
[ObservableProperty] private ObservableCollection<ISeries> _cpuUsagePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _cpu0UsagePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _cpu1UsagePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _cpu2UsagePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _cpu3UsagePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _cpuTemperatureSeries;
[ObservableProperty] private ObservableCollection<Axis> _cpuTemperatureSeriesYAxes;
[ObservableProperty] private ObservableCollection<Axis> _cpuTemperatureSeriesXAxes;
[ObservableProperty] private ObservableCollection<ISeries> _cpuTemperaturePieSeries;
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsageSeries;
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesYAxes;
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesXAxes;
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsagePieSeries;
[ObservableProperty] private int _intervalMs = 500;
[ObservableProperty] private int _chartsHistorySize = 120;
private readonly System.Timers.Timer _updateTimer;
public ResourcesViewModel(ComputeResourcesService computeResourcesService, ILogger<ResourcesViewModel> logger)
{
_computeResourcesService = computeResourcesService;
_logger = logger;
CpuUsageSeries = [
new LineSeries<double>
{
Name = "Нагрузка ЦПУ, %",
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
GeometrySize = 0,
ShowDataLabels = false,
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
GeometryFill = new SolidColorPaint(SKColors.DeepSkyBlue, 0),
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
IsHoverable = false
}
];
CpuUsageSeriesYAxes = [
new Axis
{
MinLimit = 0.0,
MaxLimit = 100.0,
Name = "Нагрузка ЦПУ, %",
NameTextSize = 14,
MinStep = 10,
ForceStepToMin = true
}
];
CpuUsageSeriesXAxes = [
new Axis
{
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
LabelsAlignment = LiveChartsCore.Drawing.Align.Start
}
];
CpuUsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 100,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 100,
ShowDataLabels = false,
IsHoverable = false
}
];
Cpu0UsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 50,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 50,
ShowDataLabels = false,
IsHoverable = false
}
];
Cpu1UsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 50,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 50,
ShowDataLabels = false,
IsHoverable = false
}
];
Cpu2UsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 50,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 50,
ShowDataLabels = false,
IsHoverable = false
}
];
Cpu3UsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 50,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 50,
ShowDataLabels = false,
IsHoverable = false
}
];
CpuTemperatureSeries = [
new LineSeries<double>
{
Name = "Температура ЦПУ, ℃",
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
GeometrySize = 0,
ShowDataLabels = false,
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
GeometryFill = new SolidColorPaint(SKColors.DeepSkyBlue, 0),
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
IsHoverable = false
}
];
CpuTemperatureSeriesYAxes = [
new Axis
{
MinLimit = 0.0,
MaxLimit = 100.0,
Name = "Температура ЦПУ, ℃",
NameTextSize = 14,
MinStep = 10,
ForceStepToMin = true
}
];
CpuTemperatureSeriesXAxes = [
new Axis
{
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
LabelsAlignment = LiveChartsCore.Drawing.Align.Start,
}
];
CpuTemperaturePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 100,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} ℃",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 100,
ShowDataLabels = false,
IsHoverable = false
}
];
MemoryUsageSeries = [
new LineSeries<double>
{
Name = "Нагрузка ОЗУ, МБ",
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
GeometrySize = 0,
ShowDataLabels = false,
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
GeometryFill = new SolidColorPaint(SKColors.Transparent, 0),
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
IsHoverable = false
}
];
MemoryUsageSeriesYAxes = [
new Axis
{
MinLimit = 0.0,
MaxLimit = 1000.0,
Name = "Нагрузка ОЗУ, МБ",
NameTextSize = 14,
MinStep = 1000,
ForceStepToMin = true
}
];
MemoryUsageSeriesXAxes = [
new Axis
{
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
LabelsAlignment = LiveChartsCore.Drawing.Align.Start
}
];
MemoryUsagePieSeries = [
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
InnerRadius = 100,
IsHoverable = false,
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("000.00")} МБ",
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
DataLabelsSize = 14,
DataLabelsPaint = new SolidColorPaint(SKColors.White)
},
new PieSeries<ObservableValue>
{
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
InnerRadius = 100,
ShowDataLabels = false,
IsHoverable = false
}
];
Update();
_updateTimer = new System.Timers.Timer(IntervalMs);
_updateTimer.Elapsed += UpdateTimerElapsed;
_updateTimer.AutoReset = true;
_updateTimer.Start();
_logger.LogInformation("{} initialized", nameof(ResourcesViewModel));
}
private void UpdateTimerElapsed(object? sender, System.Timers.ElapsedEventArgs ea) => Update();
private void Update()
{
try
{
var snapshot = _computeResourcesService.GetSnapshot();
Dispatcher.UIThread.Post(() =>
{
if (CpuUsageSeries.Count() == 1 &&
CpuUsageSeries.First().Values is ObservableCollection<double> cpuUsageValues)
{
cpuUsageValues.Add(Math.Round(snapshot.CpuUsage.AllUsagePercent, 2));
while (cpuUsageValues.Count > ChartsHistorySize)
cpuUsageValues.RemoveAt(0);
}
if (CpuUsagePieSeries.Count() == 2 &&
CpuUsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpuUsagePieValue1 &&
cpuUsagePieValue1.Count() == 1 &&
CpuUsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpuUsagePieValue2 &&
cpuUsagePieValue2.Count() == 1)
{
var roundedValue = Math.Round(snapshot.CpuUsage.AllUsagePercent, 2);
cpuUsagePieValue1.First().Value = roundedValue;
cpuUsagePieValue2.First().Value = 100 - roundedValue;
}
if (Cpu0UsagePieSeries.Count() == 2 &&
Cpu0UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu0UsagePieValue1 &&
cpu0UsagePieValue1.Count() == 1 &&
Cpu0UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu0UsagePieValue2 &&
cpu0UsagePieValue2.Count() == 1 &&
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
{
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(0).First(), 2);
cpu0UsagePieValue1.First().Value = roundedValue;
cpu0UsagePieValue2.First().Value = 100 - roundedValue;
}
if (Cpu1UsagePieSeries.Count() == 2 &&
Cpu1UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu1UsagePieValue1 &&
cpu1UsagePieValue1.Count() == 1 &&
Cpu1UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu1UsagePieValue2 &&
cpu1UsagePieValue2.Count() == 1 &&
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
{
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(1).First(), 2);
cpu1UsagePieValue1.First().Value = roundedValue;
cpu1UsagePieValue2.First().Value = 100 - roundedValue;
}
if (Cpu2UsagePieSeries.Count() == 2 &&
Cpu2UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu2UsagePieValue1 &&
cpu2UsagePieValue1.Count() == 1 &&
Cpu2UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu2UsagePieValue2 &&
cpu2UsagePieValue2.Count() == 1 &&
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
{
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(2).First(), 2);
cpu2UsagePieValue1.First().Value = roundedValue;
cpu2UsagePieValue2.First().Value = 100 - roundedValue;
}
if (Cpu3UsagePieSeries.Count() == 2 &&
Cpu3UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu3UsagePieValue1 &&
cpu3UsagePieValue1.Count() == 1 &&
Cpu3UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu3UsagePieValue2 &&
cpu3UsagePieValue2.Count() == 1 &&
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
{
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(3).First(), 2);
cpu3UsagePieValue1.First().Value = roundedValue;
cpu3UsagePieValue2.First().Value = 100 - roundedValue;
}
if (CpuTemperatureSeries.Count() == 1 &&
CpuTemperatureSeries.First().Values is ObservableCollection<double> cpuTemperatureValues)
{
cpuTemperatureValues.Add(Math.Round(snapshot.CpuTemperature.Current, 2));
while (cpuTemperatureValues.Count > ChartsHistorySize)
cpuTemperatureValues.RemoveAt(0);
}
if (CpuTemperatureSeriesYAxes.Count() == 1)
CpuTemperatureSeriesYAxes.First().MaxLimit = Math.Round(snapshot.CpuTemperature.Critical);
if (CpuTemperaturePieSeries.Count() == 2 &&
CpuTemperaturePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpuTemperaturePieValue1 &&
cpuTemperaturePieValue1.Count() == 1 &&
CpuTemperaturePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpuTemperaturePieValue2 &&
cpuTemperaturePieValue2.Count() == 1)
{
var roundedValue = Math.Round(snapshot.CpuTemperature.Current, 2);
cpuTemperaturePieValue1.First().Value = roundedValue;
cpuTemperaturePieValue2.First().Value = snapshot.CpuTemperature.Critical - roundedValue;
}
if (MemoryUsageSeries.Count() == 1 &&
MemoryUsageSeries.First().Values is ObservableCollection<double> memoryUsageValues)
{
memoryUsageValues.Add(Math.Round(snapshot.MemoryUsage.UsedMB, 2));
while (memoryUsageValues.Count > ChartsHistorySize)
memoryUsageValues.RemoveAt(0);
}
if (MemoryUsageSeriesYAxes.Count() == 1)
MemoryUsageSeriesYAxes.First().MaxLimit = Math.Round(snapshot.MemoryUsage.TotalMB);
if (MemoryUsagePieSeries.Count() == 2 &&
MemoryUsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> memoryUsagePieValue1 &&
memoryUsagePieValue1.Count() == 1 &&
MemoryUsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> memoryUsagePieValue2 &&
memoryUsagePieValue2.Count() == 1)
{
var roundedValue = Math.Round(snapshot.MemoryUsage.UsedMB, 2);
memoryUsagePieValue1.First().Value = roundedValue;
memoryUsagePieValue2.First().Value = snapshot.MemoryUsage.TotalMB - roundedValue;
}
});
}
catch (Exception e)
{
_logger.LogWarning(e, "Exception while update");
}
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
try
{
_updateTimer.Stop();
_updateTimer.Dispose();
}
catch
{ }
}
_disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
+6
View File
@@ -0,0 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace GSS2.Test.ViewModels;
public abstract class ViewModelBase : ObservableObject
{ }