Remove the telemetry (#45)

* remove the telemetry except from the renderers as I'm not being capable to remove it from there

* remove the telemetry except from the renderers as I'm not being capable to remove it from there

* Remove remainder of non-functional Telemetry and Citra Web Services

Squashed commit of the following:

commit f6dd4d4579c91db323877f0d08b9c01c82e1bb32
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 14:02:26 2024 -0600

    gl_driver.h: add back missing functions

commit 8f14384e7a7b763c3f2ccb3af6b5a59df641d9ee
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 13:56:16 2024 -0600

    gl_driver.cpp: add back missing functions

commit 5c802524b01a6eb05952d88ccf9dd78d63baee0a
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 13:39:46 2024 -0600

    apply clang-format

commit e8f62a7d3ee8a3da885a28bce21bcfcb84f13a84
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 13:16:22 2024 -0600

    remove web_tab

commit ced7f1e4909ae7b2714a96e3c3fa0500e8c62968
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 13:13:47 2024 -0600

    remove unused call?

commit f10e05da887e4570853fae2bd55a71087b4bcc77
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 13:03:47 2024 -0600

    fix build errors

commit 0489c1770b4b48d51f626145ae9235d3c81029fc
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 12:54:35 2024 -0600

    Remove deleted files

commit b2eb56f5a1f01663cc9874d99fe77ee64b48622b
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 12:43:17 2024 -0600

    Remove ConfigureWeb

commit b96f7c724006b2c5ee2272becaa70584fe90d012
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:49:51 2024 -0600

    remove unused DebugHandler

commit 91ddf16f63f9ae07b0cb2768171728dc878d1653
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:41:31 2024 -0600

    remove CollectToolingInfo() reference

commit 3909ac0502f23f8fb54944b53d5072b6986f8ffd
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:33:39 2024 -0600

    Fix "clean renderer_vulkan.cpp"

    This reverts commit 8a882658da9fabca40d71d73bfaf3bb5702acd72.

commit f4a10c4e4f27471b0a263ac363a6fa2abc9d6dc9
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:25:12 2024 -0600

    remove Core() references

commit 5593b8484e7c9f525ea218902dd2c13148d86b37
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:09:26 2024 -0600

    clean core/core.cpp

commit 55bbd8ad283297ef79db11e19ca6303fdfba6626
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:03:45 2024 -0600

    apply clang-format

commit 3707a0b2705dd415876130c9c90b0916bdea11db
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:02:16 2024 -0600

    citra_qt/main.h

commit ddbdea9be4d8179a333e04e7c302e215868715a9
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 11:01:30 2024 -0600

    clean common/detached_tasks.h

commit b513ba3b91ebc81bddd634b5690b6434824e1c7a
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:58:51 2024 -0600

    clean android/app/src/main/jni/default_ini.h

commit b6ba7d7cd730393883fdca294c651a4186727b55
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:58:14 2024 -0600

    clean android/app/src/main/jni/native.cpp

commit 2351305bb24b005920af0f3f7bb6bbb5bb3124bd
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:56:59 2024 -0600

    network/network_settings.h

commit 5b4c1ebb97c7fad5daf7789e1d3640041c2412fb
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:55:53 2024 -0600

    clean citra_qt/configuration/configure_web.ui

commit 9526d5122995c2e9c52b4d93b6e836a2ea4c80ef
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:54:53 2024 -0600

    citra_qt/configuration/config.cpp

commit ec6fe57412ce97e06096fc07f8b86dd080b7b944
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:53:50 2024 -0600

    clean citra/default_ini.h

commit acba1cf7e94de2fa87174e9f6d7c7c4554146352
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:52:47 2024 -0600

    clean citra/config.cpp

commit 02888777590d4e4bf1423e168a672ca0c5e140e5
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:50:42 2024 -0600

    clean vk_instance.cpp

commit eae451d5825b3601382c3a6dd08a3bde5c7a9460
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:48:53 2024 -0600

    clean vk_instanch.h

commit 8a882658da9fabca40d71d73bfaf3bb5702acd72
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:47:11 2024 -0600

    clean renderer_vulkan.cpp

commit ea6df111bc447913d2999acd86de984acced7eeb
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:45:51 2024 -0600

    clean renderer_opengl.cpp

commit 6b1bea0ef8cf8831c520d1c4e90b9d73d421c764
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:44:17 2024 -0600

    clean pica_to_gl.h

commit c12e984045a430cb10500241ada68701f73c85ac
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:42:48 2024 -0600

    clean gl_driver.h

commit ca3fe7801fff125a1ab8706bfc3998ca2928bded
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:40:14 2024 -0600

    clean gl_driver.cpp

commit d57381c38b217a423a7039bc7b413d79f59c2ff1
Author: Reg Tiangha <rtiangha@users.noreply.github.com>
Date:   Fri Mar 29 10:38:44 2024 -0600

    delete telemetry files

commit 1af826d1a045c5568a0d9ef4ca423514f298aee2
Author: Miguel <81558772+Miguel-hrvs@users.noreply.github.com>
Date:   Wed Mar 27 16:17:58 2024 +0100

    remove the telemetry except from the renderers as I'm not being capable to remove it from there

* rebase renderer_vulkan

* clean up renderer_vulkan

* bring back vulkan gpu logging

* clang-format vk_instance.h

* fix-formatting

---------

Co-authored-by: Reg Tiangha <rtiangha@users.noreply.github.com>
This commit is contained in:
Miguel 2024-04-02 20:25:36 +02:00 committed by GitHub
parent a442389a60
commit 8e35df1a6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 49 additions and 4395 deletions

View file

@ -266,8 +266,6 @@ void Config::ReadValues() {
}
// Web Service
NetSettings::values.enable_telemetry =
sdl2_config->GetBoolean("WebService", "enable_telemetry", false);
NetSettings::values.web_api_url =
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");

View file

@ -353,9 +353,6 @@ gdbstub_port=24689
# To LLE a service module add "LLE\<module name>=true"
[WebService]
# Whether or not to enable telemetry
# 0 (default): No, 1: Yes
enable_telemetry =
# URL for Web API
web_api_url = https://api.citra-emu.org
# Username and token for Citra Web Service

View file

@ -38,7 +38,6 @@
#include "core/hle/service/nfc/nfc.h"
#include "core/loader/loader.h"
#include "core/savestate.h"
#include "core/telemetry_session.h"
#include "jni/android_common/android_common.h"
#include "jni/applets/mii_selector.h"
#include "jni/applets/swkbd.h"
@ -207,9 +206,6 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
return load_result;
}
auto& telemetry_session = system.TelemetrySession();
telemetry_session.AddField(Common::Telemetry::FieldType::App, "Frontend", "Android");
stop_run = false;
pause_emulation = false;

View file

