mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
159 lines
6.0 KiB
C#
159 lines
6.0 KiB
C#
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using CompatBot.Utils.ResultFormatters;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
|
|
namespace CompatBot.Database.Providers;
|
|
|
|
internal static class HwInfoProvider
|
|
{
|
|
private static readonly Encoding Utf8 = new UTF8Encoding(false);
|
|
private static readonly TimeSpan CacheTime = TimeSpan.FromDays(1);
|
|
private static readonly MemoryCache UserCache = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromHours(1) });
|
|
|
|
public static async ValueTask AddOrUpdateSystemAsync(DiscordClient client, DiscordMessage msg, NameValueCollection items, CancellationToken cancellationToken)
|
|
{
|
|
var ignoreAuthor = await msg.Author.IsWhitelistedAsync(client, msg.Channel.Guild).ConfigureAwait(false);
|
|
byte counter = 0;
|
|
if (!ignoreAuthor
|
|
&& UserCache.TryGetValue(msg.Author.Id, out counter)
|
|
&& counter > 4)
|
|
{
|
|
Config.Log.Debug($"Ignoring HW report for user {msg.Author.Id} ({msg.Author.Username}#{msg.Author.Discriminator})");
|
|
return;
|
|
}
|
|
|
|
if (items["cpu_model"] is not string cpuString
|
|
|| (items["gpu_name"] ?? items["gpu_info"]) is not string gpuString
|
|
|| !int.TryParse(items["thread_count"], out var threadCount)
|
|
|| !decimal.TryParse(items["memory_amount"], out var ramGB)
|
|
|| items["cpu_extensions"] is not string cpuExtensions)
|
|
return;
|
|
|
|
var cpuStringParts = cpuString.Split(' ', 2);
|
|
var gpuStringParts = gpuString.Split(' ', 2);
|
|
if (cpuStringParts.Length != 2 || gpuStringParts.Length != 2)
|
|
return;
|
|
|
|
if (cpuStringParts[0].ToLower() is not ("intel" or "amd" or "apple"))
|
|
{
|
|
Config.Log.Warn($"Unknown CPU maker {cpuStringParts[0]}, plz fix");
|
|
return;
|
|
}
|
|
|
|
if (gpuStringParts[0].ToLower() is not ("nvidia" or "amd" or "ati" or "intel" or "apple"))
|
|
if (LogParserResult.IsNvidia(gpuString))
|
|
gpuStringParts = ["NVIDIA", gpuString];
|
|
else if (LogParserResult.IsAmd(gpuString))
|
|
gpuStringParts = ["AMD", gpuString];
|
|
else
|
|
{
|
|
Config.Log.Warn($"Unknown GPU maker {gpuStringParts[0]}, plz fix");
|
|
return;
|
|
}
|
|
|
|
var ts = msg.Timestamp.UtcDateTime;
|
|
if (items["log_start_timestamp"] is string logTs
|
|
&& DateTime.TryParse(logTs, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out var logTsVal))
|
|
ts = logTsVal.ToUniversalTime();
|
|
var osType = GetOsType(items["os_type"]);
|
|
var info = new HwInfo
|
|
{
|
|
Timestamp = ts.Ticks,
|
|
InstallId = GetHwId(items, msg),
|
|
|
|
CpuMaker = cpuStringParts[0],
|
|
CpuModel = cpuStringParts[1],
|
|
ThreadCount = threadCount,
|
|
CpuFeatures = GetFeatures(cpuExtensions),
|
|
|
|
RamInMb = (int)(ramGB * 1024),
|
|
|
|
GpuMaker = gpuStringParts[0],
|
|
GpuModel = gpuStringParts[1],
|
|
|
|
OsType = osType,
|
|
OsName = GetName(osType, items),
|
|
OsVersion = items["os_version"],
|
|
};
|
|
await using var wdb = await HardwareDb.OpenWriteAsync().ConfigureAwait(false);
|
|
var existingItem = await wdb.HwInfo.FindAsync([info.InstallId], cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
if (existingItem is null)
|
|
wdb.HwInfo.Add(info);
|
|
else if (existingItem.Timestamp <= info.Timestamp)
|
|
wdb.Entry(existingItem).CurrentValues.SetValues(info);
|
|
try
|
|
{
|
|
await wdb.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Config.Log.Error(e, "Failed to update hardware db");
|
|
}
|
|
if (!ignoreAuthor)
|
|
UserCache.Set(msg.Author.Id, counter + 1, CacheTime);
|
|
}
|
|
|
|
private static byte[] GetHwId(NameValueCollection items, DiscordMessage message)
|
|
{
|
|
var id = items["hw_id"] ?? (message.Author.Id.ToString("x16") + items["compat_database_path"]);
|
|
return Utf8.GetBytes(id).GetSaltedHash();
|
|
}
|
|
|
|
private static CpuFeatures GetFeatures(string extensions)
|
|
{
|
|
var result = CpuFeatures.None;
|
|
foreach (var ext in extensions.Split('|', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
if (ext.StartsWith("AVX"))
|
|
{
|
|
result |= CpuFeatures.Avx;
|
|
if (ext.EndsWith('x'))
|
|
result |= CpuFeatures.Xop;
|
|
if (ext.Contains("512"))
|
|
{
|
|
result |= CpuFeatures.Avx512;
|
|
if (ext.Contains('+'))
|
|
result |= CpuFeatures.Avx512IL;
|
|
}
|
|
else if (ext.Contains('+'))
|
|
result |= CpuFeatures.Avx2;
|
|
}
|
|
else if (ext.StartsWith("FMA"))
|
|
{
|
|
if (ext.Contains('3'))
|
|
result |= CpuFeatures.Fma3;
|
|
if (ext.Contains('4'))
|
|
result |= CpuFeatures.Fma4;
|
|
}
|
|
else if (ext.StartsWith("TSX"))
|
|
{
|
|
result |= CpuFeatures.Tsx;
|
|
if (ext.Contains("TSX-FA"))
|
|
result |= CpuFeatures.TsxFa;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static OsType GetOsType(string? osType)
|
|
=> osType switch
|
|
{
|
|
"Windows" => OsType.Windows,
|
|
"Linux" => OsType.Linux,
|
|
"MacOS" => OsType.MacOs,
|
|
"" => OsType.Unknown,
|
|
null => OsType.Unknown,
|
|
_ => OsType.Bsd,
|
|
};
|
|
|
|
private static string? GetName(OsType osType, NameValueCollection items)
|
|
=> osType switch
|
|
{
|
|
OsType.Windows => items["os_windows_version"],
|
|
OsType.Linux => items["os_linux_version"],
|
|
OsType.MacOs => items["os_mac_version"],
|
|
OsType.Bsd => items["os_linux_version"],
|
|
_ => null
|
|
};
|
|
} |