Пример #1
0
        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<ConfigStore>(ds);
            }
            else
            {
                TheConfig = new ConfigStore();
            }

            TheConfig.FileName = filename;
        }
Пример #2
0
        static async Task MainAsync(string[] args)
        {
            if (args.Length == 0)
            {
                PrintUsage();
                return;
            }

            DebugLog.Enabled = false;

            ConfigStore.LoadFromFile(Path.Combine(Directory.GetCurrentDirectory(), "DepotDownloader.config"));

            bool bDumpManifest = HasParameter(args, "-manifest-only");
            uint appId         = GetParameter <uint>(args, "-app", ContentDownloader.INVALID_APP_ID);
            uint depotId       = GetParameter <uint>(args, "-depot", ContentDownloader.INVALID_DEPOT_ID);

            ContentDownloader.Config.ManifestId = GetParameter <ulong>(args, "-manifest", ContentDownloader.INVALID_MANIFEST_ID);

            if (appId == ContentDownloader.INVALID_APP_ID)
            {
                Console.WriteLine("Error: -app not specified!");
                return;
            }

            if (depotId == ContentDownloader.INVALID_DEPOT_ID && ContentDownloader.Config.ManifestId != ContentDownloader.INVALID_MANIFEST_ID)
            {
                Console.WriteLine("Error: -manifest requires -depot to be specified");
                return;
            }

            ContentDownloader.Config.DownloadManifestOnly = bDumpManifest;

            int cellId = GetParameter <int>(args, "-cellid", -1);

            if (cellId == -1)
            {
                cellId = 0;
            }

            ContentDownloader.Config.CellID       = cellId;
            ContentDownloader.Config.BetaPassword = GetParameter <string>(args, "-betapassword");

            string fileList = GetParameter <string>(args, "-filelist");

            string[] files = null;

            if (fileList != null)
            {
                try
                {
                    string fileListData = File.ReadAllText(fileList);
                    files = fileListData.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

                    ContentDownloader.Config.UsingFileList        = true;
                    ContentDownloader.Config.FilesToDownload      = new List <string>();
                    ContentDownloader.Config.FilesToDownloadRegex = new List <Regex>();

                    foreach (var fileEntry in files)
                    {
                        try
                        {
                            Regex rgx = new Regex(fileEntry, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                            ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
                        }
                        catch
                        {
                            ContentDownloader.Config.FilesToDownload.Add(fileEntry);
                            continue;
                        }
                    }

                    Console.WriteLine("Using filelist: '{0}'.", fileList);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Warning: Unable to load filelist: {0}", ex.ToString());
                }
            }

            string username = GetParameter <string>(args, "-username") ?? GetParameter <string>(args, "-user");
            string password = GetParameter <string>(args, "-password") ?? GetParameter <string>(args, "-pass");

            ContentDownloader.Config.RememberPassword     = HasParameter(args, "-remember-password");
            ContentDownloader.Config.InstallDirectory     = GetParameter <string>(args, "-dir");
            ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
            ContentDownloader.Config.VerifyAll            = HasParameter(args, "-verify-all") || HasParameter(args, "-verify_all") || HasParameter(args, "-validate");
            ContentDownloader.Config.MaxServers           = GetParameter <int>(args, "-max-servers", 20);
            ContentDownloader.Config.MaxDownloads         = GetParameter <int>(args, "-max-downloads", 4);
            string branch     = GetParameter <string>(args, "-branch") ?? GetParameter <string>(args, "-beta") ?? "Public";
            bool   forceDepot = HasParameter(args, "-force-depot");
            string os         = GetParameter <string>(args, "-os", null);

            if (ContentDownloader.Config.DownloadAllPlatforms && !String.IsNullOrEmpty(os))
            {
                Console.WriteLine("Error: Cannot specify -os when -all-platforms is specified.");
                return;
            }

            ContentDownloader.Config.MaxServers = Math.Max(ContentDownloader.Config.MaxServers, ContentDownloader.Config.MaxDownloads);

            if (username != null && password == null && (!ContentDownloader.Config.RememberPassword || !ConfigStore.TheConfig.LoginKeys.ContainsKey(username)))
            {
                Console.Write("Enter account password for \"{0}\": ", username);
                password = Util.ReadPassword();
                Console.WriteLine();
            }
            else if (username == null)
            {
                Console.WriteLine("No username given. Using anonymous account with dedicated server subscription.");
            }

            // capture the supplied password in case we need to re-use it after checking the login key
            ContentDownloader.Config.SuppliedPassword = password;

            if (ContentDownloader.InitializeSteam3(username, password))
            {
                await ContentDownloader.DownloadAppAsync(appId, depotId, branch, os, forceDepot).ConfigureAwait(false);

                ContentDownloader.ShutdownSteam3();
            }
        }
Пример #3
0
        private static async Task DownloadSteam3Async(uint appId, List <DepotDownloadInfo> depots)
        {
            ulong TotalBytesCompressed   = 0;
            ulong TotalBytesUncompressed = 0;

            foreach (var depot in depots)
            {
                ulong DepotBytesCompressed   = 0;
                ulong DepotBytesUncompressed = 0;

                Console.WriteLine("Downloading depot {0} - {1}", depot.id, depot.contentName);

                CancellationTokenSource cts = new CancellationTokenSource();
                cdnPool.ExhaustedToken = cts;

                ProtoManifest oldProtoManifest = null;
                ProtoManifest newProtoManifest = null;
                string        configDir        = Path.Combine(depot.installDir, CONFIG_DIR);

                ulong lastManifestId = INVALID_MANIFEST_ID;
                ConfigStore.TheConfig.LastManifests.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();

                if (lastManifestId != INVALID_MANIFEST_ID)
                {
                    var oldManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", lastManifestId));
                    if (File.Exists(oldManifestFileName))
                    {
                        oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName);
                    }
                }

                if (lastManifestId == depot.manifestId && oldProtoManifest != null)
                {
                    newProtoManifest = oldProtoManifest;
                    Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id);
                }
                else
                {
                    var newManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", depot.manifestId));
                    if (newManifestFileName != null)
                    {
                        newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName);
                    }

                    if (newProtoManifest != null)
                    {
                        Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id);
                    }
                    else
                    {
                        Console.Write("Downloading depot manifest...");

                        DepotManifest depotManifest = null;

                        while (depotManifest == null)
                        {
                            CDNClient client = null;
                            try
                            {
                                client = await cdnPool.GetConnectionForDepotAsync(appId, depot.id, depot.depotKey, CancellationToken.None).ConfigureAwait(false);

                                depotManifest = await client.DownloadManifestAsync(depot.id, depot.manifestId).ConfigureAwait(false);

                                cdnPool.ReturnConnection(client);
                            }
                            catch (WebException e)
                            {
                                cdnPool.ReturnBrokenConnection(client);

                                if (e.Status == WebExceptionStatus.ProtocolError)
                                {
                                    var response = e.Response as HttpWebResponse;
                                    if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
                                    {
                                        Console.WriteLine("Encountered 401 for depot manifest {0} {1}. Aborting.", depot.id, depot.manifestId);
                                        break;
                                    }
                                    else
                                    {
                                        Console.WriteLine("Encountered error downloading depot manifest {0} {1}: {2}", depot.id, depot.manifestId, response.StatusCode);
                                    }
                                }
                                else
                                {
                                    Console.WriteLine("Encountered error downloading manifest for depot {0} {1}: {2}", depot.id, depot.manifestId, e.Status);
                                }
                            }
                            catch (Exception e)
                            {
                                cdnPool.ReturnBrokenConnection(client);
                                Console.WriteLine("Encountered error downloading manifest for depot {0} {1}: {2}", depot.id, depot.manifestId, e.Message);
                            }
                        }

                        if (depotManifest == null)
                        {
                            Console.WriteLine("\nUnable to download manifest {0} for depot {1}", depot.manifestId, depot.id);
                            return;
                        }

                        newProtoManifest = new ProtoManifest(depotManifest, depot.manifestId);
                        newProtoManifest.SaveToFile(newManifestFileName);

                        Console.WriteLine(" Done!");
                    }
                }

                newProtoManifest.Files.Sort((x, y) => { return(x.FileName.CompareTo(y.FileName)); });

                if (Config.DownloadManifestOnly)
                {
                    StringBuilder manifestBuilder = new StringBuilder();
                    string        txtManifest     = Path.Combine(depot.installDir, string.Format("manifest_{0}.txt", depot.id));

                    foreach (var file in newProtoManifest.Files)
                    {
                        if (file.Flags.HasFlag(EDepotFileFlag.Directory))
                        {
                            continue;
                        }

                        manifestBuilder.Append(string.Format("{0}\n", file.FileName));
                    }

                    File.WriteAllText(txtManifest, manifestBuilder.ToString());
                    continue;
                }

                ulong  complete_download_size = 0;
                ulong  size_downloaded        = 0;
                string stagingDir             = Path.Combine(depot.installDir, STAGING_DIR);

                var filesAfterExclusions = newProtoManifest.Files.AsParallel().Where(f => TestIsFileIncluded(f.FileName)).ToList();

                // Pre-process
                filesAfterExclusions.ForEach(file =>
                {
                    var fileFinalPath   = Path.Combine(depot.installDir, file.FileName);
                    var fileStagingPath = Path.Combine(stagingDir, file.FileName);

                    if (file.Flags.HasFlag(EDepotFileFlag.Directory))
                    {
                        Directory.CreateDirectory(fileFinalPath);
                        Directory.CreateDirectory(fileStagingPath);
                    }
                    else
                    {
                        // Some manifests don't explicitly include all necessary directories
                        Directory.CreateDirectory(Path.GetDirectoryName(fileFinalPath));
                        Directory.CreateDirectory(Path.GetDirectoryName(fileStagingPath));

                        complete_download_size += file.TotalSize;
                    }
                });

                var semaphore = new SemaphoreSlim(Config.MaxDownloads);
                var files     = filesAfterExclusions.Where(f => !f.Flags.HasFlag(EDepotFileFlag.Directory)).ToArray();
                var tasks     = new Task[files.Length];
                for (var i = 0; i < files.Length; i++)
                {
                    var file = files[i];
                    var task = Task.Run(async() =>
                    {
                        cts.Token.ThrowIfCancellationRequested();

                        try
                        {
                            await semaphore.WaitAsync().ConfigureAwait(false);
                            cts.Token.ThrowIfCancellationRequested();

                            string fileFinalPath   = Path.Combine(depot.installDir, file.FileName);
                            string fileStagingPath = Path.Combine(stagingDir, file.FileName);

                            // This may still exist if the previous run exited before cleanup
                            if (File.Exists(fileStagingPath))
                            {
                                File.Delete(fileStagingPath);
                            }

                            FileStream fs = null;
                            List <ProtoManifest.ChunkData> neededChunks;
                            FileInfo fi = new FileInfo(fileFinalPath);
                            if (!fi.Exists)
                            {
                                // create new file. need all chunks
                                fs = File.Create(fileFinalPath);
                                fs.SetLength(( long )file.TotalSize);
                                neededChunks = new List <ProtoManifest.ChunkData>(file.Chunks);
                            }
                            else
                            {
                                // open existing
                                ProtoManifest.FileData oldManifestFile = null;
                                if (oldProtoManifest != null)
                                {
                                    oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName);
                                }

                                if (oldManifestFile != null)
                                {
                                    neededChunks = new List <ProtoManifest.ChunkData>();

                                    if (Config.VerifyAll || !oldManifestFile.FileHash.SequenceEqual(file.FileHash))
                                    {
                                        // we have a version of this file, but it doesn't fully match what we want

                                        var matchingChunks = new List <ChunkMatch>();

                                        foreach (var chunk in file.Chunks)
                                        {
                                            var oldChunk = oldManifestFile.Chunks.FirstOrDefault(c => c.ChunkID.SequenceEqual(chunk.ChunkID));
                                            if (oldChunk != null)
                                            {
                                                matchingChunks.Add(new ChunkMatch(oldChunk, chunk));
                                            }
                                            else
                                            {
                                                neededChunks.Add(chunk);
                                            }
                                        }

                                        File.Move(fileFinalPath, fileStagingPath);

                                        fs = File.Open(fileFinalPath, FileMode.Create);
                                        fs.SetLength(( long )file.TotalSize);

                                        using (var fsOld = File.Open(fileStagingPath, FileMode.Open))
                                        {
                                            foreach (var match in matchingChunks)
                                            {
                                                fsOld.Seek(( long )match.OldChunk.Offset, SeekOrigin.Begin);

                                                byte[] tmp = new byte[match.OldChunk.UncompressedLength];
                                                fsOld.Read(tmp, 0, tmp.Length);

                                                byte[] adler = Util.AdlerHash(tmp);
                                                if (!adler.SequenceEqual(match.OldChunk.Checksum))
                                                {
                                                    neededChunks.Add(match.NewChunk);
                                                }
                                                else
                                                {
                                                    fs.Seek(( long )match.NewChunk.Offset, SeekOrigin.Begin);
                                                    fs.Write(tmp, 0, tmp.Length);
                                                }
                                            }
                                        }

                                        File.Delete(fileStagingPath);
                                    }
                                }
                                else
                                {
                                    // No old manifest or file not in old manifest. We must validate.

                                    fs = File.Open(fileFinalPath, FileMode.Open);
                                    if (( ulong )fi.Length != file.TotalSize)
                                    {
                                        fs.SetLength(( long )file.TotalSize);
                                    }

                                    neededChunks = Util.ValidateSteam3FileChecksums(fs, file.Chunks.OrderBy(x => x.Offset).ToArray());
                                }

                                if (neededChunks.Count() == 0)
                                {
                                    size_downloaded += file.TotalSize;
                                    Console.WriteLine("{0,6:#00.00}% {1}", (( float )size_downloaded / ( float )complete_download_size) * 100.0f, fileFinalPath);
                                    if (fs != null)
                                    {
                                        fs.Dispose();
                                    }
                                    return;
                                }
                                else
                                {
                                    size_downloaded += (file.TotalSize - ( ulong )neededChunks.Select(x => ( long )x.UncompressedLength).Sum());
                                }
                            }

                            foreach (var chunk in neededChunks)
                            {
                                if (cts.IsCancellationRequested)
                                {
                                    break;
                                }

                                string chunkID = Util.EncodeHexString(chunk.ChunkID);
                                CDNClient.DepotChunk chunkData = null;

                                while (!cts.IsCancellationRequested)
                                {
                                    CDNClient client;
                                    try
                                    {
                                        client = await cdnPool.GetConnectionForDepotAsync(appId, depot.id, depot.depotKey, cts.Token).ConfigureAwait(false);
                                    }
                                    catch (OperationCanceledException)
                                    {
                                        break;
                                    }

                                    DepotManifest.ChunkData data = new DepotManifest.ChunkData();
                                    data.ChunkID            = chunk.ChunkID;
                                    data.Checksum           = chunk.Checksum;
                                    data.Offset             = chunk.Offset;
                                    data.CompressedLength   = chunk.CompressedLength;
                                    data.UncompressedLength = chunk.UncompressedLength;

                                    try
                                    {
                                        chunkData = await client.DownloadDepotChunkAsync(depot.id, data).ConfigureAwait(false);
                                        cdnPool.ReturnConnection(client);
                                        break;
                                    }
                                    catch (WebException e)
                                    {
                                        cdnPool.ReturnBrokenConnection(client);

                                        if (e.Status == WebExceptionStatus.ProtocolError)
                                        {
                                            var response = e.Response as HttpWebResponse;
                                            if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
                                            {
                                                Console.WriteLine("Encountered 401 for chunk {0}. Aborting.", chunkID);
                                                cts.Cancel();
                                                break;
                                            }
                                            else
                                            {
                                                Console.WriteLine("Encountered error downloading chunk {0}: {1}", chunkID, response.StatusCode);
                                            }
                                        }
                                        else
                                        {
                                            Console.WriteLine("Encountered error downloading chunk {0}: {1}", chunkID, e.Status);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        cdnPool.ReturnBrokenConnection(client);
                                        Console.WriteLine("Encountered unexpected error downloading chunk {0}: {1}", chunkID, e.Message);
                                    }
                                }

                                if (chunkData == null)
                                {
                                    Console.WriteLine("Failed to find any server with chunk {0} for depot {1}. Aborting.", chunkID, depot.id);
                                    cts.Cancel();
                                    return;
                                }

                                TotalBytesCompressed   += chunk.CompressedLength;
                                DepotBytesCompressed   += chunk.CompressedLength;
                                TotalBytesUncompressed += chunk.UncompressedLength;
                                DepotBytesUncompressed += chunk.UncompressedLength;

                                fs.Seek(( long )chunk.Offset, SeekOrigin.Begin);
                                fs.Write(chunkData.Data, 0, chunkData.Data.Length);

                                size_downloaded += chunk.UncompressedLength;
                            }

                            fs.Dispose();

                            Console.WriteLine("{0,6:#00.00}% {1}", (( float )size_downloaded / ( float )complete_download_size) * 100.0f, fileFinalPath);
                        }
                        finally
                        {
                            semaphore.Release();
                        }
                    });

                    tasks[i] = task;
                }

                await Task.WhenAll(tasks).ConfigureAwait(false);

                ConfigStore.TheConfig.LastManifests[depot.id] = depot.manifestId;
                ConfigStore.Save();

                Console.WriteLine("Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.id, DepotBytesCompressed, DepotBytesUncompressed);
            }

            Console.WriteLine("Total downloaded: {0} bytes ({1} bytes uncompressed) from {2} depots", TotalBytesCompressed, TotalBytesUncompressed, depots.Count);
        }