@ -39,7 +39,6 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/movie.h"
#include "core/telemetry_session.h"
#include "input_common/main.h"
#include "network/network.h"
#include "video_core/gpu.h"
@ -436,8 +435,6 @@ int main(int argc, char** argv) {
break;
}
system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");
if (use_multiplayer) {
if (auto member = Network::GetRoomMember().lock()) {
member->BindOnChatMessageRecieved(OnMessageReceived);

View file

@ -328,8 +328,6 @@ void Config::ReadValues() {
}
// Web Service
NetSettings::values.enable_telemetry =
sdl2_config->GetBoolean("WebService", "enable_telemetry", false);
NetSettings::values.web_api_url =
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");

View file

@ -361,9 +361,6 @@ renderer_debug =
# To LLE a service module add "LLE\<module name>=true"
[WebService]
# Whether or not to enable telemetry
# 0 (default): No, 1: Yes
enable_telemetry =
# URL for Web API
web_api_url = https://api.citra-emu.org
# Username and token for Citra Web Service

View file

@ -81,9 +81,6 @@ add_executable(citra-qt
configuration/configure_ui.cpp
configuration/configure_ui.h
configuration/configure_ui.ui
configuration/configure_web.cpp
configuration/configure_web.h
configuration/configure_web.ui
configuration/configure_cheats.cpp
configuration/configure_cheats.h
configuration/configure_cheats.ui

View file

@ -7,14 +7,12 @@
#include <QPushButton>
#include <QtConcurrent/qtconcurrentrun.h>
#include "citra_qt/compatdb.h"
#include "common/telemetry.h"
#include "core/core.h"
#include "core/telemetry_session.h"
#include "ui_compatdb.h"
CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent)
CompatDB::CompatDB(QWidget* parent)
: QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
ui{std::make_unique<Ui::CompatDB>()}, telemetry_session{telemetry_session_} {
ui{std::make_unique<Ui::CompatDB>()} {
ui->setupUi(this);
connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext);
connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext);
@ -52,15 +50,11 @@ void CompatDB::Submit() {
case CompatDBPage::Final:
back();
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility",
compatibility->checkedId());
button(NextButton)->setEnabled(false);
button(NextButton)->setText(tr("Submitting"));
button(CancelButton)->setVisible(false);
testcase_watcher.setFuture(
QtConcurrent::run([this] { return telemetry_session.SubmitTestcase(); }));
break;
default:
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());

View file

@ -8,10 +8,6 @@
#include <QFutureWatcher>
#include <QWizard>
namespace Core {
class TelemetrySession;
}
namespace Ui {
class CompatDB;
}
@ -20,7 +16,7 @@ class CompatDB : public QWizard {
Q_OBJECT
public:
explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr);
explicit CompatDB(QWidget* parent = nullptr);
~CompatDB();
private:
@ -31,6 +27,4 @@ private:
void Submit();
void OnTestcaseSubmitted();
void EnableNext();
Core::TelemetrySession& telemetry_session;
};

View file

