From 14a9c923049a5581da0a026a2f0e2bba11c6942d Mon Sep 17 00:00:00 2001 From: Westin Miller Date: Fri, 18 Oct 2024 13:27:14 -0700 Subject: [PATCH] Don't reuse steam client --- .github/workflows/dotnet.yml | 2 +- SchemaBuilder/GameManager.cs | 51 +++++++++++++++++++++-------------- SchemaBuilder/Program.cs | 3 ++- SteamUtils/SteamDownloader.cs | 35 +++++++++++++++--------- 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index d317dcc..0dc486c 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -42,7 +42,7 @@ jobs: # Restore game cache keys. - name: Generate game cache key id: game_cache_key - run: powershell -Command echo "key=game-cache-v3-$(Get-Date -Format yyyy-MM)" >> $env:GITHUB_OUTPUT + run: powershell -Command echo "key=game-cache-v4-$(Get-Date -Format yyyy-MM)" >> $env:GITHUB_OUTPUT - name: Cache Game Binaries uses: actions/cache@v3 with: diff --git a/SchemaBuilder/GameManager.cs b/SchemaBuilder/GameManager.cs index 4523006..e6dec56 100644 --- a/SchemaBuilder/GameManager.cs +++ b/SchemaBuilder/GameManager.cs @@ -14,27 +14,17 @@ namespace SchemaBuilder { public class GameManager : IHostedService { - // Data files required for definition loading. - private static readonly string[] DataFileExtensions = { ".mwm", ".sbc", ".resx", ".xml" }; - - private static bool IsDataFile(string path) - { - foreach (var ext in DataFileExtensions) - if (path.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) - return true; - return false; - } - private const bool Skip = false; - private readonly SteamDownloader _steamInternal; + private readonly Func _steamFactory; + private SteamDownloader _steamInternal; private readonly ILogger _log; private readonly string _rootDir; - public GameManager(SteamDownloader steam, ILogger log) + public GameManager(Func steamFactory, ILogger log) { - _steamInternal = steam; + _steamFactory = steamFactory; _log = log; _rootDir = Path.GetFullPath("./"); } @@ -49,7 +39,7 @@ public async Task RestoreGame(Game game, string branch) var installDir = Path.Combine(_rootDir, "game", game.ToString(), branch); if (!Skip) await RunWithRetry(steam => steam.InstallAppAsync(info.SteamDedicatedAppId, info.SteamDedicatedDepotId, branch, installDir, - path => path.StartsWith(BinariesDir) || IsDataFile(path), game.ToString())); + path => path.StartsWith(BinariesDir), game.ToString())); return new GameInstall(this, _log, game, Path.Combine(installDir, ContentDir), Path.Combine(installDir, BinariesDir)); } @@ -121,8 +111,7 @@ public async Task RestoreMod(Game game, PublishedFileDetails details) if (!Skip) await RunWithRetry(steam => steam.InstallModAsync(info.SteamGameAppId, details.publishedfileid, installDir, path => path.IndexOf("Data/Scripts", StringComparison.OrdinalIgnoreCase) >= 0 - || path.IndexOf("Data\\Scripts", StringComparison.OrdinalIgnoreCase) >= 0 - || IsDataFile(path), + || path.IndexOf("Data\\Scripts", StringComparison.OrdinalIgnoreCase) >= 0, $"{game}-{details.publishedfileid}-{details.title}")); return installDir; } @@ -134,18 +123,40 @@ private async Task RunWithRetry(Func> action) { try { + if (_steamInternal == null) + { + _steamInternal = _steamFactory(); + await _steamInternal.LoginAsync(); + } return await action(_steamInternal); } - catch + catch (Exception ex) { + _log.LogInformation(ex, "Failed to run task"); if (attempt >= 5) throw; - await Task.Delay(TimeSpan.FromSeconds(10 * Math.Pow(2, attempt))); + // await Task.Delay(TimeSpan.FromSeconds(10 * Math.Pow(2, attempt))); attempt++; } + finally + { + if (_steamInternal is { IsLoggedIn: false }) + { + try + { + await _steamInternal.LogoutAsync(); + } + catch (Exception e) + { + _log.LogWarning(e, $"Failed to logout"); + } + + _steamInternal = null; + } + } } } - public Task StartAsync(CancellationToken cancellationToken) => RunWithRetry(steam => steam.LoginAsync()); + public Task StartAsync(CancellationToken cancellationToken) => RunWithRetry(_ => Task.FromResult(0)); public Task StopAsync(CancellationToken cancellationToken) => RunWithRetry(async steam => { diff --git a/SchemaBuilder/Program.cs b/SchemaBuilder/Program.cs index 546402f..bffc8aa 100644 --- a/SchemaBuilder/Program.cs +++ b/SchemaBuilder/Program.cs @@ -4,6 +4,7 @@ using SchemaBuilder.Schema; using SchemaService.SteamUtils; using SteamKit2; +using SteamKit2.Discovery; namespace SchemaBuilder { @@ -14,7 +15,7 @@ public static async Task Main(string[] args) using var host = new HostBuilder() .ConfigureServices(svc => { - svc.AddSteamDownloader(SteamConfiguration.Create(x => { })); + svc.AddSteamDownloader(SteamConfiguration.Create(x => x.WithServerListProvider(new MemoryServerListProvider()))); svc.AddSingleton(); svc.AddHostedService(); svc.AddSingleton(); diff --git a/SteamUtils/SteamDownloader.cs b/SteamUtils/SteamDownloader.cs index 8942b4f..7246622 100644 --- a/SteamUtils/SteamDownloader.cs +++ b/SteamUtils/SteamDownloader.cs @@ -20,12 +20,11 @@ namespace SchemaService.SteamUtils { public static class SteamDownloaderFactory { - public static void AddSteamDownloader(this IServiceCollection collection, SteamConfiguration config) + private class SteamDebugLogSetup { - var categoryCleaner = new Regex("^[0-9a-f]+/"); - collection.AddSingleton(svc => + public SteamDebugLogSetup(ILoggerFactory logFactory) { - var logFactory = svc.GetRequiredService(); + var categoryCleaner = new Regex("^[0-9a-f]+/"); DebugLog.ClearListeners(); DebugLog.AddListener((category, msg) => { @@ -40,10 +39,20 @@ public static void AddSteamDownloader(this IServiceCollection collection, SteamC } }); DebugLog.Enabled = true; - return new SteamClient(config); + } + } + + public static void AddSteamDownloader(this IServiceCollection collection, SteamConfiguration config) + { + collection.AddSingleton(); + collection.AddSingleton(config); + collection.AddSingleton>(svc => + { + var log = svc.GetRequiredService(); + var cfg = svc.GetRequiredService(); + svc.GetRequiredService(); + return () => new SteamDownloader(log, cfg); }); - collection.AddSingleton(); - collection.AddSingleton(); } } @@ -72,20 +81,20 @@ public class SteamDownloader private readonly ILogger _log; - private bool IsLoggedIn => _loginDetails != null; + public bool IsLoggedIn => _loginDetails != null; public CdnPool CdnPool { get; } - public SteamDownloader(ILogger log, SteamClient client, CdnPool cdnPool) + public SteamDownloader(ILoggerFactory log, SteamConfiguration config) { - _log = log; - _client = client; + _log = log.CreateLogger(); + _client = new SteamClient(config); _user = _client.GetHandler(); _apps = _client.GetHandler(); _cloud = _client.GetHandler(); _content = _client.GetHandler(); _unifiedMessages = _client.GetHandler(); _publishedFiles = _unifiedMessages.CreateService(); - CdnPool = cdnPool; + CdnPool = new CdnPool(log.CreateLogger(), _client); _callbacks = new CallbackPump(_client); @@ -193,7 +202,7 @@ public async Task LoginAsync(LogOnDetails details = default) .WaitForAsync(x => x is ConnectedCallback || x is DisconnectedCallback); if (connectResult is DisconnectedCallback) - throw new Exception("Failed to connect to Steam."); + throw new Exception("Failed to connect to Steam"); if (details == null) _user.LogOnAnonymous();