Пример #4
0
        static async Task MainAsync(string[] args)
        {
            if (args.Length == 0)
            {
                PrintUsage();
                return;
            }

            DebugLog.Enabled = false;

            ConfigStore.LoadFromFile(Path.Combine(Directory.GetCurrentDirectory(), "DepotDownloader.config"));

            #region Common Options

            string username = GetParameter <string>(args, "-username") ?? GetParameter <string>(args, "-user");
            string password = GetParameter <string>(args, "-password") ?? GetParameter <string>(args, "-pass");
            ContentDownloader.Config.RememberPassword = HasParameter(args, "-remember-password");

            ContentDownloader.Config.DownloadManifestOnly = HasParameter(args, "-manifest-only");

            int cellId = GetParameter <int>(args, "-cellid", -1);
            if (cellId == -1)
            {
                cellId = 0;
            }

            ContentDownloader.Config.CellID = cellId;

            string   fileList = GetParameter <string>(args, "-filelist");
            string[] files    = null;

            if (fileList != null)
            {
                try
                {
                    string fileListData = File.ReadAllText(fileList);
                    files = fileListData.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

                    ContentDownloader.Config.UsingFileList        = true;
                    ContentDownloader.Config.FilesToDownload      = new List <string>();
                    ContentDownloader.Config.FilesToDownloadRegex = new List <Regex>();

                    foreach (var fileEntry in files)
                    {
                        try
                        {
                            Regex rgx = new Regex(fileEntry, RegexOptions.Compiled | RegexOptions.IgnoreCase);
                            ContentDownloader.Config.FilesToDownloadRegex.Add(rgx);
                        }
                        catch
                        {
                            ContentDownloader.Config.FilesToDownload.Add(fileEntry);
                            continue;
                        }
                    }

                    Console.WriteLine("Using filelist: '{0}'.", fileList);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Warning: Unable to load filelist: {0}", ex.ToString());
                }
            }

            ContentDownloader.Config.InstallDirectory = GetParameter <string>(args, "-dir");

            ContentDownloader.Config.VerifyAll    = HasParameter(args, "-verify-all") || HasParameter(args, "-verify_all") || HasParameter(args, "-validate");
            ContentDownloader.Config.MaxServers   = GetParameter <int>(args, "-max-servers", 20);
            ContentDownloader.Config.MaxDownloads = GetParameter <int>(args, "-max-downloads", 4);
            ContentDownloader.Config.MaxServers   = Math.Max(ContentDownloader.Config.MaxServers, ContentDownloader.Config.MaxDownloads);

            #endregion

            ulong pubFile = GetParameter <ulong>(args, "-pubfile", ContentDownloader.INVALID_MANIFEST_ID);
            if (pubFile != ContentDownloader.INVALID_MANIFEST_ID)
            {
                #region Pubfile Downloading

                if (InitializeSteam(username, password))
                {
                    await ContentDownloader.DownloadPubfileAsync(pubFile).ConfigureAwait(false);

                    ContentDownloader.ShutdownSteam3();
                }

                #endregion
            }
            else
            {
                #region App downloading

                string branch = GetParameter <string>(args, "-branch") ?? GetParameter <string>(args, "-beta") ?? ContentDownloader.DEFAULT_BRANCH;
                ContentDownloader.Config.BetaPassword = GetParameter <string>(args, "-betapassword");

                ContentDownloader.Config.DownloadAllPlatforms = HasParameter(args, "-all-platforms");
                string os = GetParameter <string>(args, "-os", null);

                if (ContentDownloader.Config.DownloadAllPlatforms && !String.IsNullOrEmpty(os))
                {
                    Console.WriteLine("Error: Cannot specify -os when -all-platforms is specified.");
                    return;
                }

                uint appId = GetParameter <uint>(args, "-app", ContentDownloader.INVALID_APP_ID);
                if (appId == ContentDownloader.INVALID_APP_ID)
                {
                    Console.WriteLine("Error: -app not specified!");
                    return;
                }

                uint depotId;
                bool isUGC = false;

                ulong manifestId = GetParameter <ulong>(args, "-ugc", ContentDownloader.INVALID_MANIFEST_ID);
                if (manifestId != ContentDownloader.INVALID_MANIFEST_ID)
                {
                    depotId = appId;
                    isUGC   = true;
                }
                else
                {
                    depotId    = GetParameter <uint>(args, "-depot", ContentDownloader.INVALID_DEPOT_ID);
                    manifestId = GetParameter <ulong>(args, "-manifest", ContentDownloader.INVALID_MANIFEST_ID);
                    if (depotId == ContentDownloader.INVALID_DEPOT_ID && manifestId != ContentDownloader.INVALID_MANIFEST_ID)
                    {
                        Console.WriteLine("Error: -manifest requires -depot to be specified");
                        return;
                    }
                }

                if (InitializeSteam(username, password))
                {
                    await ContentDownloader.DownloadAppAsync(appId, depotId, manifestId, branch, os, isUGC).ConfigureAwait(false);

                    ContentDownloader.ShutdownSteam3();
                }

                #endregion
            }
        }
Пример #5
0
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                PrintUsage();
                return;
            }
            Program instance = new Program();

            DebugLog.Enabled = false;

            ConfigStore.LoadFromFile(Path.Combine(Environment.CurrentDirectory, "DepotDownloader.config"));

            instance.ParseOrPromptUserAndPassword(args);
            ParseGeneralContentDownloaderParams(args);
            ParseFileList(args);

            if (HasParameter(args, "-steamvrwin"))
            {
                instance.GetSteamVRWin();
                return;
            }
            if (HasParameter(args, "-steamvr"))
            {
                instance.GetSteamVR();
                return;
            }

            ContentDownloader.Config.DownloadManifestOnly = HasParameter(args, "-manifest-only");
            ContentDownloader.Config.BetaPassword         = GetParameter <string>(args, "-betapassword");

            var dir = GetParameter <string>(args, "-dir");


            var dl = new Downloadable();

            dl.AppId      = GetParameter <uint>(args, "-app", dl.AppId);
            dl.DepotId    = GetParameter <uint>(args, "-depot", dl.DepotId);
            dl.Branch     = GetBranch(args);
            dl.ManifestId = GetParameter <ulong>(args, "-manifest", dl.ManifestId);

            if (dl.AppId == ContentDownloader.INVALID_APP_ID)
            {
                Console.WriteLine("Error: -app not specified!");
                return;
            }

            if (dl.DepotId == ContentDownloader.INVALID_DEPOT_ID && dl.ManifestId != ContentDownloader.INVALID_MANIFEST_ID)
            {
                Console.WriteLine("Error: -manifest requires -depot to be specified");
                return;
            }

            dl.ForceDepot = HasParameter(args, "-force-depot");

            if (instance.Start())
            {
                instance.Download(dir, dl);
                instance.Shutdown();
            }
        }
