From 9ade941de121eb5476e1a3bff4dcc4e57cd2b16d Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sun, 4 Feb 2024 16:51:52 +0100 Subject: [PATCH 1/3] web_backend: Sync with Citra implementation While porting https://github.com/citra-emu/citra/pull/7347, I noticed the code of yuzu was not up-to-date with the implementation from Citra. --- src/web_service/web_backend.cpp | 41 ++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index dff380ccaa..f41d8af0e8 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -32,9 +32,14 @@ struct Client::Impl { Impl(std::string host_, std::string username_, std::string token_) : host{std::move(host_)}, username{std::move(username_)}, token{std::move(token_)} { std::scoped_lock lock{jwt_cache.mutex}; - if (username == jwt_cache.username && token == jwt_cache.token) { + if (this->username == jwt_cache.username && this->token == jwt_cache.token) { jwt = jwt_cache.jwt; } + + // Normalize host expression + if (!this->host.empty() && this->host.back() == '/') { + static_cast(this->host.pop_back()); + } } /// A generic function handles POST, GET and DELETE request together @@ -47,7 +52,7 @@ struct Client::Impl { if (jwt.empty() && !allow_anonymous) { LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); - return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""}; + return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed"}; } auto result = GenericRequest(method, path, data, accept, jwt); @@ -71,18 +76,16 @@ struct Client::Impl { const std::string& jwt_ = "", const std::string& username_ = "", const std::string& token_ = "") { if (cli == nullptr) { - cli = std::make_unique(host); + cli = std::make_unique(host.c_str()); + cli->set_connection_timeout(TIMEOUT_SECONDS); + cli->set_read_timeout(TIMEOUT_SECONDS); + cli->set_write_timeout(TIMEOUT_SECONDS); } - if (!cli->is_valid()) { - LOG_ERROR(WebService, "Client is invalid, skipping request!"); - return {}; + LOG_ERROR(WebService, "Invalid URL {}", host + path); + return WebResult{WebResult::Code::InvalidURL, "Invalid URL"}; } - cli->set_connection_timeout(TIMEOUT_SECONDS); - cli->set_read_timeout(TIMEOUT_SECONDS); - cli->set_write_timeout(TIMEOUT_SECONDS); - httplib::Headers params; if (!jwt_.empty()) { params = { @@ -107,32 +110,32 @@ struct Client::Impl { request.headers = params; request.body = data; - httplib::Response response; - httplib::Error error; + httplib::Result result = cli->send(request); - if (!cli->send(request, response, error)) { - LOG_ERROR(WebService, "{} to {} returned null (httplib Error: {})", method, host + path, - httplib::to_string(error)); - return WebResult{WebResult::Code::LibError, "Null response", ""}; + if (!result) { + LOG_ERROR(WebService, "{} to {} returned null", method, host + path); + return WebResult{WebResult::Code::LibError, "Null response"}; } + httplib::Response response = result.value(); + if (response.status >= 400) { LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, response.status); - return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""}; + return WebResult{WebResult::Code::HttpError, std::to_string(response.status)}; } auto content_type = response.headers.find("content-type"); if (content_type == response.headers.end()) { LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); - return WebResult{WebResult::Code::WrongContent, "", ""}; + return WebResult{WebResult::Code::WrongContent, ""}; } if (content_type->second.find(accept) == std::string::npos) { LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, content_type->second); - return WebResult{WebResult::Code::WrongContent, "Wrong content", ""}; + return WebResult{WebResult::Code::WrongContent, "Wrong content"}; } return WebResult{WebResult::Code::Success, "", response.body}; } From 185125e4e4a98eb5a780450c6cf09698556469d4 Mon Sep 17 00:00:00 2001 From: Tobias Date: Thu, 25 Jan 2024 00:17:15 +0100 Subject: [PATCH 2/3] citra_qt/configure_ui: Show country of language in the combobox This prevents an issue where we had seperate versions of the same language for different regions and they were not distinguishable (e.g. "Chinese (China)" and "Chinese (Taiwan)"). Also makes it so we do not need to hardcode specific languages anymore. --- src/yuzu/configuration/configure_ui.cpp | 78 +++---------------------- 1 file changed, 9 insertions(+), 69 deletions(-) diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index c8e8711515..f3c91586c4 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -248,82 +248,22 @@ void ConfigureUi::RetranslateUI() { } void ConfigureUi::InitializeLanguageComboBox() { - // This is a list of lexicographically sorted languages, only the available translations are - // shown to the user. - static const struct { - const QString name; - const char* id; - } languages[] = { - // clang-format off - {QStringLiteral(u"Bahasa Indonesia"), "id"}, // Indonesian - {QStringLiteral(u"Bahasa Melayu"), "ms"}, // Malay - {QStringLiteral(u"Catal\u00E0"), "ca"}, // Catalan - {QStringLiteral(u"\u010Ce\u0161tina"), "cs"}, // Czech - {QStringLiteral(u"Dansk"), "da"}, // Danish - {QStringLiteral(u"Deutsch"), "de"}, // German - {QStringLiteral(u"English"), "en"}, // English - {QStringLiteral(u"Espa\u00F1ol"), "es"}, // Spanish - {QStringLiteral(u"Fran\u00E7ais"), "fr"}, // French - {QStringLiteral(u"Hrvatski"), "hr"}, // Croatian - {QStringLiteral(u"Italiano"), "it"}, // Italian - {QStringLiteral(u"Magyar"), "hu"}, // Hungarian - {QStringLiteral(u"Nederlands"), "nl"}, // Dutch - {QStringLiteral(u"Norsk bokm\u00E5l"), "nb"}, // Norwegian - {QStringLiteral(u"Polski"), "pl"}, // Polish - {QStringLiteral(u"Portugu\u00EAs"), "pt_PT"}, // Portuguese - {QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_BR"}, // Portuguese (Brazil) - {QStringLiteral(u"Rom\u00E2n\u0103"), "ro"}, // Romanian - {QStringLiteral(u"Srpski"), "sr"}, // Serbian - {QStringLiteral(u"Suomi"), "fi"}, // Finnish - {QStringLiteral(u"Svenska"), "sv"}, // Swedish - {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t"), "vi"}, // Vietnamese - {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t (Vi\u1EC7t Nam)"), "vi_VN"}, // Vietnamese - {QStringLiteral(u"T\u00FCrk\u00E7e"), "tr_TR"}, // Turkish - {QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"}, // Greek - {QStringLiteral(u"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"), "ru_RU"}, // Russian - {QStringLiteral(u"\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"), - "uk"}, // Ukrainian - {QStringLiteral(u"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"), "ar"}, // Arabic - {QStringLiteral(u"\u0641\u0627\u0631\u0633\u06CC"), "fa"}, // Farsi - {QStringLiteral(u"\uD55C\uAD6D\uC5B4"), "ko_KR"}, // Korean - {QStringLiteral(u"\u65E5\u672C\u8A9E"), "ja_JP"}, // Japanese - {QStringLiteral(u"\u7B80\u4F53\u4E2D\u6587"), "zh_CN"}, // Simplified Chinese - {QStringLiteral(u"\u7E41\u9AD4\u4E2D\u6587"), "zh_TW"}, // Traditional Chinese - // clang-format on - }; ui->language_combobox->addItem(tr(""), QString{}); - QDir languages_dir{QStringLiteral(":/languages")}; - QStringList language_files = languages_dir.entryList(); - for (const auto& lang : languages) { - if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { - ui->language_combobox->addItem(lang.name, QStringLiteral("en")); - language_files.removeOne(QStringLiteral("en.qm")); - continue; - } - for (int i = 0; i < language_files.size(); ++i) { - QString locale = language_files[i]; - locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); - if (QString::fromLatin1(lang.id) == locale) { - ui->language_combobox->addItem(lang.name, locale); - language_files.removeAt(i); - break; - } - } - } - // Anything remaining will be at the bottom - for (const QString& file : language_files) { - LOG_CRITICAL(Frontend, "Unexpected Language File: {}", file.toStdString()); - QString locale = file; + ui->language_combobox->addItem(tr("English"), QStringLiteral("en")); + QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags); + while (it.hasNext()) { + QString locale = it.next(); locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); - const QString language_name = QLocale::languageToString(QLocale(locale).language()); - const QString lang = QStringLiteral("%1 [%2]").arg(language_name, locale); - ui->language_combobox->addItem(lang, locale); + locale.remove(0, locale.lastIndexOf(QLatin1Char{'/'}) + 1); + const QString lang = QLocale::languageToString(QLocale(locale).language()); + const QString country = QLocale::countryToString(QLocale(locale).country()); + ui->language_combobox->addItem(QStringLiteral("%1 (%2)").arg(lang, country), locale); } // Unlike other configuration changes, interface language changes need to be reflected on the // interface immediately. This is done by passing a signal to the main window, and then // retranslating when passing back. - connect(ui->language_combobox, QOverload::of(&QComboBox::currentIndexChanged), this, + connect(ui->language_combobox, qOverload(&QComboBox::currentIndexChanged), this, &ConfigureUi::OnLanguageChanged); } From c0a383d9601178c5be8a3128c9cd7155001dcf4d Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Tue, 6 Feb 2024 15:48:04 +0100 Subject: [PATCH 3/3] web_backend: Fix compilation --- src/web_service/web_backend.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index f41d8af0e8..fdf3ac8463 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -52,7 +52,7 @@ struct Client::Impl { if (jwt.empty() && !allow_anonymous) { LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); - return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed"}; + return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""}; } auto result = GenericRequest(method, path, data, accept, jwt); @@ -83,7 +83,7 @@ struct Client::Impl { } if (!cli->is_valid()) { LOG_ERROR(WebService, "Invalid URL {}", host + path); - return WebResult{WebResult::Code::InvalidURL, "Invalid URL"}; + return WebResult{WebResult::Code::InvalidURL, "Invalid URL", ""}; } httplib::Headers params; @@ -114,7 +114,7 @@ struct Client::Impl { if (!result) { LOG_ERROR(WebService, "{} to {} returned null", method, host + path); - return WebResult{WebResult::Code::LibError, "Null response"}; + return WebResult{WebResult::Code::LibError, "Null response", ""}; } httplib::Response response = result.value(); @@ -122,20 +122,20 @@ struct Client::Impl { if (response.status >= 400) { LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, response.status); - return WebResult{WebResult::Code::HttpError, std::to_string(response.status)}; + return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""}; } auto content_type = response.headers.find("content-type"); if (content_type == response.headers.end()) { LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); - return WebResult{WebResult::Code::WrongContent, ""}; + return WebResult{WebResult::Code::WrongContent, "", ""}; } if (content_type->second.find(accept) == std::string::npos) { LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, content_type->second); - return WebResult{WebResult::Code::WrongContent, "Wrong content"}; + return WebResult{WebResult::Code::WrongContent, "Wrong content", ""}; } return WebResult{WebResult::Code::Success, "", response.body}; }