111 lines
4.0 KiB
C#
111 lines
4.0 KiB
C#
using BlueLaminate.Cli;
|
|
using BlueLaminate.Cli.Logging;
|
|
using BlueLaminate.EFCore.Data;
|
|
using BlueLaminate.Scraper.Skins;
|
|
using Microsoft.Extensions.Logging;
|
|
using OpenTelemetry;
|
|
using OpenTelemetry.Resources;
|
|
using System.CommandLine;
|
|
|
|
// OpenTelemetry logging through a compact console sink that prints one
|
|
// "{utc timestamp} {message}" line per record. Swapping in an OTLP exporter
|
|
// later is a change here. Disposed at process exit so buffered records flush.
|
|
using var loggerFactory = LoggerFactory.Create(logging =>
|
|
{
|
|
logging.AddOpenTelemetry(otel =>
|
|
{
|
|
otel.SetResourceBuilder(
|
|
ResourceBuilder.CreateDefault().AddService("BlueLaminate.Cli"));
|
|
otel.IncludeFormattedMessage = true;
|
|
otel.AddProcessor(new SimpleLogRecordExportProcessor(new CompactConsoleLogExporter()));
|
|
});
|
|
});
|
|
|
|
// Entry point: System.CommandLine builds the command tree, parsing, and help.
|
|
// New features are added as additional commands here as they're implemented.
|
|
var forceOption = new Option<bool>("--force")
|
|
{
|
|
Description = "Ignore the once-a-month throttle and sync now."
|
|
};
|
|
var dryRunOption = new Option<bool>("--dry-run")
|
|
{
|
|
Description = "Load and print the skins without writing to the database."
|
|
};
|
|
|
|
var syncSkins = new Command(
|
|
"sync-skins",
|
|
"Load the CS2 skin catalogue from the CSGO-API dataset and upsert it (throttled to once a month).")
|
|
{
|
|
forceOption,
|
|
dryRunOption,
|
|
};
|
|
syncSkins.SetAction((parseResult, ct) =>
|
|
SyncSkinsAsync(
|
|
parseResult.GetValue(forceOption),
|
|
parseResult.GetValue(dryRunOption),
|
|
loggerFactory,
|
|
ct));
|
|
|
|
var root = new RootCommand("BlueLaminate CLI — Counter-Strike skin tracker tools.")
|
|
{
|
|
syncSkins,
|
|
};
|
|
|
|
return await root.Parse(args).InvokeAsync();
|
|
|
|
// Load the CS2 skin catalogue from the CSGO-API dataset and upsert it. Weapons
|
|
// and collections are derived from the skins themselves. Throttled to once a
|
|
// month unless --force; --dry-run loads and prints without a DB.
|
|
static async Task<int> SyncSkinsAsync(
|
|
bool force, bool dryRun, ILoggerFactory loggerFactory, CancellationToken ct)
|
|
{
|
|
var logger = loggerFactory.CreateLogger("BlueLaminate.Cli.SyncSkins");
|
|
var client = new SkinCatalogClient(CreateHttpClient());
|
|
|
|
if (dryRun)
|
|
{
|
|
logger.LogInformation("Loading skin catalogue (dry run — nothing will be written).");
|
|
var skins = await client.FetchAsync(ct);
|
|
logger.LogInformation("Loaded {Count} skins.", skins.Count);
|
|
Console.WriteLine($"Loaded {skins.Count} skins (dry run, nothing written):");
|
|
foreach (var s in skins)
|
|
{
|
|
var tags = (s.StatTrakAvailable ? " ST" : "") + (s.SouvenirAvailable ? " SV" : "");
|
|
var range = s.FloatMin is not null ? $"{s.FloatMin:0.00}-{s.FloatMax:0.00}" : "—";
|
|
var sources = s.Sources.Count > 0 ? string.Join(", ", s.Sources.Select(x => x.Name)) : "—";
|
|
Console.WriteLine(
|
|
$" {s.WeaponName,-16} {s.Name,-24} {s.Rarity,-14} {range,-10} {sources}{tags}");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
using var db = new SkinTrackerDbContextFactory().CreateDbContext([]);
|
|
var service = new SkinSyncService(db, client, loggerFactory.CreateLogger<SkinSyncService>());
|
|
var result = await service.SyncAsync(force, ct);
|
|
|
|
if (result.Skipped)
|
|
{
|
|
Console.WriteLine(
|
|
$"Skipped: skins were last synced {result.LastRanAt:u}. "
|
|
+ "Next run allowed one month later — pass --force to override.");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine(
|
|
$"Synced {result.Loaded} skins: {result.Inserted} inserted, "
|
|
+ $"{result.Updated} updated, "
|
|
+ $"{result.Loaded - result.Inserted - result.Updated} unchanged "
|
|
+ $"({result.WeaponsCreated} weapons, {result.CollectionsCreated} collections created).");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static HttpClient CreateHttpClient()
|
|
{
|
|
var http = new HttpClient();
|
|
http.Timeout = TimeSpan.FromMinutes(2);
|
|
http.DefaultRequestHeaders.UserAgent.ParseAdd("BlueLaminate.Cli");
|
|
return http;
|
|
}
|