Merge pull request #474 from SteamRE/cleanup

Cleanup
pull/484/head
Pavel Djundik 2 years ago committed by GitHub
commit 9d2446404a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -29,8 +29,8 @@ namespace DepotDownloader
AccountSettingsStore() AccountSettingsStore()
{ {
ContentServerPenalty = new ConcurrentDictionary<string, int>(); ContentServerPenalty = new ConcurrentDictionary<string, int>();
LoginTokens = new Dictionary<string, string>(); LoginTokens = [];
GuardData = new Dictionary<string, string>(); GuardData = [];
} }
static bool Loaded static bool Loaded
@ -50,12 +50,10 @@ namespace DepotDownloader
{ {
try try
{ {
using (var fs = IsolatedStorage.OpenFile(filename, FileMode.Open, FileAccess.Read)) using var fs = IsolatedStorage.OpenFile(filename, FileMode.Open, FileAccess.Read);
using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) using var ds = new DeflateStream(fs, CompressionMode.Decompress);
{
Instance = Serializer.Deserialize<AccountSettingsStore>(ds); Instance = Serializer.Deserialize<AccountSettingsStore>(ds);
} }
}
catch (IOException ex) catch (IOException ex)
{ {
Console.WriteLine("Failed to load account settings: {0}", ex.Message); Console.WriteLine("Failed to load account settings: {0}", ex.Message);
@ -77,12 +75,10 @@ namespace DepotDownloader
try try
{ {
using (var fs = IsolatedStorage.OpenFile(Instance.FileName, FileMode.Create, FileAccess.Write)) using var fs = IsolatedStorage.OpenFile(Instance.FileName, FileMode.Create, FileAccess.Write);
using (var ds = new DeflateStream(fs, CompressionMode.Compress)) using var ds = new DeflateStream(fs, CompressionMode.Compress);
{
Serializer.Serialize(ds, Instance); Serializer.Serialize(ds, Instance);
} }
}
catch (IOException ex) catch (IOException ex)
{ {
Console.WriteLine("Failed to save account settings: {0}", ex.Message); Console.WriteLine("Failed to save account settings: {0}", ex.Message);

@ -20,12 +20,12 @@ namespace DepotDownloader
public Client CDNClient { get; } public Client CDNClient { get; }
public Server ProxyServer { get; private set; } public Server ProxyServer { get; private set; }
private readonly ConcurrentStack<Server> activeConnectionPool; private readonly ConcurrentStack<Server> activeConnectionPool = [];
private readonly BlockingCollection<Server> availableServerEndpoints; private readonly BlockingCollection<Server> availableServerEndpoints = [];
private readonly AutoResetEvent populatePoolEvent; private readonly AutoResetEvent populatePoolEvent = new(true);
private readonly Task monitorTask; private readonly Task monitorTask;
private readonly CancellationTokenSource shutdownToken; private readonly CancellationTokenSource shutdownToken = new();
public CancellationTokenSource ExhaustedToken { get; set; } public CancellationTokenSource ExhaustedToken { get; set; }
public CDNClientPool(Steam3Session steamSession, uint appId) public CDNClientPool(Steam3Session steamSession, uint appId)
@ -34,12 +34,6 @@ namespace DepotDownloader
this.appId = appId; this.appId = appId;
CDNClient = new Client(steamSession.steamClient); CDNClient = new Client(steamSession.steamClient);
activeConnectionPool = new ConcurrentStack<Server>();
availableServerEndpoints = new BlockingCollection<Server>();
populatePoolEvent = new AutoResetEvent(true);
shutdownToken = new CancellationTokenSource();
monitorTask = Task.Factory.StartNew(ConnectionPoolMonitorAsync).Unwrap(); monitorTask = Task.Factory.StartNew(ConnectionPoolMonitorAsync).Unwrap();
} }

@ -11,9 +11,8 @@ using SteamKit2.CDN;
namespace DepotDownloader namespace DepotDownloader
{ {
class ContentDownloaderException : Exception class ContentDownloaderException(string value) : Exception(value)
{ {
public ContentDownloaderException(String value) : base(value) { }
} }
static class ContentDownloader static class ContentDownloader
@ -23,38 +22,25 @@ namespace DepotDownloader
public const ulong INVALID_MANIFEST_ID = ulong.MaxValue; public const ulong INVALID_MANIFEST_ID = ulong.MaxValue;
public const string DEFAULT_BRANCH = "public"; public const string DEFAULT_BRANCH = "public";
public static DownloadConfig Config = new DownloadConfig(); public static DownloadConfig Config = new();
private static Steam3Session steam3; private static Steam3Session steam3;
private static Steam3Session.Credentials steam3Credentials;
private static CDNClientPool cdnPool; private static CDNClientPool cdnPool;
private const string DEFAULT_DOWNLOAD_DIR = "depots"; private const string DEFAULT_DOWNLOAD_DIR = "depots";
private const string CONFIG_DIR = ".DepotDownloader"; private const string CONFIG_DIR = ".DepotDownloader";
private static readonly string STAGING_DIR = Path.Combine(CONFIG_DIR, "staging"); private static readonly string STAGING_DIR = Path.Combine(CONFIG_DIR, "staging");
private sealed class DepotDownloadInfo private sealed class DepotDownloadInfo(
{
public uint id { get; private set; }
public uint appId { get; private set; }
public ulong manifestId { get; private set; }
public string branch { get; private set; }
public string installDir { get; private set; }
public byte[] depotKey { get; private set; }
public DepotDownloadInfo(
uint depotid, uint appId, ulong manifestId, string branch, uint depotid, uint appId, ulong manifestId, string branch,
string installDir, byte[] depotKey) string installDir, byte[] depotKey)
{ {
this.id = depotid; public uint DepotId { get; } = depotid;
this.appId = appId; public uint AppId { get; } = appId;
this.manifestId = manifestId; public ulong ManifestId { get; } = manifestId;
this.branch = branch; public string Branch { get; } = branch;
this.installDir = installDir; public string InstallDir { get; } = installDir;
this.depotKey = depotKey; public byte[] DepotKey { get; } = depotKey;
}
} }
static bool CreateDirectories(uint depotId, uint depotVersion, out string installDir) static bool CreateDirectories(uint depotId, uint depotVersion, out string installDir)
@ -135,8 +121,7 @@ namespace DepotDownloader
foreach (var license in licenseQuery) foreach (var license in licenseQuery)
{ {
SteamApps.PICSProductInfoCallback.PICSProductInfo package; if (steam3.PackageInfo.TryGetValue(license, out var package) && package != null)
if (steam3.PackageInfo.TryGetValue(license, out package) && package != null)
{ {
if (package.KeyValues["appids"].Children.Any(child => child.AsUnsignedInteger() == depotId)) if (package.KeyValues["appids"].Children.Any(child => child.AsUnsignedInteger() == depotId))
return true; return true;
@ -156,33 +141,20 @@ namespace DepotDownloader
return null; return null;
} }
SteamApps.PICSProductInfoCallback.PICSProductInfo app; if (!steam3.AppInfo.TryGetValue(appId, out var app) || app == null)
if (!steam3.AppInfo.TryGetValue(appId, out app) || app == null)
{ {
return null; return null;
} }
var appinfo = app.KeyValues; var appinfo = app.KeyValues;
string section_key; var section_key = section switch
switch (section)
{ {
case EAppInfoSection.Common: EAppInfoSection.Common => "common",
section_key = "common"; EAppInfoSection.Extended => "extended",
break; EAppInfoSection.Config => "config",
case EAppInfoSection.Extended: EAppInfoSection.Depots => "depots",
section_key = "extended"; _ => throw new NotImplementedException(),
break; };
case EAppInfoSection.Config:
section_key = "config";
break;
case EAppInfoSection.Depots:
section_key = "depots";
break;
default:
throw new NotImplementedException();
}
var section_kv = appinfo.Children.Where(c => c.Name == section_key).FirstOrDefault(); var section_kv = appinfo.Children.Where(c => c.Name == section_key).FirstOrDefault();
return section_kv; return section_kv;
} }
@ -262,7 +234,7 @@ namespace DepotDownloader
// Submit the password to Steam now to get encryption keys // Submit the password to Steam now to get encryption keys
steam3.CheckAppBetaPassword(appId, Config.BetaPassword); steam3.CheckAppBetaPassword(appId, Config.BetaPassword);
if (!steam3.AppBetaPasswords.ContainsKey(branch)) if (!steam3.AppBetaPasswords.TryGetValue(branch, out var appBetaPassword))
{ {
Console.WriteLine("Password was invalid for branch {0}", branch); Console.WriteLine("Password was invalid for branch {0}", branch);
return INVALID_MANIFEST_ID; return INVALID_MANIFEST_ID;
@ -272,7 +244,7 @@ namespace DepotDownloader
byte[] manifest_bytes; byte[] manifest_bytes;
try try
{ {
manifest_bytes = CryptoHelper.SymmetricDecryptECB(input, steam3.AppBetaPasswords[branch]); manifest_bytes = CryptoHelper.SymmetricDecryptECB(input, appBetaPassword);
} }
catch (Exception e) catch (Exception e)
{ {
@ -293,14 +265,14 @@ namespace DepotDownloader
if (node.Value == null) if (node.Value == null)
return INVALID_MANIFEST_ID; return INVALID_MANIFEST_ID;
return UInt64.Parse(node.Value); return ulong.Parse(node.Value);
} }
static string GetAppName(uint appId) static string GetAppName(uint appId)
{ {
var info = GetSteam3AppSection(appId, EAppInfoSection.Common); var info = GetSteam3AppSection(appId, EAppInfoSection.Common);
if (info == null) if (info == null)
return String.Empty; return string.Empty;
return info["name"].AsString(); return info["name"].AsString();
} }
@ -325,9 +297,7 @@ namespace DepotDownloader
} }
); );
steam3Credentials = steam3.WaitForCredentials(); if (!steam3.WaitForCredentials())
if (!steam3Credentials.IsValid)
{ {
Console.WriteLine("Unable to get steam3 credentials."); Console.WriteLine("Unable to get steam3 credentials.");
return false; return false;
@ -393,8 +363,7 @@ namespace DepotDownloader
private static async Task DownloadWebFile(uint appId, string fileName, string url) private static async Task DownloadWebFile(uint appId, string fileName, string url)
{ {
string installDir; if (!CreateDirectories(appId, 0, out var installDir))
if (!CreateDirectories(appId, 0, out installDir))
{ {
Console.WriteLine("Error: Unable to create install directories!"); Console.WriteLine("Error: Unable to create install directories!");
return; return;
@ -437,8 +406,7 @@ namespace DepotDownloader
Directory.CreateDirectory(Path.Combine(configPath, CONFIG_DIR)); Directory.CreateDirectory(Path.Combine(configPath, CONFIG_DIR));
DepotConfigStore.LoadFromFile(Path.Combine(configPath, CONFIG_DIR, "depot.config")); DepotConfigStore.LoadFromFile(Path.Combine(configPath, CONFIG_DIR, "depot.config"));
if (steam3 != null) steam3?.RequestAppInfo(appId);
steam3.RequestAppInfo(appId);
if (!AccountHasAccess(appId)) if (!AccountHasAccess(appId))
{ {
@ -452,13 +420,13 @@ namespace DepotDownloader
else else
{ {
var contentName = GetAppName(appId); var contentName = GetAppName(appId);
throw new ContentDownloaderException(String.Format("App {0} ({1}) is not available from this account.", appId, contentName)); throw new ContentDownloaderException(string.Format("App {0} ({1}) is not available from this account.", appId, contentName));
} }
} }
var hasSpecificDepots = depotManifestIds.Count > 0; var hasSpecificDepots = depotManifestIds.Count > 0;
var depotIdsFound = new List<uint>(); var depotIdsFound = new List<uint>();
var depotIdsExpected = depotManifestIds.Select(x => x.Item1).ToList(); var depotIdsExpected = depotManifestIds.Select(x => x.depotId).ToList();
var depots = GetSteam3AppSection(appId, EAppInfoSection.Depots); var depots = GetSteam3AppSection(appId, EAppInfoSection.Depots);
if (isUgc) if (isUgc)
@ -537,21 +505,21 @@ namespace DepotDownloader
if (depotManifestIds.Count == 0 && !hasSpecificDepots) if (depotManifestIds.Count == 0 && !hasSpecificDepots)
{ {
throw new ContentDownloaderException(String.Format("Couldn't find any depots to download for app {0}", appId)); throw new ContentDownloaderException(string.Format("Couldn't find any depots to download for app {0}", appId));
} }
if (depotIdsFound.Count < depotIdsExpected.Count) if (depotIdsFound.Count < depotIdsExpected.Count)
{ {
var remainingDepotIds = depotIdsExpected.Except(depotIdsFound); var remainingDepotIds = depotIdsExpected.Except(depotIdsFound);
throw new ContentDownloaderException(String.Format("Depot {0} not listed for app {1}", string.Join(", ", remainingDepotIds), appId)); throw new ContentDownloaderException(string.Format("Depot {0} not listed for app {1}", string.Join(", ", remainingDepotIds), appId));
} }
} }
var infos = new List<DepotDownloadInfo>(); var infos = new List<DepotDownloadInfo>();
foreach (var depotManifest in depotManifestIds) foreach (var (depotId, manifestId) in depotManifestIds)
{ {
var info = GetDepotInfo(depotManifest.Item1, appId, depotManifest.Item2, branch); var info = GetDepotInfo(depotId, appId, manifestId, branch);
if (info != null) if (info != null)
{ {
infos.Add(info); infos.Add(info);
@ -560,7 +528,7 @@ namespace DepotDownloader
try try
{ {
await DownloadSteam3Async(appId, infos).ConfigureAwait(false); await DownloadSteam3Async(infos).ConfigureAwait(false);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -599,7 +567,7 @@ namespace DepotDownloader
} }
steam3.RequestDepotKey(depotId, appId); steam3.RequestDepotKey(depotId, appId);
if (!steam3.DepotKeys.ContainsKey(depotId)) if (!steam3.DepotKeys.TryGetValue(depotId, out var depotKey))
{ {
Console.WriteLine("No valid depot key for {0}, unable to download.", depotId); Console.WriteLine("No valid depot key for {0}, unable to download.", depotId);
return null; return null;
@ -607,28 +575,19 @@ namespace DepotDownloader
var uVersion = GetSteam3AppBuildNumber(appId, branch); var uVersion = GetSteam3AppBuildNumber(appId, branch);
string installDir; if (!CreateDirectories(depotId, uVersion, out var installDir))
if (!CreateDirectories(depotId, uVersion, out installDir))
{ {
Console.WriteLine("Error: Unable to create install directories!"); Console.WriteLine("Error: Unable to create install directories!");
return null; return null;
} }
var depotKey = steam3.DepotKeys[depotId];
return new DepotDownloadInfo(depotId, appId, manifestId, branch, installDir, depotKey); return new DepotDownloadInfo(depotId, appId, manifestId, branch, installDir, depotKey);
} }
private class ChunkMatch private class ChunkMatch(ProtoManifest.ChunkData oldChunk, ProtoManifest.ChunkData newChunk)
{
public ChunkMatch(ProtoManifest.ChunkData oldChunk, ProtoManifest.ChunkData newChunk)
{ {
OldChunk = oldChunk; public ProtoManifest.ChunkData OldChunk { get; } = oldChunk;
NewChunk = newChunk; public ProtoManifest.ChunkData NewChunk { get; } = newChunk;
}
public ProtoManifest.ChunkData OldChunk { get; private set; }
public ProtoManifest.ChunkData NewChunk { get; private set; }
} }
private class DepotFilesData private class DepotFilesData
@ -663,19 +622,19 @@ namespace DepotDownloader
public ulong DepotBytesUncompressed; public ulong DepotBytesUncompressed;
} }
private static async Task DownloadSteam3Async(uint appId, List<DepotDownloadInfo> depots) private static async Task DownloadSteam3Async(List<DepotDownloadInfo> depots)
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
cdnPool.ExhaustedToken = cts; cdnPool.ExhaustedToken = cts;
var downloadCounter = new GlobalDownloadCounter(); var downloadCounter = new GlobalDownloadCounter();
var depotsToDownload = new List<DepotFilesData>(depots.Count); var depotsToDownload = new List<DepotFilesData>(depots.Count);
var allFileNamesAllDepots = new HashSet<String>(); var allFileNamesAllDepots = new HashSet<string>();
// First, fetch all the manifests for each depot (including previous manifests) and perform the initial setup // First, fetch all the manifests for each depot (including previous manifests) and perform the initial setup
foreach (var depot in depots) foreach (var depot in depots)
{ {
var depotFileData = await ProcessDepotManifestAndFiles(cts, appId, depot); var depotFileData = await ProcessDepotManifestAndFiles(cts, depot);
if (depotFileData != null) if (depotFileData != null)
{ {
@ -690,7 +649,7 @@ namespace DepotDownloader
// This is in last-depot-wins order, from Steam or the list of depots supplied by the user // This is in last-depot-wins order, from Steam or the list of depots supplied by the user
if (!string.IsNullOrWhiteSpace(Config.InstallDirectory) && depotsToDownload.Count > 0) if (!string.IsNullOrWhiteSpace(Config.InstallDirectory) && depotsToDownload.Count > 0)
{ {
var claimedFileNames = new HashSet<String>(); var claimedFileNames = new HashSet<string>();
for (var i = depotsToDownload.Count - 1; i >= 0; i--) for (var i = depotsToDownload.Count - 1; i >= 0; i--)
{ {
@ -703,38 +662,37 @@ namespace DepotDownloader
foreach (var depotFileData in depotsToDownload) foreach (var depotFileData in depotsToDownload)
{ {
await DownloadSteam3AsyncDepotFiles(cts, appId, downloadCounter, depotFileData, allFileNamesAllDepots); await DownloadSteam3AsyncDepotFiles(cts, downloadCounter, depotFileData, allFileNamesAllDepots);
} }
Console.WriteLine("Total downloaded: {0} bytes ({1} bytes uncompressed) from {2} depots", Console.WriteLine("Total downloaded: {0} bytes ({1} bytes uncompressed) from {2} depots",
downloadCounter.TotalBytesCompressed, downloadCounter.TotalBytesUncompressed, depots.Count); downloadCounter.TotalBytesCompressed, downloadCounter.TotalBytesUncompressed, depots.Count);
} }
private static async Task<DepotFilesData> ProcessDepotManifestAndFiles(CancellationTokenSource cts, private static async Task<DepotFilesData> ProcessDepotManifestAndFiles(CancellationTokenSource cts, DepotDownloadInfo depot)
uint appId, DepotDownloadInfo depot)
{ {
var depotCounter = new DepotDownloadCounter(); var depotCounter = new DepotDownloadCounter();
Console.WriteLine("Processing depot {0}", depot.id); Console.WriteLine("Processing depot {0}", depot.DepotId);
ProtoManifest oldProtoManifest = null; ProtoManifest oldProtoManifest = null;
ProtoManifest newProtoManifest = null; ProtoManifest newProtoManifest = null;
var configDir = Path.Combine(depot.installDir, CONFIG_DIR); var configDir = Path.Combine(depot.InstallDir, CONFIG_DIR);
var lastManifestId = INVALID_MANIFEST_ID; var lastManifestId = INVALID_MANIFEST_ID;
DepotConfigStore.Instance.InstalledManifestIDs.TryGetValue(depot.id, out lastManifestId); DepotConfigStore.Instance.InstalledManifestIDs.TryGetValue(depot.DepotId, out lastManifestId);
// In case we have an early exit, this will force equiv of verifyall next run. // In case we have an early exit, this will force equiv of verifyall next run.
DepotConfigStore.Instance.InstalledManifestIDs[depot.id] = INVALID_MANIFEST_ID; DepotConfigStore.Instance.InstalledManifestIDs[depot.DepotId] = INVALID_MANIFEST_ID;
DepotConfigStore.Save(); DepotConfigStore.Save();
if (lastManifestId != INVALID_MANIFEST_ID) if (lastManifestId != INVALID_MANIFEST_ID)
{ {
var oldManifestFileName = Path.Combine(configDir, string.Format("{0}_{1}.bin", depot.id, lastManifestId)); var oldManifestFileName = Path.Combine(configDir, string.Format("{0}_{1}.bin", depot.DepotId, lastManifestId));
if (File.Exists(oldManifestFileName)) if (File.Exists(oldManifestFileName))
{ {
byte[] expectedChecksum, currentChecksum; byte[] expectedChecksum;
try try
{ {
@ -745,29 +703,29 @@ namespace DepotDownloader
expectedChecksum = null; expectedChecksum = null;
} }
oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName, out currentChecksum); oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName, out var currentChecksum);
if (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum)) if (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum))
{ {
// We only have to show this warning if the old manifest ID was different // We only have to show this warning if the old manifest ID was different
if (lastManifestId != depot.manifestId) if (lastManifestId != depot.ManifestId)
Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", lastManifestId); Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", lastManifestId);
oldProtoManifest = null; oldProtoManifest = null;
} }
} }
} }
if (lastManifestId == depot.manifestId && oldProtoManifest != null) if (lastManifestId == depot.ManifestId && oldProtoManifest != null)
{ {
newProtoManifest = oldProtoManifest; newProtoManifest = oldProtoManifest;
Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id); Console.WriteLine("Already have manifest {0} for depot {1}.", depot.ManifestId, depot.DepotId);
} }
else else
{ {
var newManifestFileName = Path.Combine(configDir, string.Format("{0}_{1}.bin", depot.id, depot.manifestId)); var newManifestFileName = Path.Combine(configDir, string.Format("{0}_{1}.bin", depot.DepotId, depot.ManifestId));
if (newManifestFileName != null) if (newManifestFileName != null)
{ {
byte[] expectedChecksum, currentChecksum; byte[] expectedChecksum;
try try
{ {
@ -778,18 +736,18 @@ namespace DepotDownloader
expectedChecksum = null; expectedChecksum = null;
} }
newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName, out currentChecksum); newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName, out var currentChecksum);
if (newProtoManifest != null && (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum))) if (newProtoManifest != null && (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum)))
{ {
Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", depot.manifestId); Console.WriteLine("Manifest {0} on disk did not match the expected checksum.", depot.ManifestId);
newProtoManifest = null; newProtoManifest = null;
} }
} }
if (newProtoManifest != null) if (newProtoManifest != null)
{ {
Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id); Console.WriteLine("Already have manifest {0} for depot {1}.", depot.ManifestId, depot.DepotId);
} }
else else
{ {
@ -816,39 +774,39 @@ namespace DepotDownloader
if (manifestRequestCode == 0 || now >= manifestRequestCodeExpiration) if (manifestRequestCode == 0 || now >= manifestRequestCodeExpiration)
{ {
manifestRequestCode = await steam3.GetDepotManifestRequestCodeAsync( manifestRequestCode = await steam3.GetDepotManifestRequestCodeAsync(
depot.id, depot.DepotId,
depot.appId, depot.AppId,
depot.manifestId, depot.ManifestId,
depot.branch); depot.Branch);
// This code will hopefully be valid for one period following the issuing period // This code will hopefully be valid for one period following the issuing period
manifestRequestCodeExpiration = now.Add(TimeSpan.FromMinutes(5)); manifestRequestCodeExpiration = now.Add(TimeSpan.FromMinutes(5));
// If we could not get the manifest code, this is a fatal error // If we could not get the manifest code, this is a fatal error
if (manifestRequestCode == 0) if (manifestRequestCode == 0)
{ {
Console.WriteLine("No manifest request code was returned for {0} {1}", depot.id, depot.manifestId); Console.WriteLine("No manifest request code was returned for {0} {1}", depot.DepotId, depot.ManifestId);
cts.Cancel(); cts.Cancel();
} }
} }
DebugLog.WriteLine("ContentDownloader", DebugLog.WriteLine("ContentDownloader",
"Downloading manifest {0} from {1} with {2}", "Downloading manifest {0} from {1} with {2}",
depot.manifestId, depot.ManifestId,
connection, connection,
cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy");
depotManifest = await cdnPool.CDNClient.DownloadManifestAsync( depotManifest = await cdnPool.CDNClient.DownloadManifestAsync(
depot.id, depot.DepotId,
depot.manifestId, depot.ManifestId,
manifestRequestCode, manifestRequestCode,
connection, connection,
depot.depotKey, depot.DepotKey,
cdnPool.ProxyServer).ConfigureAwait(false); cdnPool.ProxyServer).ConfigureAwait(false);
cdnPool.ReturnConnection(connection); cdnPool.ReturnConnection(connection);
} }
catch (TaskCanceledException) catch (TaskCanceledException)
{ {
Console.WriteLine("Connection timeout downloading depot manifest {0} {1}. Retrying.", depot.id, depot.manifestId); Console.WriteLine("Connection timeout downloading depot manifest {0} {1}. Retrying.", depot.DepotId, depot.ManifestId);
} }
catch (SteamKitWebRequestException e) catch (SteamKitWebRequestException e)
{ {
@ -856,17 +814,17 @@ namespace DepotDownloader
if (e.StatusCode == HttpStatusCode.Unauthorized || e.StatusCode == HttpStatusCode.Forbidden) if (e.StatusCode == HttpStatusCode.Unauthorized || e.StatusCode == HttpStatusCode.Forbidden)
{ {
Console.WriteLine("Encountered 401 for depot manifest {0} {1}. Aborting.", depot.id, depot.manifestId); Console.WriteLine("Encountered 401 for depot manifest {0} {1}. Aborting.", depot.DepotId, depot.ManifestId);
break; break;
} }
if (e.StatusCode == HttpStatusCode.NotFound) if (e.StatusCode == HttpStatusCode.NotFound)
{ {
Console.WriteLine("Encountered 404 for depot manifest {0} {1}. Aborting.", depot.id, depot.manifestId); Console.WriteLine("Encountered 404 for depot manifest {0} {1}. Aborting.", depot.DepotId, depot.ManifestId);
break; break;
} }
Console.WriteLine("Encountered error downloading depot manifest {0} {1}: {2}", depot.id, depot.manifestId, e.StatusCode); Console.WriteLine("Encountered error downloading depot manifest {0} {1}: {2}", depot.DepotId, depot.ManifestId, e.StatusCode);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -875,23 +833,22 @@ namespace DepotDownloader
catch (Exception e) catch (Exception e)
{ {
cdnPool.ReturnBrokenConnection(connection); cdnPool.ReturnBrokenConnection(connection);
Console.WriteLine("Encountered error downloading manifest for depot {0} {1}: {2}", depot.id, depot.manifestId, e.Message); Console.WriteLine("Encountered error downloading manifest for depot {0} {1}: {2}", depot.DepotId, depot.ManifestId, e.Message);
} }
} while (depotManifest == null); } while (depotManifest == null);
if (depotManifest == null) if (depotManifest == null)
{ {
Console.WriteLine("\nUnable to download manifest {0} for depot {1}", depot.manifestId, depot.id); Console.WriteLine("\nUnable to download manifest {0} for depot {1}", depot.ManifestId, depot.DepotId);
cts.Cancel(); cts.Cancel();
} }
// Throw the cancellation exception if requested so that this task is marked failed // Throw the cancellation exception if requested so that this task is marked failed
cts.Token.ThrowIfCancellationRequested(); cts.Token.ThrowIfCancellationRequested();
byte[] checksum;
newProtoManifest = new ProtoManifest(depotManifest, depot.manifestId); newProtoManifest = new ProtoManifest(depotManifest, depot.ManifestId);
newProtoManifest.SaveToFile(newManifestFileName, out checksum); newProtoManifest.SaveToFile(newManifestFileName, out var checksum);
File.WriteAllBytes(newManifestFileName + ".sha", checksum); File.WriteAllBytes(newManifestFileName + ".sha", checksum);
Console.WriteLine(" Done!"); Console.WriteLine(" Done!");
@ -900,7 +857,7 @@ namespace DepotDownloader
newProtoManifest.Files.Sort((x, y) => string.Compare(x.FileName, y.FileName, StringComparison.Ordinal)); newProtoManifest.Files.Sort((x, y) => string.Compare(x.FileName, y.FileName, StringComparison.Ordinal));
Console.WriteLine("Manifest {0} ({1})", depot.manifestId, newProtoManifest.CreationTime); Console.WriteLine("Manifest {0} ({1})", depot.ManifestId, newProtoManifest.CreationTime);
if (Config.DownloadManifestOnly) if (Config.DownloadManifestOnly)
{ {
@ -908,7 +865,7 @@ namespace DepotDownloader
return null; return null;
} }
var stagingDir = Path.Combine(depot.installDir, STAGING_DIR); var stagingDir = Path.Combine(depot.InstallDir, STAGING_DIR);
var filesAfterExclusions = newProtoManifest.Files.AsParallel().Where(f => TestIsFileIncluded(f.FileName)).ToList(); var filesAfterExclusions = newProtoManifest.Files.AsParallel().Where(f => TestIsFileIncluded(f.FileName)).ToList();
var allFileNames = new HashSet<string>(filesAfterExclusions.Count); var allFileNames = new HashSet<string>(filesAfterExclusions.Count);
@ -918,7 +875,7 @@ namespace DepotDownloader
{ {
allFileNames.Add(file.FileName); allFileNames.Add(file.FileName);
var fileFinalPath = Path.Combine(depot.installDir, file.FileName); var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName);
var fileStagingPath = Path.Combine(stagingDir, file.FileName); var fileStagingPath = Path.Combine(stagingDir, file.FileName);
if (file.Flags.HasFlag(EDepotFileFlag.Directory)) if (file.Flags.HasFlag(EDepotFileFlag.Directory))
@ -948,13 +905,13 @@ namespace DepotDownloader
}; };
} }
private static async Task DownloadSteam3AsyncDepotFiles(CancellationTokenSource cts, uint appId, private static async Task DownloadSteam3AsyncDepotFiles(CancellationTokenSource cts,
GlobalDownloadCounter downloadCounter, DepotFilesData depotFilesData, HashSet<String> allFileNamesAllDepots) GlobalDownloadCounter downloadCounter, DepotFilesData depotFilesData, HashSet<string> allFileNamesAllDepots)
{ {
var depot = depotFilesData.depotDownloadInfo; var depot = depotFilesData.depotDownloadInfo;
var depotCounter = depotFilesData.depotCounter; var depotCounter = depotFilesData.depotCounter;
Console.WriteLine("Downloading depot {0}", depot.id); Console.WriteLine("Downloading depot {0}", depot.DepotId);
var files = depotFilesData.filteredFiles.Where(f => !f.Flags.HasFlag(EDepotFileFlag.Directory)).ToArray(); var files = depotFilesData.filteredFiles.Where(f => !f.Flags.HasFlag(EDepotFileFlag.Directory)).ToArray();
var networkChunkQueue = new ConcurrentQueue<(FileStreamData fileStreamData, ProtoManifest.FileData fileData, ProtoManifest.ChunkData chunk)>(); var networkChunkQueue = new ConcurrentQueue<(FileStreamData fileStreamData, ProtoManifest.FileData fileData, ProtoManifest.ChunkData chunk)>();
@ -967,7 +924,7 @@ namespace DepotDownloader
await Util.InvokeAsync( await Util.InvokeAsync(
networkChunkQueue.Select(q => new Func<Task>(async () => networkChunkQueue.Select(q => new Func<Task>(async () =>
await Task.Run(() => DownloadSteam3AsyncDepotFileChunk(cts, appId, downloadCounter, depotFilesData, await Task.Run(() => DownloadSteam3AsyncDepotFileChunk(cts, downloadCounter, depotFilesData,
q.fileData, q.fileStreamData, q.chunk)))), q.fileData, q.fileStreamData, q.chunk)))),
maxDegreeOfParallelism: Config.MaxDownloads maxDegreeOfParallelism: Config.MaxDownloads
); );
@ -991,7 +948,7 @@ namespace DepotDownloader
foreach (var existingFileName in previousFilteredFiles) foreach (var existingFileName in previousFilteredFiles)
{ {
var fileFinalPath = Path.Combine(depot.installDir, existingFileName); var fileFinalPath = Path.Combine(depot.InstallDir, existingFileName);
if (!File.Exists(fileFinalPath)) if (!File.Exists(fileFinalPath))
continue; continue;
@ -1001,10 +958,10 @@ namespace DepotDownloader
} }
} }
DepotConfigStore.Instance.InstalledManifestIDs[depot.id] = depot.manifestId; DepotConfigStore.Instance.InstalledManifestIDs[depot.DepotId] = depot.ManifestId;
DepotConfigStore.Save(); DepotConfigStore.Save();
Console.WriteLine("Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.id, depotCounter.DepotBytesCompressed, depotCounter.DepotBytesUncompressed); Console.WriteLine("Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.DepotId, depotCounter.DepotBytesCompressed, depotCounter.DepotBytesUncompressed);
} }
private static void DownloadSteam3AsyncDepotFile( private static void DownloadSteam3AsyncDepotFile(
@ -1025,7 +982,7 @@ namespace DepotDownloader
oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName); oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName);
} }
var fileFinalPath = Path.Combine(depot.installDir, file.FileName); var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName);
var fileStagingPath = Path.Combine(stagingDir, file.FileName); var fileStagingPath = Path.Combine(stagingDir, file.FileName);
// This may still exist if the previous run exited before cleanup // This may still exist if the previous run exited before cleanup
@ -1049,7 +1006,7 @@ namespace DepotDownloader
} }
catch (IOException ex) catch (IOException ex)
{ {
throw new ContentDownloaderException(String.Format("Failed to allocate file {0}: {1}", fileFinalPath, ex.Message)); throw new ContentDownloaderException(string.Format("Failed to allocate file {0}: {1}", fileFinalPath, ex.Message));
} }
neededChunks = new List<ProtoManifest.ChunkData>(file.Chunks); neededChunks = new List<ProtoManifest.ChunkData>(file.Chunks);
@ -1059,7 +1016,7 @@ namespace DepotDownloader
// open existing // open existing
if (oldManifestFile != null) if (oldManifestFile != null)
{ {
neededChunks = new List<ProtoManifest.ChunkData>(); neededChunks = [];
var hashMatches = oldManifestFile.FileHash.SequenceEqual(file.FileHash); var hashMatches = oldManifestFile.FileHash.SequenceEqual(file.FileHash);
if (Config.VerifyAll || !hashMatches) if (Config.VerifyAll || !hashMatches)
@ -1123,7 +1080,7 @@ namespace DepotDownloader
} }
catch (IOException ex) catch (IOException ex)
{ {
throw new ContentDownloaderException(String.Format("Failed to resize file to expected size {0}: {1}", fileFinalPath, ex.Message)); throw new ContentDownloaderException(string.Format("Failed to resize file to expected size {0}: {1}", fileFinalPath, ex.Message));
} }
foreach (var match in copyChunks) foreach (var match in copyChunks)
@ -1155,12 +1112,12 @@ namespace DepotDownloader
} }
catch (IOException ex) catch (IOException ex)
{ {
throw new ContentDownloaderException(String.Format("Failed to allocate file {0}: {1}", fileFinalPath, ex.Message)); throw new ContentDownloaderException(string.Format("Failed to allocate file {0}: {1}", fileFinalPath, ex.Message));
} }
} }
Console.WriteLine("Validating {0}", fileFinalPath); Console.WriteLine("Validating {0}", fileFinalPath);
neededChunks = Util.ValidateSteam3FileChecksums(fs, file.Chunks.OrderBy(x => x.Offset).ToArray()); neededChunks = Util.ValidateSteam3FileChecksums(fs, [.. file.Chunks.OrderBy(x => x.Offset)]);
} }
if (neededChunks.Count == 0) if (neededChunks.Count == 0)
@ -1205,7 +1162,7 @@ namespace DepotDownloader
} }
private static async Task DownloadSteam3AsyncDepotFileChunk( private static async Task DownloadSteam3AsyncDepotFileChunk(
CancellationTokenSource cts, uint appId, CancellationTokenSource cts,
GlobalDownloadCounter downloadCounter, GlobalDownloadCounter downloadCounter,
DepotFilesData depotFilesData, DepotFilesData depotFilesData,
ProtoManifest.FileData file, ProtoManifest.FileData file,
@ -1219,12 +1176,14 @@ namespace DepotDownloader
var chunkID = Util.EncodeHexString(chunk.ChunkID); var chunkID = Util.EncodeHexString(chunk.ChunkID);
var data = new DepotManifest.ChunkData(); var data = new DepotManifest.ChunkData
data.ChunkID = chunk.ChunkID; {
data.Checksum = chunk.Checksum; ChunkID = chunk.ChunkID,
data.Offset = chunk.Offset; Checksum = chunk.Checksum,
data.CompressedLength = chunk.CompressedLength; Offset = chunk.Offset,
data.UncompressedLength = chunk.UncompressedLength; CompressedLength = chunk.CompressedLength,
UncompressedLength = chunk.UncompressedLength
};
DepotChunk chunkData = null; DepotChunk chunkData = null;
@ -1240,10 +1199,10 @@ namespace DepotDownloader
DebugLog.WriteLine("ContentDownloader", "Downloading chunk {0} from {1} with {2}", chunkID, connection, cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); DebugLog.WriteLine("ContentDownloader", "Downloading chunk {0} from {1} with {2}", chunkID, connection, cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy");
chunkData = await cdnPool.CDNClient.DownloadDepotChunkAsync( chunkData = await cdnPool.CDNClient.DownloadDepotChunkAsync(
depot.id, depot.DepotId,
data, data,
connection, connection,
depot.depotKey, depot.DepotKey,
cdnPool.ProxyServer).ConfigureAwait(false); cdnPool.ProxyServer).ConfigureAwait(false);
cdnPool.ReturnConnection(connection); cdnPool.ReturnConnection(connection);
@ -1277,7 +1236,7 @@ namespace DepotDownloader
if (chunkData == null) if (chunkData == null)
{ {
Console.WriteLine("Failed to find any server with chunk {0} for depot {1}. Aborting.", chunkID, depot.id); Console.WriteLine("Failed to find any server with chunk {0} for depot {1}. Aborting.", chunkID, depot.DepotId);
cts.Cancel(); cts.Cancel();
} }
@ -1290,12 +1249,12 @@ namespace DepotDownloader
if (fileStreamData.fileStream == null) if (fileStreamData.fileStream == null)
{ {
var fileFinalPath = Path.Combine(depot.installDir, file.FileName); var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName);
fileStreamData.fileStream = File.Open(fileFinalPath, FileMode.Open); fileStreamData.fileStream = File.Open(fileFinalPath, FileMode.Open);
} }
fileStreamData.fileStream.Seek((long)chunkData.ChunkInfo.Offset, SeekOrigin.Begin); fileStreamData.fileStream.Seek((long)chunkData.ChunkInfo.Offset, SeekOrigin.Begin);
await fileStreamData.fileStream.WriteAsync(chunkData.Data, 0, chunkData.Data.Length); await fileStreamData.fileStream.WriteAsync(chunkData.Data.AsMemory(0, chunkData.Data.Length), cts.Token);
} }
finally finally
{ {
@ -1326,20 +1285,19 @@ namespace DepotDownloader
if (remainingChunks == 0) if (remainingChunks == 0)
{ {
var fileFinalPath = Path.Combine(depot.installDir, file.FileName); var fileFinalPath = Path.Combine(depot.InstallDir, file.FileName);
Console.WriteLine("{0,6:#00.00}% {1}", (sizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath); Console.WriteLine("{0,6:#00.00}% {1}", (sizeDownloaded / (float)depotDownloadCounter.CompleteDownloadSize) * 100.0f, fileFinalPath);
} }
} }
static void DumpManifestToTextFile(DepotDownloadInfo depot, ProtoManifest manifest) static void DumpManifestToTextFile(DepotDownloadInfo depot, ProtoManifest manifest)
{ {
var txtManifest = Path.Combine(depot.installDir, $"manifest_{depot.id}_{depot.manifestId}.txt"); var txtManifest = Path.Combine(depot.InstallDir, $"manifest_{depot.DepotId}_{depot.ManifestId}.txt");
using var sw = new StreamWriter(txtManifest);
using (var sw = new StreamWriter(txtManifest)) sw.WriteLine($"Content Manifest for Depot {depot.DepotId}");
{
sw.WriteLine($"Content Manifest for Depot {depot.id}");
sw.WriteLine(); sw.WriteLine();
sw.WriteLine($"Manifest ID / date : {depot.manifestId} / {manifest.CreationTime}"); sw.WriteLine($"Manifest ID / date : {depot.ManifestId} / {manifest.CreationTime}");
int numFiles = 0, numChunks = 0; int numFiles = 0, numChunks = 0;
ulong uncompressedSize = 0, compressedSize = 0; ulong uncompressedSize = 0, compressedSize = 0;
@ -1373,5 +1331,4 @@ namespace DepotDownloader
} }
} }
} }
}
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
@ -16,7 +16,7 @@ namespace DepotDownloader
DepotConfigStore() DepotConfigStore()
{ {
InstalledManifestIDs = new Dictionary<uint, ulong>(); InstalledManifestIDs = [];
} }
static bool Loaded static bool Loaded
@ -33,8 +33,8 @@ namespace DepotDownloader
if (File.Exists(filename)) if (File.Exists(filename))
{ {
using (var fs = File.Open(filename, FileMode.Open)) using var fs = File.Open(filename, FileMode.Open);
using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) using var ds = new DeflateStream(fs, CompressionMode.Decompress);
Instance = Serializer.Deserialize<DepotConfigStore>(ds); Instance = Serializer.Deserialize<DepotConfigStore>(ds);
} }
else else
@ -50,8 +50,8 @@ namespace DepotDownloader
if (!Loaded) if (!Loaded)
throw new Exception("Saved config before loading"); throw new Exception("Saved config before loading");
using (var fs = File.Open(Instance.FileName, FileMode.Create)) using var fs = File.Open(Instance.FileName, FileMode.Create);
using (var ds = new DeflateStream(fs, CompressionMode.Compress)) using var ds = new DeflateStream(fs, CompressionMode.Compress);
Serializer.Serialize(ds, Instance); Serializer.Serialize(ds, Instance);
} }
} }

@ -1,4 +1,4 @@
using System.IO; using System.IO;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Sockets; using System.Net.Sockets;
@ -29,8 +29,10 @@ namespace DepotDownloader
// By default, we create dual-mode sockets: // By default, we create dual-mode sockets:
// Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); // Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
socket.NoDelay = true; {
NoDelay = true
};
try try
{ {

@ -16,6 +16,8 @@ namespace DepotDownloader
static int Main(string[] args) static int Main(string[] args)
=> MainAsync(args).GetAwaiter().GetResult(); => MainAsync(args).GetAwaiter().GetResult();
internal static readonly char[] newLineCharacters = ['\n', '\r'];
static async Task<int> MainAsync(string[] args) static async Task<int> MainAsync(string[] args)
{ {
if (args.Length == 0) if (args.Length == 0)
@ -63,20 +65,22 @@ namespace DepotDownloader
if (fileList != null) if (fileList != null)
{ {
const string RegexPrefix = "regex:";
try try
{ {
var fileListData = await File.ReadAllTextAsync(fileList); var fileListData = await File.ReadAllTextAsync(fileList);
var files = fileListData.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); var files = fileListData.Split(newLineCharacters, StringSplitOptions.RemoveEmptyEntries);
ContentDownloader.Config.UsingFileList = true; ContentDownloader.Config.UsingFileList = true;
ContentDownloader.Config.FilesToDownload = new HashSet<string>(StringComparer.OrdinalIgnoreCase); ContentDownloader.Config.FilesToDownload = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex = new List<Regex>(); ContentDownloader.Config.FilesToDownloadRegex = [];
foreach (var fileEntry in files) foreach (var fileEntry in files)
{ {
if (fileEntry.StartsWith("regex:")) if (fileEntry.StartsWith(RegexPrefix))
{ {
var rgx = new Regex(fileEntry.Substring(6), RegexOptions.Compiled | RegexOptions.IgnoreCase); var rgx = new Regex(fileEntry[RegexPrefix.Length..], RegexOptions.Compiled | RegexOptions.IgnoreCase);
ContentDownloader.Config.FilesToDownloadRegex.Add(rgx); ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
} }
else else
@ -192,7 +196,7 @@ namespace DepotDownloader
ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms"); ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
var os = GetParameter<string>(args, "-os"); var os = GetParameter<string>(args, "-os");
if (ContentDownloader.Config.DownloadAllPlatforms && !String.IsNullOrEmpty(os)) if (ContentDownloader.Config.DownloadAllPlatforms && !string.IsNullOrEmpty(os))
{ {
Console.WriteLine("Error: Cannot specify -os when -all-platforms is specified."); Console.WriteLine("Error: Cannot specify -os when -all-platforms is specified.");
return 1; return 1;
@ -203,7 +207,7 @@ namespace DepotDownloader
ContentDownloader.Config.DownloadAllLanguages = HasParameter(args, "-all-languages"); ContentDownloader.Config.DownloadAllLanguages = HasParameter(args, "-all-languages");
var language = GetParameter<string>(args, "-language"); var language = GetParameter<string>(args, "-language");
if (ContentDownloader.Config.DownloadAllLanguages && !String.IsNullOrEmpty(language)) if (ContentDownloader.Config.DownloadAllLanguages && !string.IsNullOrEmpty(language))
{ {
Console.WriteLine("Error: Cannot specify -language when -all-languages is specified."); Console.WriteLine("Error: Cannot specify -language when -all-languages is specified.");
return 1; return 1;
@ -314,7 +318,7 @@ namespace DepotDownloader
return IndexOfParam(args, param) > -1; return IndexOfParam(args, param) > -1;
} }
static T GetParameter<T>(string[] args, string param, T defaultValue = default(T)) static T GetParameter<T>(string[] args, string param, T defaultValue = default)
{ {
var index = IndexOfParam(args, param); var index = IndexOfParam(args, param);
@ -329,7 +333,7 @@ namespace DepotDownloader
return (T)converter.ConvertFromString(strParam); return (T)converter.ConvertFromString(strParam);
} }
return default(T); return default;
} }
static List<T> GetParameterList<T>(string[] args, string param) static List<T> GetParameterList<T>(string[] args, string param)

@ -14,7 +14,7 @@ namespace DepotDownloader
// Proto ctor // Proto ctor
private ProtoManifest() private ProtoManifest()
{ {
Files = new List<FileData>(); Files = [];
} }
public ProtoManifest(DepotManifest sourceManifest, ulong id) : this() public ProtoManifest(DepotManifest sourceManifest, ulong id) : this()
@ -30,7 +30,7 @@ namespace DepotDownloader
// Proto ctor // Proto ctor
private FileData() private FileData()
{ {
Chunks = new List<ChunkData>(); Chunks = [];
} }
public FileData(DepotManifest.FileData sourceData) : this() public FileData(DepotManifest.FileData sourceData) : this()
@ -130,8 +130,7 @@ namespace DepotDownloader
return null; return null;
} }
using (var ms = new MemoryStream()) using var ms = new MemoryStream();
{
using (var fs = File.Open(filename, FileMode.Open)) using (var fs = File.Open(filename, FileMode.Open))
using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) using (var ds = new DeflateStream(fs, CompressionMode.Decompress))
ds.CopyTo(ms); ds.CopyTo(ms);
@ -141,22 +140,19 @@ namespace DepotDownloader
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
return Serializer.Deserialize<ProtoManifest>(ms); return Serializer.Deserialize<ProtoManifest>(ms);
} }
}
public void SaveToFile(string filename, out byte[] checksum) public void SaveToFile(string filename, out byte[] checksum)
{ {
using (var ms = new MemoryStream()) using var ms = new MemoryStream();
{
Serializer.Serialize(ms, this); Serializer.Serialize(ms, this);
checksum = SHA1.HashData(ms.ToArray()); checksum = SHA1.HashData(ms.ToArray());
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
using (var fs = File.Open(filename, FileMode.Create)) using var fs = File.Open(filename, FileMode.Create);
using (var ds = new DeflateStream(fs, CompressionMode.Compress)) using var ds = new DeflateStream(fs, CompressionMode.Compress);
ms.CopyTo(ds); ms.CopyTo(ds);
} }
} }
}
} }

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
@ -14,16 +13,7 @@ namespace DepotDownloader
{ {
class Steam3Session class Steam3Session
{ {
public class Credentials public bool IsLoggedOn { get; private set; }
{
public bool LoggedOn { get; set; }
public ulong SessionToken { get; set; }
public bool IsValid
{
get { return LoggedOn; }
}
}
public ReadOnlyCollection<SteamApps.LicenseListCallback.License> Licenses public ReadOnlyCollection<SteamApps.LicenseListCallback.License> Licenses
{ {
@ -31,13 +21,12 @@ namespace DepotDownloader
private set; private set;
} }
public Dictionary<uint, ulong> AppTokens { get; private set; } public Dictionary<uint, ulong> AppTokens { get; } = [];
public Dictionary<uint, ulong> PackageTokens { get; private set; } public Dictionary<uint, ulong> PackageTokens { get; } = [];
public Dictionary<uint, byte[]> DepotKeys { get; private set; } public Dictionary<uint, byte[]> DepotKeys { get; } = [];
public ConcurrentDictionary<string, TaskCompletionSource<SteamApps.CDNAuthTokenCallback>> CDNAuthTokens { get; private set; } public Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo> AppInfo { get; } = [];
public Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo> AppInfo { get; private set; } public Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo> PackageInfo { get; } = [];
public Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo> PackageInfo { get; private set; } public Dictionary<string, byte[]> AppBetaPasswords { get; } = [];
public Dictionary<string, byte[]> AppBetaPasswords { get; private set; }
public SteamClient steamClient; public SteamClient steamClient;
public SteamUser steamUser; public SteamUser steamUser;
@ -63,32 +52,13 @@ namespace DepotDownloader
// input // input
readonly SteamUser.LogOnDetails logonDetails; readonly SteamUser.LogOnDetails logonDetails;
// output
readonly Credentials credentials;
static readonly TimeSpan STEAM3_TIMEOUT = TimeSpan.FromSeconds(30); static readonly TimeSpan STEAM3_TIMEOUT = TimeSpan.FromSeconds(30);
public Steam3Session(SteamUser.LogOnDetails details) public Steam3Session(SteamUser.LogOnDetails details)
{ {
this.logonDetails = details; this.logonDetails = details;
this.authenticatedUser = details.Username != null || ContentDownloader.Config.UseQrCode; this.authenticatedUser = details.Username != null || ContentDownloader.Config.UseQrCode;
this.credentials = new Credentials();
this.bConnected = false;
this.bConnecting = false;
this.bAborted = false;
this.bExpectingDisconnectRemote = false;
this.bDidDisconnect = false;
this.seq = 0;
this.AppTokens = new Dictionary<uint, ulong>();
this.PackageTokens = new Dictionary<uint, ulong>();
this.DepotKeys = new Dictionary<uint, byte[]>();
this.CDNAuthTokens = new ConcurrentDictionary<string, TaskCompletionSource<SteamApps.CDNAuthTokenCallback>>();
this.AppInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>();
this.PackageInfo = new Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo>();
this.AppBetaPasswords = new Dictionary<string, byte[]>();
var clientConfiguration = SteamConfiguration.Create(config => var clientConfiguration = SteamConfiguration.Create(config =>
config config
@ -109,7 +79,6 @@ namespace DepotDownloader
this.callbacks.Subscribe<SteamClient.ConnectedCallback>(ConnectedCallback); this.callbacks.Subscribe<SteamClient.ConnectedCallback>(ConnectedCallback);
this.callbacks.Subscribe<SteamClient.DisconnectedCallback>(DisconnectedCallback); this.callbacks.Subscribe<SteamClient.DisconnectedCallback>(DisconnectedCallback);
this.callbacks.Subscribe<SteamUser.LoggedOnCallback>(LogOnCallback); this.callbacks.Subscribe<SteamUser.LoggedOnCallback>(LogOnCallback);
this.callbacks.Subscribe<SteamUser.SessionTokenCallback>(SessionTokenCallback);
this.callbacks.Subscribe<SteamApps.LicenseListCallback>(LicenseListCallback); this.callbacks.Subscribe<SteamApps.LicenseListCallback>(LicenseListCallback);
Console.Write("Connecting to Steam3..."); Console.Write("Connecting to Steam3...");
@ -118,7 +87,7 @@ namespace DepotDownloader
public delegate bool WaitCondition(); public delegate bool WaitCondition();
private readonly object steamLock = new object(); private readonly object steamLock = new();
public bool WaitUntilCallback(Action submitter, WaitCondition waiter) public bool WaitUntilCallback(Action submitter, WaitCondition waiter)
{ {
@ -142,14 +111,14 @@ namespace DepotDownloader
return bAborted; return bAborted;
} }
public Credentials WaitForCredentials() public bool WaitForCredentials()
{ {
if (credentials.IsValid || bAborted) if (IsLoggedOn || bAborted)
return credentials; return IsLoggedOn;
WaitUntilCallback(() => { }, () => { return credentials.IsValid; }); WaitUntilCallback(() => { }, () => IsLoggedOn);
return credentials; return IsLoggedOn;
} }
public void RequestAppInfo(uint appId, bool bForce = false) public void RequestAppInfo(uint appId, bool bForce = false)
@ -708,7 +677,7 @@ namespace DepotDownloader
Console.WriteLine(" Done!"); Console.WriteLine(" Done!");
this.seq++; this.seq++;
credentials.LoggedOn = true; IsLoggedOn = true;
if (ContentDownloader.Config.CellID == 0) if (ContentDownloader.Config.CellID == 0)
{ {
@ -717,12 +686,6 @@ namespace DepotDownloader
} }
} }
private void SessionTokenCallback(SteamUser.SessionTokenCallback sessionToken)
{
Console.WriteLine("Got session token!");
credentials.SessionToken = sessionToken.SessionToken;
}
private void LicenseListCallback(SteamApps.LicenseListCallback licenseList) private void LicenseListCallback(SteamApps.LicenseListCallback licenseList)
{ {
if (licenseList.Result != EResult.OK) if (licenseList.Result != EResult.OK)

Loading…
Cancel
Save