From e5d2c87676efb878015b4022bbaa473dfc43b9a9 Mon Sep 17 00:00:00 2001 From: Sude Date: Thu, 22 Aug 2024 13:05:50 +0300 Subject: [PATCH] Galaxy: Refactor CDN priority handling Make CDN url template handling more generic Add option to list available CDNs Change default Galaxy CDN priority to "edgecast,akamai_edgecast_proxy,fastly" --- include/config.h | 3 +- include/downloader.h | 2 ++ include/galaxyapi.h | 2 +- include/globalconstants.h | 16 ---------- main.cpp | 24 ++++++++++----- man/lgogdownloader.1 | 23 +++++++------- src/downloader.cpp | 63 +++++++++++++++++++++++++++++++++++++++ src/galaxyapi.cpp | 43 ++++++++------------------ 8 files changed, 108 insertions(+), 68 deletions(-) diff --git a/include/config.h b/include/config.h index e0c4ad8..5567073 100644 --- a/include/config.h +++ b/include/config.h @@ -36,7 +36,7 @@ struct DownloadConfig unsigned int iGalaxyCDN; std::vector vPlatformPriority; std::vector vLanguagePriority; - std::vector vGalaxyCDNPriority; + std::vector vGalaxyCDNPriority; std::vector vTags; unsigned int iInclude; unsigned int iGalaxyPlatform; @@ -256,6 +256,7 @@ class Config #endif bool bUseFastCheck; bool bTrustAPIForExtras; + bool bGalaxyListCDNs; // Cache bool bUseCache; diff --git a/include/downloader.h b/include/downloader.h index 6c0843f..08d6164 100644 --- a/include/downloader.h +++ b/include/downloader.h @@ -124,6 +124,8 @@ class Downloader void galaxyInstallGame(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); void galaxyInstallGameById(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64); + void galaxyListCDNs(const std::string& product_id, int build_index = -1); + void galaxyListCDNsById(const std::string& product_id, int build_index = -1); void galaxyShowBuilds(const std::string& product_id, int build_index = -1); void galaxyShowCloudSaves(const std::string& product_id, int build_index = -1); void galaxyShowLocalCloudSaves(const std::string& product_id, int build_index = -1); diff --git a/include/galaxyapi.h b/include/galaxyapi.h index dd60b56..7121265 100644 --- a/include/galaxyapi.h +++ b/include/galaxyapi.h @@ -68,7 +68,7 @@ class galaxyAPI Json::Value getDependenciesJson(); std::vector getFilteredDepotItemsVectorFromJson(const Json::Value& depot_json, const std::string& galaxy_language, const std::string& galaxy_arch, const bool& is_dependency = false); std::string getPathFromDownlinkUrl(const std::string& downlink_url, const std::string& gamename); - std::vector cdnUrlTemplatesFromJson(const Json::Value& json, const std::vector& cdnPriority); + std::vector cdnUrlTemplatesFromJson(const Json::Value& json, const std::vector& cdnPriority); protected: private: CurlConfig curlConf; diff --git a/include/globalconstants.h b/include/globalconstants.h index 45927d8..8dfc537 100644 --- a/include/globalconstants.h +++ b/include/globalconstants.h @@ -102,22 +102,6 @@ namespace GlobalConstants { ARCH_X64, "64", "64-bit", "64|x64|64bit|64-bit" } }; - // Galaxy CDNs - const unsigned int CDN_EDGECAST = 1 << 0; - const unsigned int CDN_HIGHWINDS = 1 << 1; - const unsigned int CDN_GOG = 1 << 2; - const unsigned int CDN_LUMEN = 1 << 3; - const unsigned int CDN_AKAMAI = 1 << 4; - - const std::vector GALAXY_CDNS = - { - { CDN_EDGECAST, "edgecast", "Edgecast", "ec|edgecast" }, - { CDN_HIGHWINDS, "high_winds", "Highwinds", "hw|highwinds|high_winds" }, - { CDN_GOG, "gog_cdn", "GOG", "gog|gog_cdn" }, - { CDN_LUMEN, "lumen", "Lumen", "lumen|lumen_cdn" }, - { CDN_AKAMAI, "akamai_edgecast_proxy", "Akamai", "akamai|akamai_cdn|akamai_ec|akamai_edgecast_proxy" } - }; - const unsigned int LIST_FORMAT_GAMES = 1 << 0; const unsigned int LIST_FORMAT_DETAILS_TEXT = 1 << 1; const unsigned int LIST_FORMAT_DETAILS_JSON = 1 << 2; diff --git a/main.cpp b/main.cpp index e6c4285..f3076a7 100644 --- a/main.cpp +++ b/main.cpp @@ -125,11 +125,8 @@ int main(int argc, char *argv[]) // Create help text for --galaxy-cdn-priority option std::string galaxy_cdn_priority_text = "Set priority for used CDNs\n"; - for (unsigned int i = 0; i < GlobalConstants::GALAXY_CDNS.size(); ++i) - { - galaxy_cdn_priority_text += GlobalConstants::GALAXY_CDNS[i].str + " = " + GlobalConstants::GALAXY_CDNS[i].regexp + "\n"; - } - galaxy_cdn_priority_text += "\n" + priority_help_text; + galaxy_cdn_priority_text += "Use --galaxy-list-cdns to list available CDNs\n"; + galaxy_cdn_priority_text += "Set priority by separating values with \",\""; // Create help text for --check-orphans std::string orphans_regex_default = ".*\\.(zip|exe|bin|dmg|old|deb|tar\\.gz|pkg|sh|mp4)$"; // Limit to files with these extensions (".old" is for renamed older version files) @@ -155,6 +152,7 @@ int main(int argc, char *argv[]) } std::string galaxy_product_id_install; + std::string galaxy_product_id_list_cdns; std::string galaxy_product_id_show_builds; std::string galaxy_product_id_show_cloud_paths; std::string galaxy_product_id_show_local_cloud_paths; @@ -313,7 +311,8 @@ int main(int argc, char *argv[]) ("galaxy-arch", bpo::value(&sGalaxyArch)->default_value("x64"), galaxy_arch_text.c_str()) ("galaxy-no-dependencies", bpo::value(&bNoGalaxyDependencies)->zero_tokens()->default_value(false), "Don't download dependencies during --galaxy-install") ("subdir-galaxy-install", bpo::value(&Globals::globalConfig.dirConf.sGalaxyInstallSubdir)->default_value("%install_dir%"), galaxy_install_subdir_text.c_str()) - ("galaxy-cdn-priority", bpo::value(&sGalaxyCDN)->default_value("edgecast,highwinds,akamai,lumen,gog_cdn"), galaxy_cdn_priority_text.c_str()) + ("galaxy-cdn-priority", bpo::value(&sGalaxyCDN)->default_value("edgecast,akamai_edgecast_proxy,fastly"), galaxy_cdn_priority_text.c_str()) + ("galaxy-list-cdns", bpo::value(&galaxy_product_id_list_cdns)->default_value(""), "List available CDNs for game using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345") ; options_cli_all.add(options_cli_no_cfg).add(options_cli_cfg).add(options_cli_experimental); @@ -577,7 +576,7 @@ int main(int argc, char *argv[]) if (Globals::globalConfig.dlConf.iGalaxyArch == 0 || Globals::globalConfig.dlConf.iGalaxyArch == Util::getOptionValue("all", GlobalConstants::GALAXY_ARCHS, false)) Globals::globalConfig.dlConf.iGalaxyArch = GlobalConstants::ARCH_X64; - Util::parseOptionString(sGalaxyCDN, Globals::globalConfig.dlConf.vGalaxyCDNPriority, Globals::globalConfig.dlConf.iGalaxyCDN, GlobalConstants::GALAXY_CDNS); + Globals::globalConfig.dlConf.vGalaxyCDNPriority = Util::tokenize(sGalaxyCDN, ","); unsigned int include_value = 0; unsigned int exclude_value = 0; @@ -876,6 +875,17 @@ int main(int argc, char *argv[]) } downloader.galaxyInstallGame(product_id, build_index, Globals::globalConfig.dlConf.iGalaxyArch); } + else if (!galaxy_product_id_list_cdns.empty()) + { + int build_index = -1; + std::vector tokens = Util::tokenize(galaxy_product_id_list_cdns, "/"); + std::string product_id = tokens[0]; + if (tokens.size() == 2) + { + build_index = std::stoi(tokens[1]); + } + downloader.galaxyListCDNs(product_id, build_index); + } else if (!galaxy_product_cloud_saves.empty()) { int build_index = -1; std::vector tokens = Util::tokenize(galaxy_product_cloud_saves, "/"); diff --git a/man/lgogdownloader.1 b/man/lgogdownloader.1 index 1629145..54abdc8 100644 --- a/man/lgogdownloader.1 +++ b/man/lgogdownloader.1 @@ -561,24 +561,21 @@ is removed: .br > \- _ . ( ) [ ] { } .TP -\fB\-\-galaxy\-cdn\-priority\fR arg (=edgecast,highwinds,akamai,lumen,gog_cdn) +\fB\-\-galaxy\-cdn\-priority\fR arg (=edgecast,akamai_edgecast_proxy,fastly) Set priority for used CDNs .br -Edgecast = ec|edgecast +Use \-\-galaxy\-list\-cdns to list available CDNs .br -Highwinds = hw|highwinds|high_winds -.br -GOG = gog|gog_cdn -.br -Lumen = lumen|lumen_cdn -.br -Akamai = akamai|akamai_cdn|akamai_ec|ak -.br -amai_edgecast_proxy -.sp 1 Set priority by separating values with "," +.TP +\fB\-\-galaxy\-list-cdns\fR arg +List available CDNs for a game using product id [product_id/build_index] or +gamename regex [gamename/build_id] +.br +Build index is used to select a build and defaults to 0 if not specified. +.br +Example: 12345/2 selects build 2 for product 12345 .br -Combine values by separating with "+" .SH LANGUAGES Languages available to select with \fB\-\-language\fR and \fB\-\-galaxy\-language\fR options .br diff --git a/src/downloader.cpp b/src/downloader.cpp index 8e3a1f7..535f0ff 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -4159,6 +4159,69 @@ void Downloader::galaxyInstallGameById(const std::string& product_id, int build_ } } +void Downloader::galaxyListCDNs(const std::string& product_id, int build_index) +{ + std::string id; + if(this->galaxySelectProductIdHelper(product_id, id)) + { + if (!id.empty()) + this->galaxyListCDNsById(id, build_index); + } +} + +void Downloader::galaxyListCDNsById(const std::string& product_id, int build_index) +{ + if (build_index < 0) + build_index = 0; + + std::string sPlatform; + unsigned int iPlatform = Globals::globalConfig.dlConf.iGalaxyPlatform; + if (iPlatform == GlobalConstants::PLATFORM_LINUX) + sPlatform = "linux"; + else if (iPlatform == GlobalConstants::PLATFORM_MAC) + sPlatform = "osx"; + else + sPlatform = "windows"; + + Json::Value json = gogGalaxy->getProductBuilds(product_id, sPlatform); + + // JSON is empty and platform is Linux. Most likely cause is that Galaxy API doesn't have Linux support + if (json.empty() && iPlatform == GlobalConstants::PLATFORM_LINUX) + { + std::cout << "Galaxy API doesn't have Linux support" << std::endl; + + return; + } + + if (json["items"][build_index]["generation"].asInt() != 2) + { + std::cout << "Only generation 2 builds are supported currently" << std::endl; + return; + } + + std::string link = json["items"][build_index]["link"].asString(); + std::string buildHash; + buildHash.assign(link.begin()+link.find_last_of("/")+1, link.end()); + + json = gogGalaxy->getSecureLink(product_id, "/"); + + std::vector vEndpointNames; + if (!json.empty()) + { + for (unsigned int i = 0; i < json["urls"].size(); ++i) + { + std::string endpoint_name = json["urls"][i]["endpoint_name"].asString(); + if (!endpoint_name.empty()) + vEndpointNames.push_back(endpoint_name); + } + } + + for (auto endpoint : vEndpointNames) + std::cout << endpoint << std::endl; + + return; +} + void Downloader::processGalaxyDownloadQueue(const std::string& install_path, Config conf, const unsigned int& tid) { std::string msg_prefix = "[Thread #" + std::to_string(tid) + "]"; diff --git a/src/galaxyapi.cpp b/src/galaxyapi.cpp index ce8a6b1..56d5745 100644 --- a/src/galaxyapi.cpp +++ b/src/galaxyapi.cpp @@ -590,7 +590,7 @@ std::string galaxyAPI::getPathFromDownlinkUrl(const std::string& downlink_url, c return path; } -std::vector galaxyAPI::cdnUrlTemplatesFromJson(const Json::Value& json, const std::vector& cdnPriority) +std::vector galaxyAPI::cdnUrlTemplatesFromJson(const Json::Value& json, const std::vector& cdnPriority) { // Handle priority of CDNs struct urlPriority @@ -606,10 +606,9 @@ std::vector galaxyAPI::cdnUrlTemplatesFromJson(const Json::Value& j std::string endpoint_name = json["urls"][i]["endpoint_name"].asString(); unsigned int score = cdnPriority.size(); - unsigned int cdn = Util::getOptionValue(endpoint_name, GlobalConstants::GALAXY_CDNS, false); for (unsigned int idx = 0; idx < score; ++idx) { - if (cdn & cdnPriority[idx]) + if (endpoint_name == cdnPriority[idx]) { score = idx; break; @@ -625,36 +624,20 @@ std::vector galaxyAPI::cdnUrlTemplatesFromJson(const Json::Value& j } // Build url according to url_format - std::string link_base_url = json["urls"][i]["parameters"]["base_url"].asString(); - std::string link_path = json["urls"][i]["parameters"]["path"].asString(); - std::string link_token = json["urls"][i]["parameters"]["token"].asString(); - - // Add our own template to path - link_path += "{LGOGDOWNLOADER_GALAXY_PATH}"; - std::string url = json["urls"][i]["url_format"].asString(); + for (auto cdn_url_template_param : json["urls"][i]["parameters"].getMemberNames()) + { + std::string template_to_replace = "{" + cdn_url_template_param + "}"; + std::string replacement = json["urls"][i]["parameters"][cdn_url_template_param].asString(); - while(Util::replaceString(url, "{base_url}", link_base_url)); - while(Util::replaceString(url, "{path}", link_path)); - while(Util::replaceString(url, "{token}", link_token)); + // Add our own template to path + if (template_to_replace == "{path}") + { + replacement += "{LGOGDOWNLOADER_GALAXY_PATH}"; + } - // Highwinds specific - std::string link_hw_l= json["urls"][i]["parameters"]["l"].asString(); - std::string link_hw_source = json["urls"][i]["parameters"]["source"].asString(); - std::string link_hw_ttl = json["urls"][i]["parameters"]["ttl"].asString(); - std::string link_hw_gog_token = json["urls"][i]["parameters"]["gog_token"].asString(); - - while(Util::replaceString(url, "{l}", link_hw_l)); - while(Util::replaceString(url, "{source}", link_hw_source)); - while(Util::replaceString(url, "{ttl}", link_hw_ttl)); - while(Util::replaceString(url, "{gog_token}", link_hw_gog_token)); - - // Lumen specific - std::string dirs = json["urls"][i]["parameters"]["dirs"].asString(); - std::string expires_at = json["urls"][i]["parameters"]["expires_at"].asString(); - - while(Util::replaceString(url, "{dirs}", dirs)); - while(Util::replaceString(url, "{expires_at}", expires_at)); + while(Util::replaceString(url, template_to_replace, replacement)); + } urlPriority cdnurl; cdnurl.url = url;