Пример #6
0
        private void LogOnCallback(SteamUser.LoggedOnCallback loggedOn)
        {
            bool isSteamGuard = loggedOn.Result == EResult.AccountLogonDenied;
            bool is2FA        = loggedOn.Result == EResult.AccountLoginDeniedNeedTwoFactor;
            bool isLoginKey   = ContentDownloader.Config.RememberPassword && logonDetails.LoginKey != null && loggedOn.Result == EResult.InvalidPassword;

            if (isSteamGuard || is2FA || isLoginKey)
            {
                bExpectingDisconnectRemote = true;
                Abort(false);

                if (!isLoginKey)
                {
                    Console.WriteLine("This account is protected by Steam Guard.");
                }

                if (is2FA)
                {
                    Console.Write("Please enter your 2 factor auth code from your authenticator app: ");
                    logonDetails.TwoFactorCode = Console.ReadLine();
                }
                else if (isLoginKey)
                {
                    ConfigStore.TheConfig.LoginKeys.Remove(logonDetails.Username);
                    ConfigStore.Save();

                    logonDetails.LoginKey = null;

                    if (ContentDownloader.Config.SuppliedPassword != null)
                    {
                        Console.WriteLine("Login key was expired. Connecting with supplied password.");
                        logonDetails.Password = ContentDownloader.Config.SuppliedPassword;
                    }
                    else
                    {
                        Console.WriteLine("Login key was expired. Please enter your password: "******"Please enter the authentication code sent to your email address: ");
                    logonDetails.AuthCode = Console.ReadLine();
                }

                Console.Write("Retrying Steam3 connection...");
                Connect();

                return;
            }
            else if (loggedOn.Result == EResult.ServiceUnavailable)
            {
                Console.WriteLine("Unable to login to Steam3: {0}", loggedOn.Result);
                Abort(false);

                return;
            }
            else if (loggedOn.Result != EResult.OK)
            {
                Console.WriteLine("Unable to login to Steam3: {0}", loggedOn.Result);
                Abort();

                return;
            }

            Console.WriteLine(" Done!");

            this.seq++;
            credentials.LoggedOn = true;

            if (ContentDownloader.Config.CellID == 0)
            {
                Console.WriteLine("Using Steam3 suggested CellID: " + loggedOn.CellID);
                ContentDownloader.Config.CellID = ( int )loggedOn.CellID;
            }
        }
Пример #7
0
        private static void DownloadSteam3(List <DepotDownloadInfo> depots)
        {
            ulong TotalBytesCompressed   = 0;
            ulong TotalBytesUncompressed = 0;

            foreach (var depot in depots)
            {
                ulong DepotBytesCompressed   = 0;
                ulong DepotBytesUncompressed = 0;

                Console.WriteLine("Downloading depot {0} - {1}", depot.id, depot.contentName);
                Console.Write("Finding content servers...");

                List <CDNClient> cdnClients = null;

                Console.WriteLine(" Done!");

                ProtoManifest oldProtoManifest = null;
                ProtoManifest newProtoManifest = null;
                string        configDir        = Path.Combine(depot.installDir, CONFIG_DIR);

                ulong lastManifestId = INVALID_MANIFEST_ID;
                ConfigStore.TheConfig.LastManifests.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();

                if (lastManifestId != INVALID_MANIFEST_ID)
                {
                    var oldManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", lastManifestId));
                    if (File.Exists(oldManifestFileName))
                    {
                        oldProtoManifest = ProtoManifest.LoadFromFile(oldManifestFileName);
                    }
                }

                if (lastManifestId == depot.manifestId && oldProtoManifest != null)
                {
                    newProtoManifest = oldProtoManifest;
                    Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id);
                }
                else
                {
                    var newManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", depot.manifestId));
                    if (newManifestFileName != null)
                    {
                        newProtoManifest = ProtoManifest.LoadFromFile(newManifestFileName);
                    }

                    if (newProtoManifest != null)
                    {
                        Console.WriteLine("Already have manifest {0} for depot {1}.", depot.manifestId, depot.id);
                    }
                    else
                    {
                        Console.Write("Downloading depot manifest...");

                        DepotManifest depotManifest = null;

                        cdnClients = CollectCDNClientsForDepot(depot);

                        foreach (var c in cdnClients)
                        {
                            try
                            {
                                depotManifest = c.DownloadManifest(depot.manifestId);
                                break;
                            }
                            catch (WebException) { }
                            catch (SocketException) { }
                        }

                        if (depotManifest == null)
                        {
                            Console.WriteLine("\nUnable to download manifest {0} for depot {1}", depot.manifestId, depot.id);
                            return;
                        }

                        newProtoManifest = new ProtoManifest(depotManifest, depot.manifestId);
                        newProtoManifest.SaveToFile(newManifestFileName);

                        Console.WriteLine(" Done!");
                    }
                }

                newProtoManifest.Files.Sort((x, y) => { return(x.FileName.CompareTo(y.FileName)); });

                if (Config.DownloadManifestOnly)
                {
                    StringBuilder manifestBuilder = new StringBuilder();
                    string        txtManifest     = Path.Combine(depot.installDir, string.Format("manifest_{0}.txt", depot.id));

                    foreach (var file in newProtoManifest.Files)
                    {
                        if (file.Flags.HasFlag(EDepotFileFlag.Directory))
                        {
                            continue;
                        }

                        manifestBuilder.Append(string.Format("{0}\n", file.FileName));
                    }

                    File.WriteAllText(txtManifest, manifestBuilder.ToString());
                    continue;
                }

                ulong  complete_download_size = 0;
                ulong  size_downloaded        = 0;
                string stagingDir             = Path.Combine(depot.installDir, STAGING_DIR);

                var filesAfterExclusions = newProtoManifest.Files.AsParallel().Where(f => TestIsFileIncluded(f.FileName)).ToList();

                // Pre-process
                filesAfterExclusions.ForEach(file =>
                {
                    var fileFinalPath   = Path.Combine(depot.installDir, file.FileName);
                    var fileStagingPath = Path.Combine(stagingDir, file.FileName);

                    if (file.Flags.HasFlag(EDepotFileFlag.Directory))
                    {
                        Directory.CreateDirectory(fileFinalPath);
                        Directory.CreateDirectory(fileStagingPath);
                    }
                    else
                    {
                        // Some manifests don't explicitly include all necessary directories
                        Directory.CreateDirectory(Path.GetDirectoryName(fileFinalPath));
                        Directory.CreateDirectory(Path.GetDirectoryName(fileStagingPath));

                        complete_download_size += file.TotalSize;
                    }
                });

                var rand = new Random();

                filesAfterExclusions.Where(f => !f.Flags.HasFlag(EDepotFileFlag.Directory))
                .AsParallel().WithDegreeOfParallelism(Config.MaxDownloads)
                .ForAll(file =>
                {
                    string fileFinalPath   = Path.Combine(depot.installDir, file.FileName);
                    string fileStagingPath = Path.Combine(stagingDir, file.FileName);

                    // This may still exist if the previous run exited before cleanup
                    if (File.Exists(fileStagingPath))
                    {
                        File.Delete(fileStagingPath);
                    }

                    FileStream fs = null;
                    List <ProtoManifest.ChunkData> neededChunks;
                    FileInfo fi = new FileInfo(fileFinalPath);
                    if (!fi.Exists)
                    {
                        // create new file. need all chunks
                        fs = File.Create(fileFinalPath);
                        fs.SetLength((long)file.TotalSize);
                        neededChunks = new List <ProtoManifest.ChunkData>(file.Chunks);
                    }
                    else
                    {
                        // open existing
                        ProtoManifest.FileData oldManifestFile = null;
                        if (oldProtoManifest != null)
                        {
                            oldManifestFile = oldProtoManifest.Files.SingleOrDefault(f => f.FileName == file.FileName);
                        }

                        if (oldManifestFile != null)
                        {
                            neededChunks = new List <ProtoManifest.ChunkData>();

                            if (Config.VerifyAll || !oldManifestFile.FileHash.SequenceEqual(file.FileHash))
                            {
                                // we have a version of this file, but it doesn't fully match what we want

                                var matchingChunks = new List <ChunkMatch>();

                                foreach (var chunk in file.Chunks)
                                {
                                    var oldChunk = oldManifestFile.Chunks.FirstOrDefault(c => c.ChunkID.SequenceEqual(chunk.ChunkID));
                                    if (oldChunk != null)
                                    {
                                        matchingChunks.Add(new ChunkMatch(oldChunk, chunk));
                                    }
                                    else
                                    {
                                        neededChunks.Add(chunk);
                                    }
                                }

                                File.Move(fileFinalPath, fileStagingPath);

                                fs = File.Open(fileFinalPath, FileMode.Create);
                                fs.SetLength((long)file.TotalSize);

                                using (var fsOld = File.Open(fileStagingPath, FileMode.Open))
                                {
                                    foreach (var match in matchingChunks)
                                    {
                                        fs.Seek((long)match.NewChunk.Offset, SeekOrigin.Begin);
                                        fsOld.Seek((long)match.OldChunk.Offset, SeekOrigin.Begin);

                                        byte[] tmp = new byte[match.OldChunk.UncompressedLength];
                                        fsOld.Read(tmp, 0, tmp.Length);
                                        fs.Write(tmp, 0, tmp.Length);
                                    }
                                }

                                File.Delete(fileStagingPath);
                            }
                        }
                        else
                        {
                            // No old manifest or file not in old manifest. We must validate.

                            fs = File.Open(fileFinalPath, FileMode.Open);
                            if ((ulong)fi.Length != file.TotalSize)
                            {
                                fs.SetLength((long)file.TotalSize);
                            }

                            neededChunks = Util.ValidateSteam3FileChecksums(fs, file.Chunks.OrderBy(x => x.Offset).ToArray());
                        }

                        if (neededChunks.Count() == 0)
                        {
                            size_downloaded += file.TotalSize;
                            Console.WriteLine("{0,6:#00.00}% {1}", ((float)size_downloaded / (float)complete_download_size) * 100.0f, fileFinalPath);
                            if (fs != null)
                            {
                                fs.Close();
                            }
                            return;
                        }
                        else
                        {
                            size_downloaded += (file.TotalSize - (ulong)neededChunks.Select(x => (int)x.UncompressedLength).Sum());
                        }
                    }

                    int cdnClientIndex = 0;
                    if (neededChunks.Count > 0 && cdnClients == null)
                    {
                        // If we didn't need to connect to get manifests, connect now.
                        cdnClients     = CollectCDNClientsForDepot(depot);
                        cdnClientIndex = rand.Next(0, cdnClients.Count);
                    }

                    foreach (var chunk in neededChunks)
                    {
                        string chunkID = Util.EncodeHexString(chunk.ChunkID);

                        CDNClient.DepotChunk chunkData = null;
                        int idx = cdnClientIndex;
                        while (true)
                        {
                            DepotManifest.ChunkData data = new DepotManifest.ChunkData();
                            data.ChunkID            = chunk.ChunkID;
                            data.Checksum           = chunk.Checksum;
                            data.Offset             = chunk.Offset;
                            data.CompressedLength   = chunk.CompressedLength;
                            data.UncompressedLength = chunk.UncompressedLength;

                            try
                            {
                                chunkData = cdnClients[idx].DownloadDepotChunk(data);
                                break;
                            }
                            catch
                            {
                                if (++idx >= cdnClients.Count)
                                {
                                    idx = 0;
                                }

                                if (idx == cdnClientIndex)
                                {
                                    break;
                                }
                            }
                        }

                        if (chunkData == null)
                        {
                            Console.WriteLine("Failed to find any server with chunk {0} for depot {1}. Aborting.", chunkID, depot);
                            return;
                        }

                        TotalBytesCompressed   += chunk.CompressedLength;
                        DepotBytesCompressed   += chunk.CompressedLength;
                        TotalBytesUncompressed += chunk.UncompressedLength;
                        DepotBytesUncompressed += chunk.UncompressedLength;

                        fs.Seek((long)chunk.Offset, SeekOrigin.Begin);
                        fs.Write(chunkData.Data, 0, chunkData.Data.Length);

                        size_downloaded += chunk.UncompressedLength;
                    }

                    fs.Close();

                    Console.WriteLine("{0,6:#00.00}% {1}", ((float)size_downloaded / (float)complete_download_size) * 100.0f, fileFinalPath);
                });

                ConfigStore.TheConfig.LastManifests[depot.id] = depot.manifestId;
                ConfigStore.Save();

                Console.WriteLine("Depot {0} - Downloaded {1} bytes ({2} bytes uncompressed)", depot.id, DepotBytesCompressed, DepotBytesUncompressed);
            }

            Console.WriteLine("Total downloaded: {0} bytes ({1} bytes uncompressed) from {2} depots", TotalBytesCompressed, TotalBytesUncompressed, depots.Count);
        }