@ -837,8 +837,6 @@ void Config::ReadUpdaterValues() {
void Config::ReadWebServiceValues() {
qt_config->beginGroup(QStringLiteral("WebService"));
NetSettings::values.enable_telemetry =
ReadSetting(QStringLiteral("enable_telemetry"), false).toBool();
NetSettings::values.web_api_url =
ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.citra-emu.org"))
.toString()
@ -1319,7 +1317,6 @@ void Config::SaveUpdaterValues() {
void Config::SaveWebServiceValues() {
qt_config->beginGroup(QStringLiteral("WebService"));
WriteSetting(QStringLiteral("enable_telemetry"), NetSettings::values.enable_telemetry, false);
WriteSetting(QStringLiteral("web_api_url"),
QString::fromStdString(NetSettings::values.web_api_url),
QStringLiteral("https://api.citra-emu.org"));

View file

@ -97,12 +97,6 @@
<header>configuration/configure_enhancements.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureWeb</class>
<extends>QWidget</extends>
<header>configuration/configure_web.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureUi</class>
<extends>QWidget</extends>

View file

@ -16,7 +16,6 @@
#include "citra_qt/configuration/configure_storage.h"
#include "citra_qt/configuration/configure_system.h"
#include "citra_qt/configuration/configure_ui.h"
#include "citra_qt/configuration/configure_web.h"
#include "citra_qt/hotkeys.h"
#include "common/settings.h"
#include "core/core.h"
@ -38,7 +37,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
camera_tab{std::make_unique<ConfigureCamera>(this)},
debug_tab{std::make_unique<ConfigureDebug>(is_powered_on, this)},
storage_tab{std::make_unique<ConfigureStorage>(is_powered_on, this)},
web_tab{std::make_unique<ConfigureWeb>(this)}, ui_tab{std::make_unique<ConfigureUi>(this)} {
ui_tab{std::make_unique<ConfigureUi>(this)} {
Settings::SetConfiguringGlobal(true);
ui->setupUi(this);
@ -53,11 +52,9 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
ui->tabWidget->addTab(camera_tab.get(), tr("Camera"));
ui->tabWidget->addTab(debug_tab.get(), tr("Debug"));
ui->tabWidget->addTab(storage_tab.get(), tr("Storage"));
ui->tabWidget->addTab(web_tab.get(), tr("Web"));
ui->tabWidget->addTab(ui_tab.get(), tr("UI"));
hotkeys_tab->Populate(registry);
web_tab->SetWebServiceConfigEnabled(enable_web_config);
PopulateSelectionList();
@ -90,7 +87,6 @@ void ConfigureDialog::SetConfiguration() {
audio_tab->SetConfiguration();
camera_tab->SetConfiguration();
debug_tab->SetConfiguration();
web_tab->SetConfiguration();
ui_tab->SetConfiguration();
storage_tab->SetConfiguration();
}
@ -106,7 +102,6 @@ void ConfigureDialog::ApplyConfiguration() {
audio_tab->ApplyConfiguration();
camera_tab->ApplyConfiguration();
debug_tab->ApplyConfiguration();
web_tab->ApplyConfiguration();
ui_tab->ApplyConfiguration();
storage_tab->ApplyConfiguration();
system.ApplySettings();
@ -119,7 +114,7 @@ void ConfigureDialog::PopulateSelectionList() {
ui->selectorList->clear();
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
{{tr("General"), {general_tab.get(), web_tab.get(), debug_tab.get(), ui_tab.get()}},
{{tr("General"), {general_tab.get(), debug_tab.get(), ui_tab.get()}},
{tr("System"), {system_tab.get(), camera_tab.get(), storage_tab.get()}},
{tr("Graphics"), {enhancements_tab.get(), graphics_tab.get()}},
{tr("Audio"), {audio_tab.get()}},
@ -159,7 +154,6 @@ void ConfigureDialog::RetranslateUI() {
audio_tab->RetranslateUI();
camera_tab->RetranslateUI();
debug_tab->RetranslateUI();
web_tab->RetranslateUI();
ui_tab->RetranslateUI();
storage_tab->RetranslateUI();
}
@ -179,7 +173,6 @@ void ConfigureDialog::UpdateVisibleTabs() {
{camera_tab.get(), tr("Camera")},
{debug_tab.get(), tr("Debug")},
{storage_tab.get(), tr("Storage")},
{web_tab.get(), tr("Web")},
{ui_tab.get(), tr("UI")}};
ui->tabWidget->clear();

View file

@ -29,7 +29,6 @@ class ConfigureAudio;
class ConfigureCamera;
class ConfigureDebug;
class ConfigureStorage;
class ConfigureWeb;
class ConfigureUi;
class ConfigureDialog : public QDialog {
@ -70,6 +69,5 @@ private:
std::unique_ptr<ConfigureCamera> camera_tab;
std::unique_ptr<ConfigureDebug> debug_tab;
std::unique_ptr<ConfigureStorage> storage_tab;
std::unique_ptr<ConfigureWeb> web_tab;
std::unique_ptr<ConfigureUi> ui_tab;
};

View file

@ -1,165 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QIcon>
#include <QMessageBox>
#include <QtConcurrent/QtConcurrentRun>
#include "citra_qt/configuration/configure_web.h"
#include "citra_qt/uisettings.h"
#include "core/telemetry_session.h"
#include "network/network_settings.h"
#include "ui_configure_web.h"
static constexpr char token_delimiter{':'};
static std::string GenerateDisplayToken(const std::string& username, const std::string& token) {
if (username.empty() || token.empty()) {
return {};
}
const std::string unencoded_display_token{username + token_delimiter + token};
QByteArray b{unencoded_display_token.c_str()};
QByteArray b64 = b.toBase64();
return b64.toStdString();
}
static std::string UsernameFromDisplayToken(const std::string& display_token) {
const std::string unencoded_display_token{
QByteArray::fromBase64(display_token.c_str()).toStdString()};
return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter));
}
static std::string TokenFromDisplayToken(const std::string& display_token) {
const std::string unencoded_display_token{
QByteArray::fromBase64(display_token.c_str()).toStdString()};
return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1);
}
ConfigureWeb::ConfigureWeb(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
ui->setupUi(this);
connect(ui->button_regenerate_telemetry_id, &QPushButton::clicked, this,
&ConfigureWeb::RefreshTelemetryID);
connect(ui->button_verify_login, &QPushButton::clicked, this, &ConfigureWeb::VerifyLogin);
connect(&verify_watcher, &QFutureWatcher<bool>::finished, this, &ConfigureWeb::OnLoginVerified);
#ifndef USE_DISCORD_PRESENCE
ui->discord_group->setVisible(false);
#endif
SetConfiguration();
}
ConfigureWeb::~ConfigureWeb() = default;
void ConfigureWeb::SetConfiguration() {
ui->web_credentials_disclaimer->setWordWrap(true);
ui->telemetry_learn_more->setOpenExternalLinks(true);
ui->telemetry_learn_more->setText(tr("<a "
"href='https://citra-emu.org/entry/"
"telemetry-and-why-thats-a-good-thing/'><span "
"style=\"text-decoration: underline; "
"color:#039be5;\">Learn more</span></a>"));
ui->web_signup_link->setOpenExternalLinks(true);
ui->web_signup_link->setText(
tr("<a href='https://profile.citra-emu.org/'><span style=\"text-decoration: underline; "
"color:#039be5;\">Sign up</span></a>"));
ui->web_token_info_link->setOpenExternalLinks(true);
ui->web_token_info_link->setText(
tr("<a href='https://citra-emu.org/wiki/citra-web-service/'><span style=\"text-decoration: "
"underline; color:#039be5;\">What is my token?</span></a>"));
ui->toggle_telemetry->setChecked(NetSettings::values.enable_telemetry);
if (NetSettings::values.citra_username.empty()) {
ui->username->setText(tr("Unspecified"));
} else {
ui->username->setText(QString::fromStdString(NetSettings::values.citra_username));
}
ui->edit_token->setText(QString::fromStdString(
GenerateDisplayToken(NetSettings::values.citra_username, NetSettings::values.citra_token)));
// Connect after setting the values, to avoid calling OnLoginChanged now
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
ui->label_telemetry_id->setText(
tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
user_verified = true;
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
}
void ConfigureWeb::ApplyConfiguration() {
NetSettings::values.enable_telemetry = ui->toggle_telemetry->isChecked();
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
if (user_verified) {
NetSettings::values.citra_username =
UsernameFromDisplayToken(ui->edit_token->text().toStdString());
NetSettings::values.citra_token =
TokenFromDisplayToken(ui->edit_token->text().toStdString());
} else {
QMessageBox::warning(
this, tr("Token not verified"),
tr("Token was not verified. The change to your token has not been saved."));
}
}
void ConfigureWeb::RefreshTelemetryID() {
const u64 new_telemetry_id{Core::RegenerateTelemetryId()};
ui->label_telemetry_id->setText(
tr("Telemetry ID: 0x%1").arg(QString::number(new_telemetry_id, 16).toUpper()));
}
void ConfigureWeb::OnLoginChanged() {
if (ui->edit_token->text().isEmpty()) {
user_verified = true;
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
ui->label_token_verified->setPixmap(pixmap);
} else {
user_verified = false;
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
ui->label_token_verified->setPixmap(pixmap);
}
}
void ConfigureWeb::VerifyLogin() {
ui->button_verify_login->setDisabled(true);
ui->button_verify_login->setText(tr("Verifying..."));
verify_watcher.setFuture(QtConcurrent::run(
[username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()),
token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] {
return Core::VerifyLogin(username, token);
}));
}
void ConfigureWeb::OnLoginVerified() {
ui->button_verify_login->setEnabled(true);
ui->button_verify_login->setText(tr("Verify"));
if (verify_watcher.result()) {
user_verified = true;
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
ui->label_token_verified->setPixmap(pixmap);
ui->username->setText(
QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString())));
} else {
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
ui->label_token_verified->setPixmap(pixmap);
ui->username->setText(tr("Unspecified"));
QMessageBox::critical(this, tr("Verification failed"),
tr("Verification failed. Check that you have entered your token "
"correctly, and that your internet connection is working."));
}
}
void ConfigureWeb::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureWeb::SetWebServiceConfigEnabled(bool enabled) {
ui->label_disable_info->setVisible(!enabled);
ui->groupBoxWebConfig->setEnabled(enabled);
}

View file

@ -1,37 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <QFutureWatcher>
#include <QWidget>
namespace Ui {
class ConfigureWeb;
}
class ConfigureWeb : public QWidget {
Q_OBJECT
public:
explicit ConfigureWeb(QWidget* parent = nullptr);
~ConfigureWeb() override;
void ApplyConfiguration();
void RetranslateUI();
void SetConfiguration();
void SetWebServiceConfigEnabled(bool enabled);
private:
void RefreshTelemetryID();
void OnLoginChanged();
void VerifyLogin();
void OnLoginVerified();
bool user_verified = true;
QFutureWatcher<bool> verify_watcher;
std::unique_ptr<Ui::ConfigureWeb> ui;
};

View file

@ -1,214 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureWeb</class>
<widget class="QWidget" name="ConfigureWeb">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>996</width>
<height>561</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBoxWebConfig">
<property name="title">
<string>Citra Web Service</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutCitraWebService">
<item>
<widget class="QLabel" name="web_credentials_disclaimer">
<property name="text">
<string>By providing your username and token, you agree to allow Citra to collect additional usage data, which may include user identifying information.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayoutCitraUsername">
<item row="2" column="3">
<widget class="QPushButton" name="button_verify_login">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Verify</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="web_signup_link">
<property name="text">
<string>Sign up</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLabel" name="username"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_token">
<property name="text">
<string>Token: </string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_token_verified"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_username">
<property name="text">
<string>Username: </string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="edit_token">
<property name="maxLength">
<number>80</number>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="web_token_info_link">
<property name="text">
<string>What is my token?</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="label_disable_info">
<property name="text">
<string>Web Service configuration can only be changed when a public room isn't being hosted.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Telemetry</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="toggle_telemetry">
<property name="text">
<string>Share anonymous usage data with the Citra team</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="telemetry_learn_more">
<property name="text">
<string>Learn more</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayoutTelemetryId">
<item row="0" column="0">
<widget class="QLabel" name="label_telemetry_id">
<property name="text">
<string>Telemetry ID:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="button_regenerate_telemetry_id">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Regenerate</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="discord_group">
<property name="title">
<string>Discord Presence</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QCheckBox" name="toggle_discordrpc">
<property name="text">
<string>Show Current Game in your Discord Status</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>edit_token</tabstop>
<tabstop>button_verify_login</tabstop>
<tabstop>toggle_telemetry</tabstop>
<tabstop>button_regenerate_telemetry_id</tabstop>
<tabstop>toggle_discordrpc</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View file

@ -15,7 +15,6 @@
#include <QtGui>
#include <QtWidgets>
#include <fmt/format.h>
#include "core/telemetry_session.h"
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
@ -128,27 +127,6 @@ constexpr int default_mouse_timeout = 2500;
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
* user. This is 32-bits - if we have more than 32 callouts, we should retire and recycle old ones.
*/
enum class CalloutFlag : uint32_t {
Telemetry = 0x1,
};
void GMainWindow::ShowTelemetryCallout() {
if (UISettings::values.callout_flags.GetValue() &
static_cast<uint32_t>(CalloutFlag::Telemetry)) {
return;
}
UISettings::values.callout_flags =
UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
const QString telemetry_message =
tr("<a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous "
"data is collected</a> to help improve Citra. "
"<br/><br/>Would you like to share your usage data with us?");
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) == QMessageBox::Yes) {
NetSettings::values.enable_telemetry = true;
system.ApplySettings();
}
}
const int GMainWindow::max_recent_files_item;
@ -263,9 +241,6 @@ GMainWindow::GMainWindow(Core::System& system_)
game_list->LoadCompatibilityList();
game_list->PopulateAsync(UISettings::values.game_dirs);
// Show one-time "callout" messages to the user
ShowTelemetryCallout();
mouse_hide_timer.setInterval(default_mouse_timeout);
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity);
@ -1244,7 +1219,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
game_path = filename;
system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt");
return true;
}
@ -1988,7 +1962,7 @@ void GMainWindow::OnLoadComplete() {
void GMainWindow::OnMenuReportCompatibility() {
if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) {
CompatDB compatdb{system.TelemetrySession(), this};
CompatDB compatdb{this};
compatdb.exec();
} else {
QMessageBox::critical(this, tr("Missing Citra Account"),

View file

@ -152,7 +152,6 @@ private:
void BootGame(const QString& filename);
void ShutdownGame();
void ShowTelemetryCallout();
void SetDiscordEnabled(bool state);
void LoadAmiibo(const QString& filename);

View file

@ -130,8 +130,6 @@ add_library(citra_common STATIC
string_util.cpp
string_util.h
swap.h
telemetry.cpp
telemetry.h
texture.cpp
texture.h
thread.cpp

View file

@ -12,10 +12,10 @@ namespace Common {
/**
* A background manager which ensures that all detached task is finished before program exits.
*
* Some tasks, telemetry submission for example, prefer executing asynchronously and don't care
* about the result. These tasks are suitable for std::thread::detach(). However, this is unsafe if
* the task is launched just before the program exits (which is a common case for telemetry), so we
* need to block on these tasks on program exit.
* Some tasks prefer executing asynchronously and don't care
* about the result. These tasks are suitable for std::thread::detach().
* However, this is unsafe if the task is launched just before the program exits
* so we need to block on these tasks on program exit.
*
* To make detached task safe, a single DetachedTasks object should be placed in the main(), and
* call WaitForAllTasks() after all program execution but before global/static variable destruction.

View file

@ -1,92 +1 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cstring>
#include "common/arch.h"
#include "common/assert.h"
#include "common/scm_rev.h"
#include "common/telemetry.h"
#if CITRA_ARCH(x86_64)
#include "common/x64/cpu_detect.h"
#endif
namespace Common::Telemetry {
void FieldCollection::Accept(VisitorInterface& visitor) const {
for (const auto& field : fields) {
field.second->Accept(visitor);
}
}
void FieldCollection::AddField(std::unique_ptr<FieldInterface> field) {
fields[field->GetName()] = std::move(field);
}
template <class T>
void Field<T>::Accept(VisitorInterface& visitor) const {
visitor.Visit(*this);
}
template class Field<bool>;
template class Field<double>;
template class Field<float>;
template class Field<u8>;
template class Field<u16>;
template class Field<u32>;
template class Field<u64>;
template class Field<s8>;
template class Field<s16>;
template class Field<s32>;
template class Field<s64>;
template class Field<std::string>;
template class Field<const char*>;
template class Field<std::chrono::microseconds>;
void AppendBuildInfo(FieldCollection& fc) {
const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr};
fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty);
fc.AddField(FieldType::App, "Git_Branch", Common::g_scm_branch);
fc.AddField(FieldType::App, "Git_Revision", Common::g_scm_rev);
fc.AddField(FieldType::App, "BuildDate", Common::g_build_date);
fc.AddField(FieldType::App, "BuildName", Common::g_build_name);
}
void AppendCPUInfo(FieldCollection& fc) {
#if CITRA_ARCH(x86_64)
fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string);
fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX512", Common::GetCPUCaps().avx512);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI1", Common::GetCPUCaps().bmi1);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI2", Common::GetCPUCaps().bmi2);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_FMA", Common::GetCPUCaps().fma);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_FMA4", Common::GetCPUCaps().fma4);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE", Common::GetCPUCaps().sse);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE2", Common::GetCPUCaps().sse2);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE3", Common::GetCPUCaps().sse3);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSSE3", Common::GetCPUCaps().ssse3);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE41", Common::GetCPUCaps().sse4_1);
fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE42", Common::GetCPUCaps().sse4_2);
#else
fc.AddField(FieldType::UserSystem, "CPU_Model", "Other");
#endif
}
void AppendOSInfo(FieldCollection& fc) {
#ifdef __APPLE__
fc.AddField(FieldType::UserSystem, "OsPlatform", "Apple");
#elif defined(_WIN32)
fc.AddField(FieldType::UserSystem, "OsPlatform", "Windows");
#elif defined(__linux__) || defined(linux) || defined(__linux)
fc.AddField(FieldType::UserSystem, "OsPlatform", "Linux");
#else
fc.AddField(FieldType::UserSystem, "OsPlatform", "Unknown");
#endif
}
} // namespace Common::Telemetry

View file

@ -1,199 +1 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include <map>
#include <memory>
#include <string>
#include "common/common_types.h"
namespace Common::Telemetry {
/// Field type, used for grouping fields together in the final submitted telemetry log
enum class FieldType : u8 {
None = 0, ///< No specified field group
App, ///< Citra application fields (e.g. version, branch, etc.)
Session, ///< Emulated session fields (e.g. title ID, log, etc.)
Performance, ///< Emulated performance (e.g. fps, emulated CPU speed, etc.)
UserFeedback, ///< User submitted feedback (e.g. star rating, user notes, etc.)
UserConfig, ///< User configuration fields (e.g. emulated CPU core, renderer, etc.)
UserSystem, ///< User system information (e.g. host CPU type, RAM, etc.)
};
struct VisitorInterface;
/**
* Interface class for telemetry data fields.
*/
class FieldInterface : NonCopyable {
public:
virtual ~FieldInterface() = default;
/**
* Accept method for the visitor pattern.
* @param visitor Reference to the visitor that will visit this field.
*/
virtual void Accept(VisitorInterface& visitor) const = 0;
/**
* Gets the name of this field.
* @returns Name of this field as a string.
*/
virtual const std::string& GetName() const = 0;
};
/**
* Represents a telemetry data field, i.e. a unit of data that gets logged and submitted to our
* telemetry web service.
*/
template <typename T>
class Field : public FieldInterface {
public:
Field(FieldType type, std::string name, T value)
: name(std::move(name)), type(type), value(std::move(value)) {}
Field(const Field&) = default;
Field& operator=(const Field&) = default;
Field(Field&&) = default;
Field& operator=(Field&& other) = default;
void Accept(VisitorInterface& visitor) const override;
[[nodiscard]] const std::string& GetName() const override {
return name;
}
/**
* Returns the type of the field.
*/
[[nodiscard]] FieldType GetType() const {
return type;
}
/**
* Returns the value of the field.
*/
[[nodiscard]] const T& GetValue() const {
return value;
}
[[nodiscard]] bool operator==(const Field& other) const {
return (type == other.type) && (name == other.name) && (value == other.value);
}
[[nodiscard]] bool operator!=(const Field& other) const {
return !operator==(other);
}
private:
std::string name; ///< Field name, must be unique
FieldType type{}; ///< Field type, used for grouping fields together
T value; ///< Field value
};
/**
* Collection of data fields that have been logged.
*/
class FieldCollection final : NonCopyable {
public:
FieldCollection() = default;
/**
* Accept method for the visitor pattern, visits each field in the collection.
* @param visitor Reference to the visitor that will visit each field.
*/
void Accept(VisitorInterface& visitor) const;
/**
* Creates a new field and adds it to the field collection.
* @param type Type of the field to add.
* @param name Name of the field to add.
* @param value Value for the field to add.
*/
template <typename T>
void AddField(FieldType type, const char* name, T value) {
return AddField(std::make_unique<Field<T>>(type, name, std::move(value)));
}
/**
* Adds a new field to the field collection.
* @param field Field to add to the field collection.
*/
void AddField(std::unique_ptr<FieldInterface> field);
private:
std::map<std::string, std::unique_ptr<FieldInterface>> fields;
};
/**
* Telemetry fields visitor interface class. A backend to log to a web service should implement
* this interface.
*/
struct VisitorInterface : NonCopyable {
virtual ~VisitorInterface() = default;
virtual void Visit(const Field<bool>& field) = 0;
virtual void Visit(const Field<double>& field) = 0;
virtual void Visit(const Field<float>& field) = 0;
virtual void Visit(const Field<u8>& field) = 0;
virtual void Visit(const Field<u16>& field) = 0;
virtual void Visit(const Field<u32>& field) = 0;
virtual void Visit(const Field<u64>& field) = 0;
virtual void Visit(const Field<s8>& field) = 0;
virtual void Visit(const Field<s16>& field) = 0;
virtual void Visit(const Field<s32>& field) = 0;
virtual void Visit(const Field<s64>& field) = 0;
virtual void Visit(const Field<std::string>& field) = 0;
virtual void Visit(const Field<const char*>& field) = 0;
virtual void Visit(const Field<std::chrono::microseconds>& field) = 0;
/// Completion method, called once all fields have been visited
virtual void Complete() = 0;
virtual bool SubmitTestcase() = 0;
};
/**
* Empty implementation of VisitorInterface that drops all fields. Used when a functional
* backend implementation is not available.
*/
struct NullVisitor : public VisitorInterface {
~NullVisitor() = default;
void Visit(const Field<bool>& /*field*/) override {}
void Visit(const Field<double>& /*field*/) override {}
void Visit(const Field<float>& /*field*/) override {}
void Visit(const Field<u8>& /*field*/) override {}
void Visit(const Field<u16>& /*field*/) override {}
void Visit(const Field<u32>& /*field*/) override {}
void Visit(const Field<u64>& /*field*/) override {}
void Visit(const Field<s8>& /*field*/) override {}
void Visit(const Field<s16>& /*field*/) override {}
void Visit(const Field<s32>& /*field*/) override {}
void Visit(const Field<s64>& /*field*/) override {}
void Visit(const Field<std::string>& /*field*/) override {}
void Visit(const Field<const char*>& /*field*/) override {}
void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
void Complete() override {}
bool SubmitTestcase() override {
return false;
}
};
/// Appends build-specific information to the given FieldCollection,
/// such as branch name, revision hash, etc.
void AppendBuildInfo(FieldCollection& fc);
/// Appends CPU-specific information to the given FieldCollection,
/// such as instruction set extensions, etc.
void AppendCPUInfo(FieldCollection& fc);
/// Appends OS-specific information to the given FieldCollection,
/// such as platform name, etc.
void AppendOSInfo(FieldCollection& fc);
} // namespace Common::Telemetry

View file

@ -467,8 +467,6 @@ add_library(citra_core STATIC
savestate_data.h
system_titles.cpp
system_titles.h
telemetry_session.cpp
telemetry_session.h
tracer/citrace.h
tracer/recorder.cpp
tracer/recorder.h

View file

@ -47,7 +47,6 @@
#ifdef ENABLE_SCRIPTING
#include "core/rpc/server.h"
#endif
#include "core/telemetry_session.h"
#include "network/network.h"
#include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/gpu.h"
@ -322,7 +321,6 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
restore_plugin_context.reset();
}
telemetry_session->AddInitialInfo(*app_loader);
std::shared_ptr<Kernel::Process> process;
const Loader::ResultStatus load_result{app_loader->Load(process)};
if (Loader::ResultStatus::Success != load_result) {
@ -452,8 +450,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
Settings::values.output_device.GetValue());
dsp_core->EnableStretching(Settings::values.enable_audio_stretching.GetValue());
telemetry_session = std::make_unique<Core::TelemetrySession>();
#ifdef ENABLE_SCRIPTING
rpc_server = std::make_unique<RPC::Server>(*this);
#endif
@ -578,16 +574,6 @@ void System::RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> im
}
void System::Shutdown(bool is_deserializing) {
// Log last frame performance stats
const auto perf_results = GetAndResetPerfStats();
constexpr auto performance = Common::Telemetry::FieldType::Performance;
telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
perf_results.emulation_speed * 100.0);
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
telemetry_session->AddField(performance, "Mean_Frametime_MS",
perf_stats ? perf_stats->GetMeanFrametime() : 0);
// Shutdown emulation session
is_powered_on = false;
@ -599,7 +585,6 @@ void System::Shutdown(bool is_deserializing) {
app_loader.reset();
}
custom_tex_manager.reset();
telemetry_session.reset();
#ifdef ENABLE_SCRIPTING
rpc_server.reset();
#endif

View file

@ -72,7 +72,6 @@ class AppLoader;
namespace Core {
class ARM_Interface;
class TelemetrySession;
class ExclusiveMonitor;
class Timing;
@ -165,14 +164,6 @@ public:
return is_powered_on;
}
/**
* Returns a reference to the telemetry session for this emulation session.
* @returns Reference to the telemetry session.
*/
[[nodiscard]] Core::TelemetrySession& TelemetrySession() const {
return *telemetry_session;
}
/// Prepare the core emulation for a reschedule
void PrepareReschedule();
@ -385,9 +376,6 @@ private:
/// When true, signals that a reschedule should happen
bool reschedule_pending{};
/// Telemetry session for this emulation session
std::unique_ptr<Core::TelemetrySession> telemetry_session;
std::unique_ptr<VideoCore::GPU> gpu;
/// Service manager

View file

@ -34,7 +34,6 @@
#include "core/hw/aes/ccm.h"
#include "core/hw/aes/key.h"
#include "core/loader/loader.h"
#include "core/telemetry_session.h"
SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
@ -274,10 +273,6 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
// Log in telemetry if the game uses the shared font
apt->system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session,
"RequiresSharedFont", true);
if (!apt->shared_font_loaded) {
// On real 3DS, font loading happens on booting. However, we load it on demand to coordinate
// with CFG region auto configuration, which happens later than APT initialization.

View file

@ -26,7 +26,6 @@
#include "core/loader/smdh.h"
#include "core/memory.h"
#include "core/system_titles.h"
#include "core/telemetry_session.h"
#include "network/network.h"
namespace Loader {
@ -277,9 +276,6 @@ ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
overlay_ncch = &update_ncch;
}
system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session, "ProgramId",
program_id);
if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info;
ReadTitle(game_info.name);

View file

@ -1,176 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <cryptopp/osrng.h>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/loader/loader.h"
#include "core/telemetry_session.h"
#include "network/network_settings.h"
#ifdef ENABLE_WEB_SERVICE
#include "web_service/telemetry_json.h"
#include "web_service/verify_login.h"
#endif
namespace Core {
namespace Telemetry = Common::Telemetry;
static u64 GenerateTelemetryId() {
u64 telemetry_id{};
CryptoPP::AutoSeededRandomPool rng;
rng.GenerateBlock(reinterpret_cast<CryptoPP::byte*>(&telemetry_id), sizeof(u64));
return telemetry_id;
}
u64 GetTelemetryId() {
u64 telemetry_id{};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
if (FileUtil::Exists(filename)) {
FileUtil::IOFile file(filename, "rb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
file.ReadBytes(&telemetry_id, sizeof(u64));
} else {
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
telemetry_id = GenerateTelemetryId();
file.WriteBytes(&telemetry_id, sizeof(u64));
}
return telemetry_id;
}
u64 RegenerateTelemetryId() {
const u64 new_telemetry_id{GenerateTelemetryId()};
const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) +
"telemetry_id"};
FileUtil::IOFile file(filename, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
return {};
}
file.WriteBytes(&new_telemetry_id, sizeof(u64));
return new_telemetry_id;
}
bool VerifyLogin(const std::string& username, const std::string& token) {
#ifdef ENABLE_WEB_SERVICE
return WebService::VerifyLogin(NetSettings::values.web_api_url, username, token);
#else
return false;
#endif
}
TelemetrySession::TelemetrySession() = default;
TelemetrySession::~TelemetrySession() {
// Log one-time session end information
const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(NetSettings::values.web_api_url,
NetSettings::values.citra_username,
NetSettings::values.citra_token);
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
// Complete the session, submitting to the web service backend if necessary
field_collection.Accept(*backend);
if (NetSettings::values.enable_telemetry) {
backend->Complete();
}
}
void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
// Log one-time top-level information
AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
// Log one-time session start information
const s64 init_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Init_Time", init_time);
std::string program_name;
const Loader::ResultStatus res{app_loader.ReadTitle(program_name)};
if (res == Loader::ResultStatus::Success) {
AddField(Telemetry::FieldType::Session, "ProgramName", program_name);
}
// Log application information
Telemetry::AppendBuildInfo(field_collection);
// Log user system information
Telemetry::AppendCPUInfo(field_collection);
Telemetry::AppendOSInfo(field_collection);
// Log user configuration information
AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId",
static_cast<int>(Settings::values.output_type.GetValue()));
AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
Settings::values.enable_audio_stretching.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit",
Settings::values.use_cpu_jit.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor",
Settings::values.resolution_factor.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit",
Settings::values.frame_limit.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_Backend",
static_cast<int>(Settings::values.graphics_api.GetValue()));
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseHwShader",
Settings::values.use_hw_shader.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_ShadersAccurateMul",
Settings::values.shaders_accurate_mul.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseShaderJit",
Settings::values.use_shader_jit.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_UseVsync",
Settings::values.use_vsync_new.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_FilterMode",
Settings::values.filter_mode.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_Render3d",
static_cast<int>(Settings::values.render_3d.GetValue()));
AddField(Telemetry::FieldType::UserConfig, "Renderer_Factor3d",
Settings::values.factor_3d.GetValue());
AddField(Telemetry::FieldType::UserConfig, "Renderer_MonoRenderOption",
static_cast<int>(Settings::values.mono_render_option.GetValue()));
AddField(Telemetry::FieldType::UserConfig, "System_IsNew3ds",
Settings::values.is_new_3ds.GetValue());
AddField(Telemetry::FieldType::UserConfig, "System_LLEApplets",
Settings::values.lle_applets.GetValue());
AddField(Telemetry::FieldType::UserConfig, "System_RegionValue",
Settings::values.region_value.GetValue());
}
bool TelemetrySession::SubmitTestcase() {
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(NetSettings::values.web_api_url,
NetSettings::values.citra_username,
NetSettings::values.citra_token);
field_collection.Accept(*backend);
return backend->SubmitTestcase();
#else
return false;
#endif
}
} // namespace Core

