From 436519d4454dd1170734470ee081d3e7559edd09 Mon Sep 17 00:00:00 2001 From: Ryan Kistner Date: Thu, 6 Feb 2020 21:51:18 -0700 Subject: [PATCH] Split DepotDownloader configuration file into account settings stored in IsolatedStorage, and depot installation data stored in the .DepotDownloader config directory alongside cached manifests --- DepotDownloader/AccountSettingsStore.cs | 90 +++++++++++++++++++++++++ DepotDownloader/CDNClientPool.cs | 6 +- DepotDownloader/ConfigStore.cs | 70 ------------------- DepotDownloader/ContentDownloader.cs | 22 ++++-- DepotDownloader/DepotConfigStore.cs | 58 ++++++++++++++++ DepotDownloader/Program.cs | 4 +- DepotDownloader/Steam3Session.cs | 22 +++--- 7 files changed, 180 insertions(+), 92 deletions(-) create mode 100644 DepotDownloader/AccountSettingsStore.cs delete mode 100644 DepotDownloader/ConfigStore.cs create mode 100644 DepotDownloader/DepotConfigStore.cs diff --git a/DepotDownloader/AccountSettingsStore.cs b/DepotDownloader/AccountSettingsStore.cs new file mode 100644 index 00000000..b1808aed --- /dev/null +++ b/DepotDownloader/AccountSettingsStore.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using ProtoBuf; +using System.IO; +using System.IO.Compression; +using System.IO.IsolatedStorage; +using System.Linq; +using SteamKit2; +using SteamKit2.Discovery; + +namespace DepotDownloader +{ + [ProtoContract] + class AccountSettingsStore + { + [ProtoMember(1, IsRequired=false)] + public Dictionary SentryData { get; private set; } + + [ProtoMember(2, IsRequired = false)] + public System.Collections.Concurrent.ConcurrentDictionary ContentServerPenalty { get; private set; } + + [ProtoMember(3, IsRequired = false)] + public Dictionary LoginKeys { get; private set; } + + string FileName = null; + + AccountSettingsStore() + { + SentryData = new Dictionary(); + ContentServerPenalty = new System.Collections.Concurrent.ConcurrentDictionary(); + LoginKeys = new Dictionary(); + } + + static bool Loaded + { + get { return Instance != null; } + } + + public static AccountSettingsStore Instance = null; + static readonly IsolatedStorageFile IsolatedStorage = IsolatedStorageFile.GetUserStoreForAssembly(); + + public static void LoadFromFile(string filename) + { + if (Loaded) + throw new Exception("Config already loaded"); + + if (IsolatedStorage.FileExists(filename)) + { + try + { + using (var fs = IsolatedStorage.OpenFile(filename, FileMode.Open, FileAccess.Read)) + using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress)) + { + Instance = ProtoBuf.Serializer.Deserialize(ds); + } + } + catch (IOException ex) + { + Console.WriteLine("Failed to load account settings: {0}", ex.Message); + Instance = new AccountSettingsStore(); + } + } + else + { + Instance = new AccountSettingsStore(); + } + + Instance.FileName = filename; + } + + public static void Save() + { + if (!Loaded) + throw new Exception("Saved config before loading"); + + try + { + using (var fs = IsolatedStorage.OpenFile(Instance.FileName, FileMode.Open, FileAccess.Read)) + using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress)) + { + ProtoBuf.Serializer.Serialize(ds, Instance); + } + } + catch (IOException ex) + { + Console.WriteLine("Failed to save account settings: {0}", ex.Message); + } + } + } +} diff --git a/DepotDownloader/CDNClientPool.cs b/DepotDownloader/CDNClientPool.cs index 35e9c602..964a354e 100644 --- a/DepotDownloader/CDNClientPool.cs +++ b/DepotDownloader/CDNClientPool.cs @@ -90,7 +90,7 @@ namespace DepotDownloader var weightedCdnServers = servers.Select(x => { int penalty = 0; - ConfigStore.TheConfig.ContentServerPenalty.TryGetValue(x.Host, out penalty); + AccountSettingsStore.Instance.ContentServerPenalty.TryGetValue(x.Host, out penalty); return Tuple.Create(x, penalty); }).OrderBy(x => x.Item2).ThenBy(x => x.Item1.WeightedLoad); @@ -174,8 +174,8 @@ namespace DepotDownloader Console.WriteLine("Failed to connect to content server {0}: {1}", server, ex.Message); int penalty = 0; - ConfigStore.TheConfig.ContentServerPenalty.TryGetValue(server.Host, out penalty); - ConfigStore.TheConfig.ContentServerPenalty[server.Host] = penalty + 1; + AccountSettingsStore.Instance.ContentServerPenalty.TryGetValue(server.Host, out penalty); + AccountSettingsStore.Instance.ContentServerPenalty[server.Host] = penalty + 1; } } diff --git a/DepotDownloader/ConfigStore.cs b/DepotDownloader/ConfigStore.cs deleted file mode 100644 index 646c5ef7..00000000 --- a/DepotDownloader/ConfigStore.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using ProtoBuf; -using System.IO; -using System.IO.Compression; - -namespace DepotDownloader -{ - [ProtoContract] - class ConfigStore - { - [ProtoMember(1)] - public Dictionary LastManifests { get; private set; } - - [ProtoMember(3, IsRequired=false)] - public Dictionary SentryData { get; private set; } - - [ProtoMember(4, IsRequired = false)] - public System.Collections.Concurrent.ConcurrentDictionary ContentServerPenalty { get; private set; } - - [ProtoMember(5, IsRequired = false)] - public Dictionary LoginKeys { get; private set; } - - string FileName = null; - - ConfigStore() - { - LastManifests = new Dictionary(); - SentryData = new Dictionary(); - ContentServerPenalty = new System.Collections.Concurrent.ConcurrentDictionary(); - LoginKeys = new Dictionary(); - } - - static bool Loaded - { - get { return TheConfig != null; } - } - - public static ConfigStore TheConfig = null; - - public static void LoadFromFile(string filename) - { - if (Loaded) - throw new Exception("Config already loaded"); - - if (File.Exists(filename)) - { - using (FileStream fs = File.Open(filename, FileMode.Open)) - using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress)) - TheConfig = ProtoBuf.Serializer.Deserialize(ds); - } - else - { - TheConfig = new ConfigStore(); - } - - TheConfig.FileName = filename; - } - - public static void Save() - { - if (!Loaded) - throw new Exception("Saved config before loading"); - - using (FileStream fs = File.Open(TheConfig.FileName, FileMode.Create)) - using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress)) - ProtoBuf.Serializer.Serialize(ds, TheConfig); - } - } -} diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs index 40c31141..7fd9398f 100644 --- a/DepotDownloader/ContentDownloader.cs +++ b/DepotDownloader/ContentDownloader.cs @@ -339,7 +339,7 @@ namespace DepotDownloader if ( username != null && Config.RememberPassword ) { - _ = ConfigStore.TheConfig.LoginKeys.TryGetValue( username, out loginKey ); + _ = AccountSettingsStore.Instance.LoginKeys.TryGetValue( username, out loginKey ); } steam3 = new Steam3Session( @@ -395,6 +395,16 @@ namespace DepotDownloader public static async Task DownloadAppAsync( uint appId, uint depotId, ulong manifestId, string branch, string os, bool isUgc ) { + // Load our configuration data containing the depots currently installed + string configPath = ContentDownloader.Config.InstallDirectory; + if (string.IsNullOrWhiteSpace(configPath)) + { + configPath = DEFAULT_DOWNLOAD_DIR; + } + + Directory.CreateDirectory(Path.Combine(configPath, CONFIG_DIR)); + DepotConfigStore.LoadFromFile(Path.Combine(configPath, CONFIG_DIR, "depot.config")); + if ( steam3 != null ) steam3.RequestAppInfo( appId ); @@ -574,11 +584,11 @@ namespace DepotDownloader string configDir = Path.Combine( depot.installDir, CONFIG_DIR ); ulong lastManifestId = INVALID_MANIFEST_ID; - ConfigStore.TheConfig.LastManifests.TryGetValue( depot.id, out lastManifestId ); + DepotConfigStore.Instance.InstalledManifestIDs.TryGetValue( depot.id, out lastManifestId ); // In case we have an early exit, this will force equiv of verifyall next run. - ConfigStore.TheConfig.LastManifests[ depot.id ] = INVALID_MANIFEST_ID; - ConfigStore.Save(); + DepotConfigStore.Instance.InstalledManifestIDs[ depot.id ] = INVALID_MANIFEST_ID; + DepotConfigStore.Save(); if ( lastManifestId != INVALID_MANIFEST_ID ) { @@ -971,8 +981,8 @@ namespace DepotDownloader await Task.WhenAll( tasks ).ConfigureAwait( false ); - ConfigStore.TheConfig.LastManifests[ depot.id ] = depot.manifestId; - ConfigStore.Save(); + DepotConfigStore.Instance.InstalledManifestIDs[ depot.id ] = depot.manifestId; + DepotConfigStore.Save(); Console.WriteLine( "Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.id, DepotBytesCompressed, DepotBytesUncompressed ); } diff --git a/DepotDownloader/DepotConfigStore.cs b/DepotDownloader/DepotConfigStore.cs new file mode 100644 index 00000000..79a414ab --- /dev/null +++ b/DepotDownloader/DepotConfigStore.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using ProtoBuf; +using System.IO; +using System.IO.Compression; + +namespace DepotDownloader +{ + [ProtoContract] + class DepotConfigStore + { + [ProtoMember(1)] + public Dictionary InstalledManifestIDs { get; private set; } + + string FileName = null; + + DepotConfigStore() + { + InstalledManifestIDs = new Dictionary(); + } + + static bool Loaded + { + get { return Instance != null; } + } + + public static DepotConfigStore Instance = null; + + public static void LoadFromFile(string filename) + { + if (Loaded) + throw new Exception("Config already loaded"); + + if (File.Exists(filename)) + { + using (FileStream fs = File.Open(filename, FileMode.Open)) + using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress)) + Instance = ProtoBuf.Serializer.Deserialize(ds); + } + else + { + Instance = new DepotConfigStore(); + } + + Instance.FileName = filename; + } + + public static void Save() + { + if (!Loaded) + throw new Exception("Saved config before loading"); + + using (FileStream fs = File.Open(Instance.FileName, FileMode.Create)) + using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress)) + ProtoBuf.Serializer.Serialize(ds, Instance); + } + } +} diff --git a/DepotDownloader/Program.cs b/DepotDownloader/Program.cs index 2126ebad..26d15e99 100644 --- a/DepotDownloader/Program.cs +++ b/DepotDownloader/Program.cs @@ -23,7 +23,7 @@ namespace DepotDownloader DebugLog.Enabled = false; - ConfigStore.LoadFromFile( Path.Combine( Directory.GetCurrentDirectory(), "DepotDownloader.config" ) ); + AccountSettingsStore.LoadFromFile( "account.config" ); #region Common Options @@ -191,7 +191,7 @@ namespace DepotDownloader static bool InitializeSteam( string username, string password ) { - if ( username != null && password == null && ( !ContentDownloader.Config.RememberPassword || !ConfigStore.TheConfig.LoginKeys.ContainsKey( username ) ) ) + if ( username != null && password == null && ( !ContentDownloader.Config.RememberPassword || !AccountSettingsStore.Instance.LoginKeys.ContainsKey( username ) ) ) { do { diff --git a/DepotDownloader/Steam3Session.cs b/DepotDownloader/Steam3Session.cs index f7e85554..7dfb82f0 100644 --- a/DepotDownloader/Steam3Session.cs +++ b/DepotDownloader/Steam3Session.cs @@ -105,16 +105,16 @@ namespace DepotDownloader if ( authenticatedUser ) { FileInfo fi = new FileInfo( String.Format( "{0}.sentryFile", logonDetails.Username ) ); - if ( ConfigStore.TheConfig.SentryData != null && ConfigStore.TheConfig.SentryData.ContainsKey( logonDetails.Username ) ) + if ( AccountSettingsStore.Instance.SentryData != null && AccountSettingsStore.Instance.SentryData.ContainsKey( logonDetails.Username ) ) { - logonDetails.SentryFileHash = Util.SHAHash( ConfigStore.TheConfig.SentryData[ logonDetails.Username ] ); + logonDetails.SentryFileHash = Util.SHAHash( AccountSettingsStore.Instance.SentryData[ logonDetails.Username ] ); } else if ( fi.Exists && fi.Length > 0 ) { var sentryData = File.ReadAllBytes( fi.FullName ); logonDetails.SentryFileHash = Util.SHAHash( sentryData ); - ConfigStore.TheConfig.SentryData[ logonDetails.Username ] = sentryData; - ConfigStore.Save(); + AccountSettingsStore.Instance.SentryData[ logonDetails.Username ] = sentryData; + AccountSettingsStore.Save(); } } @@ -454,7 +454,7 @@ namespace DepotDownloader DateTime now = new DateTime(); if ( now >= waitUntil ) break; - if ( ConfigStore.TheConfig.LoginKeys.ContainsKey( logonDetails.Username ) ) break; + if ( AccountSettingsStore.Instance.LoginKeys.ContainsKey( logonDetails.Username ) ) break; callbacks.RunWaitAllCallbacks( TimeSpan.FromMilliseconds( 100 ) ); } @@ -544,8 +544,8 @@ namespace DepotDownloader } else if ( isLoginKey ) { - ConfigStore.TheConfig.LoginKeys.Remove( logonDetails.Username ); - ConfigStore.Save(); + AccountSettingsStore.Instance.LoginKeys.Remove( logonDetails.Username ); + AccountSettingsStore.Save(); logonDetails.LoginKey = null; @@ -623,8 +623,8 @@ namespace DepotDownloader byte[] hash = Util.SHAHash( machineAuth.Data ); Console.WriteLine( "Got Machine Auth: {0} {1} {2} {3}", machineAuth.FileName, machineAuth.Offset, machineAuth.BytesToWrite, machineAuth.Data.Length, hash ); - ConfigStore.TheConfig.SentryData[ logonDetails.Username ] = machineAuth.Data; - ConfigStore.Save(); + AccountSettingsStore.Instance.SentryData[ logonDetails.Username ] = machineAuth.Data; + AccountSettingsStore.Save(); var authResponse = new SteamUser.MachineAuthDetails { @@ -651,8 +651,8 @@ namespace DepotDownloader { Console.WriteLine( "Accepted new login key for account {0}", logonDetails.Username ); - ConfigStore.TheConfig.LoginKeys[ logonDetails.Username ] = loginKey.LoginKey; - ConfigStore.Save(); + AccountSettingsStore.Instance.LoginKeys[ logonDetails.Username ] = loginKey.LoginKey; + AccountSettingsStore.Save(); steamUser.AcceptNewLoginKey( loginKey ); }