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