Browse Source
Merge pull request #2819 from bunnei/telemetry-submit
Merge pull request #2819 from bunnei/telemetry-submit
Telemetry: Submit logged data to the Citra servicence_cpp
committed by
GitHub
19 changed files with 303 additions and 3 deletions
-
6.gitmodules
-
5CMakeLists.txt
-
12externals/CMakeLists.txt
-
1externals/cpr
-
1externals/json
-
3src/CMakeLists.txt
-
4src/citra/config.cpp
-
4src/citra/default_ini.h
-
12src/citra_qt/configuration/config.cpp
-
3src/common/logging/backend.cpp
-
1src/common/logging/log.h
-
3src/core/CMakeLists.txt
-
3src/core/settings.h
-
10src/core/telemetry_session.cpp
-
14src/web_service/CMakeLists.txt
-
87src/web_service/telemetry_json.cpp
-
54src/web_service/telemetry_json.h
-
52src/web_service/web_backend.cpp
-
31src/web_service/web_backend.h
@ -0,0 +1,14 @@ |
|||||
|
set(SRCS |
||||
|
telemetry_json.cpp |
||||
|
web_backend.cpp |
||||
|
) |
||||
|
|
||||
|
set(HEADERS |
||||
|
telemetry_json.h |
||||
|
web_backend.h |
||||
|
) |
||||
|
|
||||
|
create_directory_groups(${SRCS} ${HEADERS}) |
||||
|
|
||||
|
add_library(web_service STATIC ${SRCS} ${HEADERS}) |
||||
|
target_link_libraries(web_service PUBLIC common cpr json-headers) |
||||
@ -0,0 +1,87 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "common/assert.h"
|
||||
|
#include "core/settings.h"
|
||||
|
#include "web_service/telemetry_json.h"
|
||||
|
#include "web_service/web_backend.h"
|
||||
|
|
||||
|
namespace WebService { |
||||
|
|
||||
|
template <class T> |
||||
|
void TelemetryJson::Serialize(Telemetry::FieldType type, const std::string& name, T value) { |
||||
|
sections[static_cast<u8>(type)][name] = value; |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::SerializeSection(Telemetry::FieldType type, const std::string& name) { |
||||
|
TopSection()[name] = sections[static_cast<unsigned>(type)]; |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<bool>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<double>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<float>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<u8>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<u16>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<u32>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<u64>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<s8>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<s16>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<s32>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<s64>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<std::string>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<const char*>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), std::string(field.GetValue())); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Visit(const Telemetry::Field<std::chrono::microseconds>& field) { |
||||
|
Serialize(field.GetType(), field.GetName(), field.GetValue().count()); |
||||
|
} |
||||
|
|
||||
|
void TelemetryJson::Complete() { |
||||
|
SerializeSection(Telemetry::FieldType::App, "App"); |
||||
|
SerializeSection(Telemetry::FieldType::Session, "Session"); |
||||
|
SerializeSection(Telemetry::FieldType::Performance, "Performance"); |
||||
|
SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); |
||||
|
SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); |
||||
|
SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); |
||||
|
PostJson(Settings::values.telemetry_endpoint_url, TopSection().dump()); |
||||
|
} |
||||
|
|
||||
|
} // namespace WebService
|
||||
@ -0,0 +1,54 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <array> |
||||
|
#include <string> |
||||
|
#include <json.hpp> |
||||
|
#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 Telemetry::VisitorInterface { |
||||
|
public: |
||||
|
TelemetryJson() = default; |
||||
|
~TelemetryJson() = default; |
||||
|
|
||||
|
void Visit(const Telemetry::Field<bool>& field) override; |
||||
|
void Visit(const Telemetry::Field<double>& field) override; |
||||
|
void Visit(const Telemetry::Field<float>& field) override; |
||||
|
void Visit(const Telemetry::Field<u8>& field) override; |
||||
|
void Visit(const Telemetry::Field<u16>& field) override; |
||||
|
void Visit(const Telemetry::Field<u32>& field) override; |
||||
|
void Visit(const Telemetry::Field<u64>& field) override; |
||||
|
void Visit(const Telemetry::Field<s8>& field) override; |
||||
|
void Visit(const Telemetry::Field<s16>& field) override; |
||||
|
void Visit(const Telemetry::Field<s32>& field) override; |
||||
|
void Visit(const Telemetry::Field<s64>& field) override; |
||||
|
void Visit(const Telemetry::Field<std::string>& field) override; |
||||
|
void Visit(const Telemetry::Field<const char*>& field) override; |
||||
|
void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override; |
||||
|
|
||||
|
void Complete() override; |
||||
|
|
||||
|
private: |
||||
|
nlohmann::json& TopSection() { |
||||
|
return sections[static_cast<u8>(Telemetry::FieldType::None)]; |
||||
|
} |
||||
|
|
||||
|
template <class T> |
||||
|
void Serialize(Telemetry::FieldType type, const std::string& name, T value); |
||||
|
|
||||
|
void SerializeSection(Telemetry::FieldType type, const std::string& name); |
||||
|
|
||||
|
nlohmann::json output; |
||||
|
std::array<nlohmann::json, 7> sections; |
||||
|
}; |
||||
|
|
||||
|
} // namespace WebService |
||||
@ -0,0 +1,52 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include <cpr/cpr.h>
|
||||
|
#include <stdlib.h>
|
||||
|
#include "common/logging/log.h"
|
||||
|
#include "web_service/web_backend.h"
|
||||
|
|
||||
|
namespace WebService { |
||||
|
|
||||
|
static constexpr char API_VERSION[]{"1"}; |
||||
|
static constexpr char ENV_VAR_USERNAME[]{"CITRA_WEB_SERVICES_USERNAME"}; |
||||
|
static constexpr char ENV_VAR_TOKEN[]{"CITRA_WEB_SERVICES_TOKEN"}; |
||||
|
|
||||
|
static std::string GetEnvironmentVariable(const char* name) { |
||||
|
const char* value{getenv(name)}; |
||||
|
if (value) { |
||||
|
return value; |
||||
|
} |
||||
|
return {}; |
||||
|
} |
||||
|
|
||||
|
const std::string& GetUsername() { |
||||
|
static const std::string username{GetEnvironmentVariable(ENV_VAR_USERNAME)}; |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
const std::string& GetToken() { |
||||
|
static const std::string token{GetEnvironmentVariable(ENV_VAR_TOKEN)}; |
||||
|
return token; |
||||
|
} |
||||
|
|
||||
|
void PostJson(const std::string& url, const std::string& data) { |
||||
|
if (url.empty()) { |
||||
|
LOG_ERROR(WebService, "URL is invalid"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (GetUsername().empty() || GetToken().empty()) { |
||||
|
LOG_ERROR(WebService, "Environment variables %s and %s must be set to POST JSON", |
||||
|
ENV_VAR_USERNAME, ENV_VAR_TOKEN); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
cpr::PostAsync(cpr::Url{url}, cpr::Body{data}, cpr::Header{{"Content-Type", "application/json"}, |
||||
|
{"x-username", GetUsername()}, |
||||
|
{"x-token", GetToken()}, |
||||
|
{"api-version", API_VERSION}}); |
||||
|
} |
||||
|
|
||||
|
} // namespace WebService
|
||||
@ -0,0 +1,31 @@ |
|||||
|
// Copyright 2017 Citra Emulator Project |
||||
|
// Licensed under GPLv2 or any later version |
||||
|
// Refer to the license.txt file included. |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <string> |
||||
|
#include "common/common_types.h" |
||||
|
|
||||
|
namespace WebService { |
||||
|
|
||||
|
/** |
||||
|
* Gets the current username for accessing services.citra-emu.org. |
||||
|
* @returns Username as a string, empty if not set. |
||||
|
*/ |
||||
|
const std::string& GetUsername(); |
||||
|
|
||||
|
/** |
||||
|
* Gets the current token for accessing services.citra-emu.org. |
||||
|
* @returns Token as a string, empty if not set. |
||||
|
*/ |
||||
|
const std::string& GetToken(); |
||||
|
|
||||
|
/** |
||||
|
* Posts JSON to services.citra-emu.org. |
||||
|
* @param url URL of the services.citra-emu.org endpoint to post data to. |
||||
|
* @param data String of JSON data to use for the body of the POST request. |
||||
|
*/ |
||||
|
void PostJson(const std::string& url, const std::string& data); |
||||
|
|
||||
|
} // namespace WebService |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue