diff --git a/DepotDownloader/AccountSettingsStore.cs b/DepotDownloader/AccountSettingsStore.cs index d2ea417d..2374a92a 100644 --- a/DepotDownloader/AccountSettingsStore.cs +++ b/DepotDownloader/AccountSettingsStore.cs @@ -29,8 +29,8 @@ namespace DepotDownloader AccountSettingsStore() { ContentServerPenalty = new ConcurrentDictionary(); - LoginTokens = new Dictionary(); - GuardData = new Dictionary(); + LoginTokens = []; + GuardData = []; } static bool Loaded @@ -50,11 +50,9 @@ namespace DepotDownloader { try { - using (var fs = IsolatedStorage.OpenFile(filename, FileMode.Open, FileAccess.Read)) - using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) - { - Instance = Serializer.Deserialize(ds); - } + using var fs = IsolatedStorage.OpenFile(filename, FileMode.Open, FileAccess.Read); + using var ds = new DeflateStream(fs, CompressionMode.Decompress); + Instance = Serializer.Deserialize(ds); } catch (IOException ex) { @@ -77,11 +75,9 @@ namespace DepotDownloader try { - using (var fs = IsolatedStorage.OpenFile(Instance.FileName, FileMode.Create, FileAccess.Write)) - using (var ds = new DeflateStream(fs, CompressionMode.Compress)) - { - Serializer.Serialize(ds, Instance); - } + using var fs = IsolatedStorage.OpenFile(Instance.FileName, FileMode.Create, FileAccess.Write); + using var ds = new DeflateStream(fs, CompressionMode.Compress); + Serializer.Serialize(ds, Instance); } catch (IOException ex) { diff --git a/DepotDownloader/CDNClientPool.cs b/DepotDownloader/CDNClientPool.cs index d40d4b2a..6503d5fe 100644 --- a/DepotDownloader/CDNClientPool.cs +++ b/DepotDownloader/CDNClientPool.cs @@ -35,7 +35,7 @@ namespace DepotDownloader CDNClient = new Client(steamSession.steamClient); activeConnectionPool = new ConcurrentStack(); - availableServerEndpoints = new BlockingCollection(); + availableServerEndpoints = []; populatePoolEvent = new AutoResetEvent(true); shutdownToken = new CancellationTokenSource(); diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs index 4747a7eb..0eace1a2 100644 --- a/DepotDownloader/ContentDownloader.cs +++ b/DepotDownloader/ContentDownloader.cs @@ -11,9 +11,8 @@ using SteamKit2.CDN; namespace DepotDownloader { - class ContentDownloaderException : Exception + class ContentDownloaderException(string value) : Exception(value) { - public ContentDownloaderException(String value) : base(value) { } } static class ContentDownloader @@ -23,7 +22,7 @@ namespace DepotDownloader public const ulong INVALID_MANIFEST_ID = ulong.MaxValue; public const string DEFAULT_BRANCH = "public"; - public static DownloadConfig Config = new DownloadConfig(); + public static DownloadConfig Config = new(); private static Steam3Session steam3; private static Steam3Session.Credentials steam3Credentials; @@ -33,28 +32,16 @@ namespace DepotDownloader private const string CONFIG_DIR = ".DepotDownloader"; private static readonly string STAGING_DIR = Path.Combine(CONFIG_DIR, "staging"); - private sealed class DepotDownloadInfo + private sealed class DepotDownloadInfo( + uint depotid, uint appId, ulong manifestId, string branch, + string installDir, byte[] depotKey) { - 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, - string installDir, byte[] depotKey) - { - this.id = depotid; - this.appId = appId; - this.manifestId = manifestId; - this.branch = branch; - this.installDir = installDir; - this.depotKey = depotKey; - } + public uint DepotId { get; } = depotid; + public uint AppId { get; } = appId; + public ulong ManifestId { get; } = manifestId; + public string Branch { get; } = branch; + public string InstallDir { get; } = installDir; + public byte[] DepotKey { get; } = depotKey; } static bool CreateDirectories(uint depotId, uint depotVersion, out string installDir) @@ -135,8 +122,7 @@ namespace DepotDownloader foreach (var license in licenseQuery) { - SteamApps.PICSProductInfoCallback.PICSProductInfo package; - if (steam3.PackageInfo.TryGetValue(license, out package) && package != null) + if (steam3.PackageInfo.TryGetValue(license, out var package) && package != null) { if (package.KeyValues["appids"].Children.Any(child => child.AsUnsignedInteger() == depotId)) return true; @@ -156,33 +142,20 @@ namespace DepotDownloader return null; } - SteamApps.PICSProductInfoCallback.PICSProductInfo app; - if (!steam3.AppInfo.TryGetValue(appId, out app) || app == null) + if (!steam3.AppInfo.TryGetValue(appId, out var app) || app == null) { return null; } var appinfo = app.KeyValues; - string section_key; - - switch (section) + var section_key = section switch { - case EAppInfoSection.Common: - section_key = "common"; - break; - case EAppInfoSection.Extended: - section_key = "extended"; - break; - case EAppInfoSection.Config: - section_key = "config"; - break; - case EAppInfoSection.Depots: - section_key = "depots"; - break; - default: - throw new NotImplementedException(); - } - + EAppInfoSection.Common => "common", + EAppInfoSection.Extended => "extended", + EAppInfoSection.Config => "config", + EAppInfoSection.Depots => "depots", + _ => throw new NotImplementedException(), + }; var section_kv = appinfo.Children.Where(c => c.Name == section_key).FirstOrDefault(); return section_kv; } @@ -262,7 +235,7 @@ namespace DepotDownloader // Submit the password to Steam now to get encryption keys 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); return INVALID_MANIFEST_ID; @@ -272,7 +245,7 @@ namespace DepotDownloader byte[] manifest_bytes; try { - manifest_bytes = CryptoHelper.SymmetricDecryptECB(input, steam3.AppBetaPasswords[branch]); + manifest_bytes = CryptoHelper.SymmetricDecryptECB(input, appBetaPassword); } catch (Exception e) { @@ -293,14 +266,14 @@ namespace DepotDownloader if (node.Value == null) return INVALID_MANIFEST_ID; - return UInt64.Parse(node.Value); + return ulong.Parse(node.Value); } static string GetAppName(uint appId) { var info = GetSteam3AppSection(appId, EAppInfoSection.Common); if (info == null) - return String.Empty; + return string.Empty; return info["name"].AsString(); } @@ -393,8 +366,7 @@ namespace DepotDownloader private static async Task DownloadWebFile(uint appId, string fileName, string url) { - string installDir; - if (!CreateDirectories(appId, 0, out installDir)) + if (!CreateDirectories(appId, 0, out var installDir)) { Console.WriteLine("Error: Unable to create install directories!"); return; @@ -437,8 +409,7 @@ namespace DepotDownloader Directory.CreateDirectory(Path.Combine(configPath, CONFIG_DIR)); DepotConfigStore.LoadFromFile(Path.Combine(configPath, CONFIG_DIR, "depot.config")); - if (steam3 != null) - steam3.RequestAppInfo(appId); + steam3?.RequestAppInfo(appId); if (!AccountHasAccess(appId)) { @@ -452,13 +423,13 @@ namespace DepotDownloader else { 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 depotIdsFound = new List(); - var depotIdsExpected = depotManifestIds.Select(x => x.Item1).ToList(); + var depotIdsExpected = depotManifestIds.Select(x => x.depotId).ToList(); var depots = GetSteam3AppSection(appId, EAppInfoSection.Depots); if (isUgc) @@ -537,21 +508,21 @@ namespace DepotDownloader 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) { 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(); - 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) { infos.Add(info); @@ -560,7 +531,7 @@ namespace DepotDownloader try { - await DownloadSteam3Async(appId, infos).ConfigureAwait(false); + await DownloadSteam3Async(infos).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -599,7 +570,7 @@ namespace DepotDownloader } 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); return null; @@ -607,28 +578,19 @@ namespace DepotDownloader var uVersion = GetSteam3AppBuildNumber(appId, branch); - string installDir; - if (!CreateDirectories(depotId, uVersion, out installDir)) + if (!CreateDirectories(depotId, uVersion, out var installDir)) { Console.WriteLine("Error: Unable to create install directories!"); return null; } - var depotKey = steam3.DepotKeys[depotId]; - 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; - NewChunk = newChunk; - } - - public ProtoManifest.ChunkData OldChunk { get; private set; } - public ProtoManifest.ChunkData NewChunk { get; private set; } + public ProtoManifest.ChunkData OldChunk { get; } = oldChunk; + public ProtoManifest.ChunkData NewChunk { get; } = newChunk; } private class DepotFilesData @@ -663,19 +625,19 @@ namespace DepotDownloader public ulong DepotBytesUncompressed; } - private static async Task DownloadSteam3Async(uint appId, List depots) + private static async Task DownloadSteam3Async(List depots) { var cts = new CancellationTokenSource(); cdnPool.ExhaustedToken = cts; var downloadCounter = new GlobalDownloadCounter(); var depotsToDownload = new List(depots.Count); - var allFileNamesAllDepots = new HashSet(); + var allFileNamesAllDepots = new HashSet(); // First, fetch all the manifests for each depot (including previous manifests) and perform the initial setup foreach (var depot in depots) { - var depotFileData = await ProcessDepotManifestAndFiles(cts, appId, depot); + var depotFileData = await ProcessDepotManifestAndFiles(cts, depot); if (depotFileData != null) { @@ -690,7 +652,7 @@ namespace DepotDownloader // 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) { - var claimedFileNames = new HashSet(); + var claimedFileNames = new HashSet(); for (var i = depotsToDownload.Count - 1; i >= 0; i--) { @@ -703,38 +665,37 @@ namespace DepotDownloader 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", downloadCounter.TotalBytesCompressed, downloadCounter.TotalBytesUncompressed, depots.Count); } - private static async Task ProcessDepotManifestAndFiles(CancellationTokenSource cts, - uint appId, DepotDownloadInfo depot) + private static async Task ProcessDepotManifestAndFiles(CancellationTokenSource cts, DepotDownloadInfo depot) { var depotCounter = new DepotDownloadCounter(); - Console.WriteLine("Processing depot {0}", depot.id); + Console.WriteLine("Processing depot {0}", depot.DepotId); ProtoManifest oldProtoManifest = 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; - 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. - DepotConfigStore.Instance.InstalledManifestIDs[depot.id] = INVALID_MANIFEST_ID; + DepotConfigStore.Instance.InstalledManifestIDs[depot.DepotId] = INVALID_MANIFEST_ID; DepotConfigStore.Save(); 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)) { - byte[] expectedChecksum, currentChecksum; + byte[] expectedChecksum; try { @@ -745,29 +706,29 @@ namespace DepotDownloader expectedChecksum = null; } - oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName, out currentChecksum); + oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName, out var currentChecksum); if (expectedChecksum == null || !expectedChecksum.SequenceEqual(currentChecksum)) { // 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); oldProtoManifest = null; } } } - if (lastManifestId == depot.manifestId && oldProtoManifest != null) + if (lastManifestId == depot.ManifestId && oldProtoManifest != null) { 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 { - 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) { - byte[] expectedChecksum, currentChecksum; + byte[] expectedChecksum; try { @@ -778,18 +739,18 @@ namespace DepotDownloader expectedChecksum = null; } - newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName, out currentChecksum); + newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName, out var 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; } } 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 { @@ -816,39 +777,39 @@ namespace DepotDownloader if (manifestRequestCode == 0 || now >= manifestRequestCodeExpiration) { manifestRequestCode = await steam3.GetDepotManifestRequestCodeAsync( - depot.id, - depot.appId, - depot.manifestId, - depot.branch); + depot.DepotId, + depot.AppId, + depot.ManifestId, + depot.Branch); // This code will hopefully be valid for one period following the issuing period manifestRequestCodeExpiration = now.Add(TimeSpan.FromMinutes(5)); // If we could not get the manifest code, this is a fatal error 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(); } } DebugLog.WriteLine("ContentDownloader", "Downloading manifest {0} from {1} with {2}", - depot.manifestId, + depot.ManifestId, connection, cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); depotManifest = await cdnPool.CDNClient.DownloadManifestAsync( - depot.id, - depot.manifestId, + depot.DepotId, + depot.ManifestId, manifestRequestCode, connection, - depot.depotKey, + depot.DepotKey, cdnPool.ProxyServer).ConfigureAwait(false); cdnPool.ReturnConnection(connection); } 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) { @@ -856,17 +817,17 @@ namespace DepotDownloader 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; } 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; } - 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) { @@ -875,23 +836,22 @@ namespace DepotDownloader catch (Exception e) { 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); 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(); } // Throw the cancellation exception if requested so that this task is marked failed cts.Token.ThrowIfCancellationRequested(); - byte[] checksum; - newProtoManifest = new ProtoManifest(depotManifest, depot.manifestId); - newProtoManifest.SaveToFile(newManifestFileName, out checksum); + newProtoManifest = new ProtoManifest(depotManifest, depot.ManifestId); + newProtoManifest.SaveToFile(newManifestFileName, out var checksum); File.WriteAllBytes(newManifestFileName + ".sha", checksum); Console.WriteLine(" Done!"); @@ -900,7 +860,7 @@ namespace DepotDownloader 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) { @@ -908,7 +868,7 @@ namespace DepotDownloader 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 allFileNames = new HashSet(filesAfterExclusions.Count); @@ -918,7 +878,7 @@ namespace DepotDownloader { 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); if (file.Flags.HasFlag(EDepotFileFlag.Directory)) @@ -948,13 +908,13 @@ namespace DepotDownloader }; } - private static async Task DownloadSteam3AsyncDepotFiles(CancellationTokenSource cts, uint appId, - GlobalDownloadCounter downloadCounter, DepotFilesData depotFilesData, HashSet allFileNamesAllDepots) + private static async Task DownloadSteam3AsyncDepotFiles(CancellationTokenSource cts, + GlobalDownloadCounter downloadCounter, DepotFilesData depotFilesData, HashSet allFileNamesAllDepots) { var depot = depotFilesData.depotDownloadInfo; 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 networkChunkQueue = new ConcurrentQueue<(FileStreamData fileStreamData, ProtoManifest.FileData fileData, ProtoManifest.ChunkData chunk)>(); @@ -967,7 +927,7 @@ namespace DepotDownloader await Util.InvokeAsync( networkChunkQueue.Select(q => new Func(async () => - await Task.Run(() => DownloadSteam3AsyncDepotFileChunk(cts, appId, downloadCounter, depotFilesData, + await Task.Run(() => DownloadSteam3AsyncDepotFileChunk(cts, downloadCounter, depotFilesData, q.fileData, q.fileStreamData, q.chunk)))), maxDegreeOfParallelism: Config.MaxDownloads ); @@ -991,7 +951,7 @@ namespace DepotDownloader foreach (var existingFileName in previousFilteredFiles) { - var fileFinalPath = Path.Combine(depot.installDir, existingFileName); + var fileFinalPath = Path.Combine(depot.InstallDir, existingFileName); if (!File.Exists(fileFinalPath)) continue; @@ -1001,10 +961,10 @@ namespace DepotDownloader } } - DepotConfigStore.Instance.InstalledManifestIDs[depot.id] = depot.manifestId; + DepotConfigStore.Instance.InstalledManifestIDs[depot.DepotId] = depot.ManifestId; 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( @@ -1025,7 +985,7 @@ namespace DepotDownloader 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); // This may still exist if the previous run exited before cleanup @@ -1049,7 +1009,7 @@ namespace DepotDownloader } 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(file.Chunks); @@ -1059,7 +1019,7 @@ namespace DepotDownloader // open existing if (oldManifestFile != null) { - neededChunks = new List(); + neededChunks = []; var hashMatches = oldManifestFile.FileHash.SequenceEqual(file.FileHash); if (Config.VerifyAll || !hashMatches) @@ -1123,7 +1083,7 @@ namespace DepotDownloader } 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) @@ -1155,12 +1115,12 @@ namespace DepotDownloader } 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); - 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) @@ -1205,7 +1165,7 @@ namespace DepotDownloader } private static async Task DownloadSteam3AsyncDepotFileChunk( - CancellationTokenSource cts, uint appId, + CancellationTokenSource cts, GlobalDownloadCounter downloadCounter, DepotFilesData depotFilesData, ProtoManifest.FileData file, @@ -1219,12 +1179,14 @@ namespace DepotDownloader var chunkID = Util.EncodeHexString(chunk.ChunkID); - var data = new DepotManifest.ChunkData(); - data.ChunkID = chunk.ChunkID; - data.Checksum = chunk.Checksum; - data.Offset = chunk.Offset; - data.CompressedLength = chunk.CompressedLength; - data.UncompressedLength = chunk.UncompressedLength; + var data = new DepotManifest.ChunkData + { + ChunkID = chunk.ChunkID, + Checksum = chunk.Checksum, + Offset = chunk.Offset, + CompressedLength = chunk.CompressedLength, + UncompressedLength = chunk.UncompressedLength + }; DepotChunk chunkData = null; @@ -1240,10 +1202,10 @@ namespace DepotDownloader DebugLog.WriteLine("ContentDownloader", "Downloading chunk {0} from {1} with {2}", chunkID, connection, cdnPool.ProxyServer != null ? cdnPool.ProxyServer : "no proxy"); chunkData = await cdnPool.CDNClient.DownloadDepotChunkAsync( - depot.id, + depot.DepotId, data, connection, - depot.depotKey, + depot.DepotKey, cdnPool.ProxyServer).ConfigureAwait(false); cdnPool.ReturnConnection(connection); @@ -1277,7 +1239,7 @@ namespace DepotDownloader 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(); } @@ -1290,12 +1252,12 @@ namespace DepotDownloader 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.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 { @@ -1326,51 +1288,49 @@ namespace DepotDownloader 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); } } 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.id}"); - sw.WriteLine(); - sw.WriteLine($"Manifest ID / date : {depot.manifestId} / {manifest.CreationTime}"); + sw.WriteLine($"Content Manifest for Depot {depot.DepotId}"); + sw.WriteLine(); + sw.WriteLine($"Manifest ID / date : {depot.ManifestId} / {manifest.CreationTime}"); - int numFiles = 0, numChunks = 0; - ulong uncompressedSize = 0, compressedSize = 0; + int numFiles = 0, numChunks = 0; + ulong uncompressedSize = 0, compressedSize = 0; - foreach (var file in manifest.Files) - { - if (file.Flags.HasFlag(EDepotFileFlag.Directory)) - continue; + foreach (var file in manifest.Files) + { + if (file.Flags.HasFlag(EDepotFileFlag.Directory)) + continue; - numFiles++; - numChunks += file.Chunks.Count; + numFiles++; + numChunks += file.Chunks.Count; - foreach (var chunk in file.Chunks) - { - uncompressedSize += chunk.UncompressedLength; - compressedSize += chunk.CompressedLength; - } + foreach (var chunk in file.Chunks) + { + uncompressedSize += chunk.UncompressedLength; + compressedSize += chunk.CompressedLength; } + } - sw.WriteLine($"Total number of files : {numFiles}"); - sw.WriteLine($"Total number of chunks : {numChunks}"); - sw.WriteLine($"Total bytes on disk : {uncompressedSize}"); - sw.WriteLine($"Total bytes compressed : {compressedSize}"); - sw.WriteLine(); - sw.WriteLine(" Size Chunks File SHA Flags Name"); + sw.WriteLine($"Total number of files : {numFiles}"); + sw.WriteLine($"Total number of chunks : {numChunks}"); + sw.WriteLine($"Total bytes on disk : {uncompressedSize}"); + sw.WriteLine($"Total bytes compressed : {compressedSize}"); + sw.WriteLine(); + sw.WriteLine(" Size Chunks File SHA Flags Name"); - foreach (var file in manifest.Files) - { - var sha1Hash = BitConverter.ToString(file.FileHash).Replace("-", ""); - sw.WriteLine($"{file.TotalSize,14} {file.Chunks.Count,6} {sha1Hash} {file.Flags,5:D} {file.FileName}"); - } + foreach (var file in manifest.Files) + { + var sha1Hash = BitConverter.ToString(file.FileHash).Replace("-", ""); + sw.WriteLine($"{file.TotalSize,14} {file.Chunks.Count,6} {sha1Hash} {file.Flags,5:D} {file.FileName}"); } } } diff --git a/DepotDownloader/DepotConfigStore.cs b/DepotDownloader/DepotConfigStore.cs index 2bd2bb59..99f052c5 100644 --- a/DepotDownloader/DepotConfigStore.cs +++ b/DepotDownloader/DepotConfigStore.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -16,7 +16,7 @@ namespace DepotDownloader DepotConfigStore() { - InstalledManifestIDs = new Dictionary(); + InstalledManifestIDs = []; } static bool Loaded @@ -33,9 +33,9 @@ namespace DepotDownloader if (File.Exists(filename)) { - using (var fs = File.Open(filename, FileMode.Open)) - using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) - Instance = Serializer.Deserialize(ds); + using var fs = File.Open(filename, FileMode.Open); + using var ds = new DeflateStream(fs, CompressionMode.Decompress); + Instance = Serializer.Deserialize(ds); } else { @@ -50,9 +50,9 @@ namespace DepotDownloader if (!Loaded) throw new Exception("Saved config before loading"); - using (var fs = File.Open(Instance.FileName, FileMode.Create)) - using (var ds = new DeflateStream(fs, CompressionMode.Compress)) - Serializer.Serialize(ds, Instance); + using var fs = File.Open(Instance.FileName, FileMode.Create); + using var ds = new DeflateStream(fs, CompressionMode.Compress); + Serializer.Serialize(ds, Instance); } } } diff --git a/DepotDownloader/HttpClientFactory.cs b/DepotDownloader/HttpClientFactory.cs index 8067826b..aa642bc7 100644 --- a/DepotDownloader/HttpClientFactory.cs +++ b/DepotDownloader/HttpClientFactory.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Net.Sockets; @@ -29,8 +29,10 @@ namespace DepotDownloader // By default, we create dual-mode sockets: // Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - socket.NoDelay = true; + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) + { + NoDelay = true + }; try { diff --git a/DepotDownloader/Program.cs b/DepotDownloader/Program.cs index eb396051..14f7f88d 100644 --- a/DepotDownloader/Program.cs +++ b/DepotDownloader/Program.cs @@ -16,6 +16,8 @@ namespace DepotDownloader static int Main(string[] args) => MainAsync(args).GetAwaiter().GetResult(); + internal static readonly char[] newLineCharacters = ['\n', '\r']; + static async Task MainAsync(string[] args) { if (args.Length == 0) @@ -63,20 +65,22 @@ namespace DepotDownloader if (fileList != null) { + const string RegexPrefix = "regex:"; + try { 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.FilesToDownload = new HashSet(StringComparer.OrdinalIgnoreCase); - ContentDownloader.Config.FilesToDownloadRegex = new List(); + ContentDownloader.Config.FilesToDownloadRegex = []; 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); } else @@ -192,7 +196,7 @@ namespace DepotDownloader ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms"); var os = GetParameter(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."); return 1; @@ -203,7 +207,7 @@ namespace DepotDownloader ContentDownloader.Config.DownloadAllLanguages = HasParameter(args, "-all-languages"); var language = GetParameter(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."); return 1; @@ -314,7 +318,7 @@ namespace DepotDownloader return IndexOfParam(args, param) > -1; } - static T GetParameter(string[] args, string param, T defaultValue = default(T)) + static T GetParameter(string[] args, string param, T defaultValue = default) { var index = IndexOfParam(args, param); @@ -329,7 +333,7 @@ namespace DepotDownloader return (T)converter.ConvertFromString(strParam); } - return default(T); + return default; } static List GetParameterList(string[] args, string param) diff --git a/DepotDownloader/ProtoManifest.cs b/DepotDownloader/ProtoManifest.cs index 1770cb50..e4a9c854 100644 --- a/DepotDownloader/ProtoManifest.cs +++ b/DepotDownloader/ProtoManifest.cs @@ -14,7 +14,7 @@ namespace DepotDownloader // Proto ctor private ProtoManifest() { - Files = new List(); + Files = []; } public ProtoManifest(DepotManifest sourceManifest, ulong id) : this() @@ -30,7 +30,7 @@ namespace DepotDownloader // Proto ctor private FileData() { - Chunks = new List(); + Chunks = []; } public FileData(DepotManifest.FileData sourceData) : this() @@ -130,33 +130,29 @@ namespace DepotDownloader return null; } - using (var ms = new MemoryStream()) - { - using (var fs = File.Open(filename, FileMode.Open)) - using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) - ds.CopyTo(ms); + using var ms = new MemoryStream(); + using (var fs = File.Open(filename, FileMode.Open)) + using (var ds = new DeflateStream(fs, CompressionMode.Decompress)) + ds.CopyTo(ms); - checksum = SHA1.HashData(ms.ToArray()); + checksum = SHA1.HashData(ms.ToArray()); - ms.Seek(0, SeekOrigin.Begin); - return Serializer.Deserialize(ms); - } + ms.Seek(0, SeekOrigin.Begin); + return Serializer.Deserialize(ms); } public void SaveToFile(string filename, out byte[] checksum) { - using (var ms = new MemoryStream()) - { - Serializer.Serialize(ms, this); + using var ms = new MemoryStream(); + 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 ds = new DeflateStream(fs, CompressionMode.Compress)) - ms.CopyTo(ds); - } + using var fs = File.Open(filename, FileMode.Create); + using var ds = new DeflateStream(fs, CompressionMode.Compress); + ms.CopyTo(ds); } } } diff --git a/DepotDownloader/Steam3Session.cs b/DepotDownloader/Steam3Session.cs index 4ca89126..c6d6f6f2 100644 --- a/DepotDownloader/Steam3Session.cs +++ b/DepotDownloader/Steam3Session.cs @@ -82,13 +82,13 @@ namespace DepotDownloader this.bDidDisconnect = false; this.seq = 0; - this.AppTokens = new Dictionary(); - this.PackageTokens = new Dictionary(); - this.DepotKeys = new Dictionary(); + this.AppTokens = []; + this.PackageTokens = []; + this.DepotKeys = []; this.CDNAuthTokens = new ConcurrentDictionary>(); - this.AppInfo = new Dictionary(); - this.PackageInfo = new Dictionary(); - this.AppBetaPasswords = new Dictionary(); + this.AppInfo = []; + this.PackageInfo = []; + this.AppBetaPasswords = []; var clientConfiguration = SteamConfiguration.Create(config => config @@ -118,7 +118,7 @@ namespace DepotDownloader public delegate bool WaitCondition(); - private readonly object steamLock = new object(); + private readonly object steamLock = new(); public bool WaitUntilCallback(Action submitter, WaitCondition waiter) {