View file

@ -1,91 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include "common/telemetry.h"
namespace Loader {
class AppLoader;
}
namespace Core {
/**
* Instruments telemetry for this emulation session. Creates a new set of telemetry fields on each
* session, logging any one-time fields. Interfaces with the telemetry backend used for submitting
* data to the web service. Submits session data on close.
*/
class TelemetrySession {
public:
explicit TelemetrySession();
~TelemetrySession();
TelemetrySession(const TelemetrySession&) = delete;
TelemetrySession& operator=(const TelemetrySession&) = delete;
TelemetrySession(TelemetrySession&&) = delete;
TelemetrySession& operator=(TelemetrySession&&) = delete;
/**
* Adds the initial telemetry info necessary when starting up a title.
*
* This includes information such as:
* - Telemetry ID
* - Initialization time
* - Title ID
* - Title name
* - Title file format
* - Miscellaneous settings values.
*
* @param app_loader The application loader to use to retrieve
* title-specific information.
*/
void AddInitialInfo(Loader::AppLoader& app_loader);
/**
* Wrapper around the Telemetry::FieldCollection::AddField method.
* @param type Type of the field to add.
* @param name Name of the field to add.
* @param value Value for the field to add.
*/
template <typename T>
void AddField(Common::Telemetry::FieldType type, const char* name, T value) {
field_collection.AddField(type, name, std::move(value));
}
/**
* Submits a Testcase.
* @returns A bool indicating whether the submission succeeded
*/
bool SubmitTestcase();
private:
/// Tracks all added fields for the session
Common::Telemetry::FieldCollection field_collection;
};
/**
* Gets TelemetryId, a unique identifier used for the user's telemetry sessions.
* @returns The current TelemetryId for the session.
*/
u64 GetTelemetryId();
/**
* Regenerates TelemetryId, a unique identifier used for the user's telemetry sessions.
* @returns The new TelemetryId that was generated.
*/
u64 RegenerateTelemetryId();
/**
* Verifies the username and token.
* @param username Citra username to use for authentication.
* @param token Citra token to use for authentication.
* @returns Future with bool indicating whether the verification succeeded
*/
bool VerifyLogin(const std::string& username, const std::string& token);
} // namespace Core

