summaryrefslogtreecommitdiffstats
path: root/src/web_service/telemetry_json.cpp
blob: 51c79200453fb0c9367b3a66ee6674dc7b9fc3cd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <nlohmann/json.hpp>
#include "common/detached_tasks.h"
#include "web_service/telemetry_json.h"
#include "web_service/web_backend.h"
#include "web_service/web_result.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");
    impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");

    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 == WebResult::Code::Success;
}

} // namespace WebService