Пример #8
0
        private void LogOnCallback(SteamUser.LoggedOnCallback loggedOn)
        {
            isLoggingIn = false;

            if (logonDetails != null)
            {
                bool isSteamGuard = loggedOn.Result == EResult.AccountLogonDenied;
                bool is2FA        = loggedOn.Result == EResult.AccountLoginDeniedNeedTwoFactor;
                bool isLoginKey   = logonDetails.ShouldRememberPassword && logonDetails.LoginKey != null && loggedOn.Result == EResult.InvalidPassword;
                if (isSteamGuard || is2FA || isLoginKey)
                {
                    bExpectingDisconnectRemote = true;
                    Abort(false);

                    if (!isLoginKey)
                    {
                        DebugLog.WriteLine("Steam3Session", "This account is protected by Steam Guard.");
                    }

                    if (is2FA)
                    {
                        DebugLog.WriteLine("Steam3Session", "Please enter your 2 factor auth code from your authenticator app: ");
                        on2faRequired?.Invoke(loggedOn.Result);
                        //logonDetails.TwoFactorCode = Console.ReadLine();
                    }
                    else if (isLoginKey)
                    {
                        ConfigStore.TheConfig.LoginKeys.Remove(logonDetails.Username);
                        ConfigStore.Save();

                        logonDetails.LoginKey = null;

                        DebugLog.WriteLine("Steam3Session", "Login key was expired. Please enter your password: "******"Steam3Session", "Please enter the authentication code sent to your email address: ");
                        onAuthRequired?.Invoke(loggedOn.Result);
                        //logonDetails.AuthCode = Console.ReadLine();
                    }

                    //DebugLog.WriteLine("Steam3Session",  "Retrying Steam3 connection..." );
                    //Connect();
                    onLogonFailed?.Invoke(loggedOn.Result);

                    return;
                }
                else if (loggedOn.Result == EResult.ServiceUnavailable)
                {
                    DebugLog.WriteLine("Steam3Session", "Unable to login to Steam3: " + loggedOn.Result);
                    Abort(false);

                    onLogonFailed?.Invoke(loggedOn.Result);
                    return;
                }
                else if (loggedOn.Result != EResult.OK)
                {
                    DebugLog.WriteLine("Steam3Session", "Unable to login to Steam3: " + loggedOn.Result);
                    Abort();

                    onLogonFailed?.Invoke(loggedOn.Result);
                    return;
                }
            }

            DebugLog.WriteLine("Steam3Session", " Done!");
            DebugLog.WriteLine("Steam3Session", "Using Steam3 suggested CellID: " + loggedOn.CellID);
            ContentDownloader.Config.CellID = (int)loggedOn.CellID;

            onLoggedOn?.Invoke();
        }