View file

@ -10,7 +10,6 @@ namespace NetSettings {
struct Values {
// WebService
bool enable_telemetry;
std::string web_api_url;
std::string citra_username;
std::string citra_token;

View file

@ -5,7 +5,6 @@
#include <glad/glad.h>
#include "common/assert.h"
#include "common/settings.h"
#include "core/telemetry_session.h"
#include "video_core/custom_textures/custom_format.h"
#include "video_core/renderer_opengl/gl_driver.h"
#include "video_core/renderer_opengl/gl_vars.h"
@ -70,12 +69,11 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
level = Common::Log::Level::Debug;
break;
}
LOG_GENERIC(Common::Log::Class::Render_OpenGL, level, "{} {} {}: {}", GetSource(source),
GetType(type), id, message);
}
Driver::Driver(Core::TelemetrySession& telemetry_session_) : telemetry_session{telemetry_session_} {
Driver::Driver() {
const bool enable_debug = Settings::values.renderer_debug.GetValue();
if (enable_debug) {
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@ -135,12 +133,6 @@ void Driver::ReportDriverInfo() {
LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
// Add the information to the telemetry system
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
telemetry_session.AddField(user_system, "GPU_Vendor", std::string{gpu_vendor});
telemetry_session.AddField(user_system, "GPU_Model", std::string{gpu_model});
telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string{gl_version});
}
void Driver::DeduceGLES() {

View file

@ -7,10 +7,6 @@
#include <string_view>
#include "common/common_types.h"
namespace Core {
class TelemetrySession;
}
namespace VideoCore {
enum class CustomPixelFormat : u32;
}
@ -48,7 +44,7 @@ enum class DriverBug {
*/
class Driver {
public:
Driver(Core::TelemetrySession& telemetry_session);
Driver();
~Driver();
/// Returns true of the driver has a particular bug stated in the DriverBug enum
@ -143,7 +139,6 @@ private:
void FindBugs();
private:
Core::TelemetrySession& telemetry_session;
Vendor vendor = Vendor::Unknown;
DriverBug bugs{};
bool is_suitable{};

View file

@ -9,7 +9,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/telemetry_session.h"
#include "video_core/pica/regs_framebuffer.h"
#include "video_core/pica/regs_lighting.h"
#include "video_core/pica/regs_texturing.h"
@ -76,9 +75,6 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
}
if (index > 3) {
Core::System::GetInstance().TelemetrySession().AddField(
Common::Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode",
static_cast<u32>(index));
LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index);
}

View file

@ -75,9 +75,9 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: VideoCore::RendererBase{system, window, secondary_window}, pica{pica_},
driver{system.TelemetrySession()}, rasterizer{system.Memory(), pica,
system.CustomTexManager(), *this, driver},
frame_dumper{system, window} {
rasterizer{system.Memory(), pica, system.CustomTexManager(), *this, driver}, frame_dumper{
system,
window} {
const bool has_debug_tool = driver.HasDebugTool();
window.mailbox = std::make_unique<OGLTextureMailbox>(has_debug_tool);
if (secondary_window) {

View file

@ -53,9 +53,9 @@ constexpr static std::array<vk::DescriptorSetLayoutBinding, 1> PRESENT_BINDINGS
RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: RendererBase{system, window, secondary_window}, memory{system.Memory()}, pica{pica_},
instance{system.TelemetrySession(), window, Settings::values.physical_device.GetValue()},
scheduler{instance}, renderpass_cache{instance, scheduler}, pool{instance},
main_window{window, instance, scheduler},
instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance},
renderpass_cache{instance, scheduler}, pool{instance}, main_window{window, instance,
scheduler},
vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer,
VERTEX_BUFFER_SIZE},
rasterizer{memory,

View file

@ -9,7 +9,6 @@
#include "common/assert.h"
#include "common/settings.h"
#include "core/frontend/emu_window.h"
#include "core/telemetry_session.h"
#include "video_core/custom_textures/custom_format.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_platform.h"
@ -138,8 +137,7 @@ Instance::Instance(bool enable_validation, bool dump_command_buffers)
enable_validation, dump_command_buffers)},
physical_devices{instance->enumeratePhysicalDevices()} {}
Instance::Instance(Core::TelemetrySession& telemetry, Frontend::EmuWindow& window,
u32 physical_device_index)
Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
: library{OpenLibrary(&window)}, instance{CreateInstance(
*library, window.GetWindowInfo().type,
Settings::values.renderer_debug.GetValue(),
@ -161,10 +159,9 @@ Instance::Instance(Core::TelemetrySession& telemetry, Frontend::EmuWindow& windo
VK_VERSION_MAJOR(properties.apiVersion), VK_VERSION_MINOR(properties.apiVersion)));
}
CollectTelemetryParameters(telemetry);
CreateDevice();
CollectToolingInfo();
CreateFormatTable();
CollectToolingInfo();
CreateCustomFormatTable();
CreateAttribTable();
}
@ -645,7 +642,10 @@ void Instance::CreateAllocator() {
}
}
void Instance::CollectTelemetryParameters(Core::TelemetrySession& telemetry) {
void Instance::CollectToolingInfo() {
if (!tooling_info) {
return;
}
const vk::StructureChain property_chain =
physical_device
.getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties>();
@ -664,19 +664,6 @@ void Instance::CollectTelemetryParameters(Core::TelemetrySession& telemetry) {
LOG_INFO(Render_Vulkan, "VK_DRIVER: {}", driver_name);
LOG_INFO(Render_Vulkan, "VK_DEVICE: {}", model_name);
LOG_INFO(Render_Vulkan, "VK_VERSION: {}", api_version);
static constexpr auto field = Common::Telemetry::FieldType::UserSystem;
telemetry.AddField(field, "GPU_Vendor", vendor_name);
telemetry.AddField(field, "GPU_Model", model_name);
telemetry.AddField(field, "GPU_Vulkan_Driver", driver_name);
telemetry.AddField(field, "GPU_Vulkan_Version", api_version);
telemetry.AddField(field, "GPU_Vulkan_Extensions", extensions);
}
void Instance::CollectToolingInfo() {
if (!tooling_info) {
return;
}
const auto tools = physical_device.getToolPropertiesEXT();
for (const vk::PhysicalDeviceToolProperties& tool : tools) {
const std::string_view name = tool.name;

View file

@ -10,10 +10,6 @@
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/renderer_vulkan/vk_platform.h"
namespace Core {
class TelemetrySession;
}
namespace Frontend {
class EmuWindow;
}
@ -41,8 +37,7 @@ struct FormatTraits {
class Instance {
public:
explicit Instance(bool validation = false, bool dump_command_buffers = false);
explicit Instance(Core::TelemetrySession& telemetry, Frontend::EmuWindow& window,
u32 physical_device_index);
explicit Instance(Frontend::EmuWindow& window, u32 physical_device_index);
~Instance();
/// Returns the FormatTraits struct for the provided pixel format
@ -290,8 +285,7 @@ private:
/// Creates the VMA allocator handle
void CreateAllocator();
/// Collects telemetry information from the device.
void CollectTelemetryParameters(Core::TelemetrySession& telemetry);
// Collects logging gpu info
void CollectToolingInfo();
private:
@ -334,4 +328,4 @@ private:
bool has_renderdoc{};
};
} // namespace Vulkan
} // namespace Vulkan

View file

@ -2,8 +2,6 @@ add_library(web_service STATIC
announce_room_json.cpp
announce_room_json.h
precompiled_headers.h
telemetry_json.cpp
telemetry_json.h
verify_login.cpp
verify_login.h
verify_user_jwt.cpp

View file

@ -1,130 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <json.hpp>
#include "common/detached_tasks.h"
#include "common/web_result.h"
#include "web_service/telemetry_json.h"
#include "web_service/web_backend.h"
namespace WebService {
namespace Telemetry = Common::Telemetry;
struct TelemetryJson::Impl {
Impl(std::string host, std::string username, std::string token)
: host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {}
nlohmann::json& TopSection() {
return sections[static_cast<u8>(Telemetry::FieldType::None)];
}
const nlohmann::json& TopSection() const {
return sections[static_cast<u8>(Telemetry::FieldType::None)];
}
template <class T>
void Serialize(Telemetry::FieldType type, const std::string& name, T value) {
sections[static_cast<u8>(type)][name] = value;
}
void SerializeSection(Telemetry::FieldType type, const std::string& name) {
TopSection()[name] = sections[static_cast<unsigned>(type)];
}
nlohmann::json output;
std::array<nlohmann::json, 7> sections;
std::string host;
std::string username;
std::string token;
};
TelemetryJson::TelemetryJson(std::string host, std::string username, std::string token)
: impl{std::make_unique<Impl>(std::move(host), std::move(username), std::move(token))} {}
TelemetryJson::~TelemetryJson() = default;
void TelemetryJson::Visit(const Telemetry::Field<bool>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<double>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<float>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u8>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u16>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u32>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<u64>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s8>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s16>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s32>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<s64>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<std::string>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue());
}
void TelemetryJson::Visit(const Telemetry::Field<const char*>& field) {
impl->Serialize(field.GetType(), field.GetName(), std::string(field.GetValue()));
}
void TelemetryJson::Visit(const Telemetry::Field<std::chrono::microseconds>& field) {
impl->Serialize(field.GetType(), field.GetName(), field.GetValue().count());
}
void TelemetryJson::Complete() {
impl->SerializeSection(Telemetry::FieldType::App, "App");
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
auto content = impl->TopSection().dump();
// Send the telemetry async but don't handle the errors since they were written to the log
Common::DetachedTasks::AddTask([host{impl->host}, content]() {
Client{host, "", ""}.PostJson("/telemetry", content, true);
});
}
bool TelemetryJson::SubmitTestcase() {
impl->SerializeSection(Telemetry::FieldType::App, "App");
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
auto content = impl->TopSection().dump();
Client client(impl->host, impl->username, impl->token);
auto value = client.PostJson("/gamedb/testcase", content, false);
return value.result_code == Common::WebResult::Code::Success;
}
} // namespace WebService

View file

@ -1,46 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include <string>
#include "common/announce_multiplayer_room.h"
#include "common/telemetry.h"
namespace WebService {
/**
* Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the
* Citra web service
*/
class TelemetryJson : public Common::Telemetry::VisitorInterface {
public:
TelemetryJson(std::string host, std::string username, std::string token);
~TelemetryJson() override;
void Visit(const Common::Telemetry::Field<bool>& field) override;
void Visit(const Common::Telemetry::Field<double>& field) override;
void Visit(const Common::Telemetry::Field<float>& field) override;
void Visit(const Common::Telemetry::Field<u8>& field) override;
void Visit(const Common::Telemetry::Field<u16>& field) override;
void Visit(const Common::Telemetry::Field<u32>& field) override;
void Visit(const Common::Telemetry::Field<u64>& field) override;
void Visit(const Common::Telemetry::Field<s8>& field) override;
void Visit(const Common::Telemetry::Field<s16>& field) override;
void Visit(const Common::Telemetry::Field<s32>& field) override;
void Visit(const Common::Telemetry::Field<s64>& field) override;
void Visit(const Common::Telemetry::Field<std::string>& field) override;
void Visit(const Common::Telemetry::Field<const char*>& field) override;
void Visit(const Common::Telemetry::Field<std::chrono::microseconds>& field) override;
void Complete() override;
bool SubmitTestcase() override;
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace WebService