Save/load settings with jansson

This commit is contained in:
rock88 2020-05-22 22:42:32 +03:00
parent 5bdcd23506
commit 147fe08426
12 changed files with 146 additions and 112 deletions

3
.gitmodules vendored
View file

@ -4,6 +4,3 @@
[submodule "third_party/nanogui"]
path = third_party/nanogui
url=https://github.com/rock88/nanogui.git
[submodule "third_party/json"]
path = third_party/json
url = https://github.com/nlohmann/json.git

View file

@ -65,8 +65,7 @@ M_INCLUDES := \
-I$(TOPDIR)/third_party/moonlight-common-c/src \
-I$(TOPDIR)/third_party/moonlight-common-c/enet/include \
-I$(TOPDIR)/third_party/nanogui/include \
-I$(TOPDIR)/third_party/nanogui/ext/nanovg/src \
-I$(TOPDIR)/third_party/json/single_include/nlohmann
-I$(TOPDIR)/third_party/nanogui/ext/nanovg/src
DEFINES := -DNANOGUI_USE_OPENGL -DNVG_STB_IMAGE_IMPLEMENTATION -DNANOGUI_NO_GLFW \
-DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE -DUSE_MBEDTLS_CRYPTO
@ -84,7 +83,7 @@ LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*
LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto \
-lavcodec -lavutil -lopus -lbz2 -lz -lexpat -lm \
-lglad -lEGL -lglapi -ldrm_nouveau -lglfw3 \
-lnx -lwebp -lswresample -lavformat -lvpx
-lnx -lwebp -lswresample -lavformat -lvpx -ljansson
LIBGAMESTREAM_C_SOURCES = \
xml.c

View file

@ -20,9 +20,7 @@
#include "http.h"
#include "client.h"
#include "errors.h"
#include "limits.h"
#include <errno.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
@ -39,35 +37,6 @@
static char* unique_id = "0123456789ABCDEF";
const char* gs_error;
int mkdirtree(const char* directory) {
char buffer[PATH_MAX];
char* p = buffer;
// The passed in string could be a string literal
// so we must copy it first
strncpy(p, directory, PATH_MAX - 1);
buffer[PATH_MAX - 1] = '\0';
while (*p != 0) {
// Find the end of the path element
do {
p++;
} while (*p != 0 && *p != '/');
char oldChar = *p;
*p = 0;
// Create the directory if it doesn't exist already
if (mkdir(buffer, 0775) == -1 && errno != EEXIST) {
return -1;
}
*p = oldChar;
}
return 0;
}
static int load_server_status(PSERVER_DATA server) {
int ret;
char url[4096];

View file

@ -44,7 +44,6 @@ typedef struct _SERVER_DATA {
SERVER_INFORMATION serverInfo;
} SERVER_DATA, *PSERVER_DATA;
int mkdirtree(const char* directory);
int gs_init(PSERVER_DATA server, char* address, const char *keyDirectory, int logLevel, bool unsupported);
int gs_app_boxart(PSERVER_DATA server, int app_id, char **art_data, size_t *art_data_size);
int gs_start_app(PSERVER_DATA server, PSTREAM_CONFIGURATION config, int appId, bool sops, bool localaudio, int gamepad_mask);

View file

@ -1044,7 +1044,6 @@
"\"$(SRCROOT)/src/nanogui_resources\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/enet/include\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/src\"",
"\"$(SRCROOT)/third_party/json/single_include/nlohmann\"",
"\"$(SRCROOT)/src/switch\"",
/opt/devkitpro/libnx/include2,
);
@ -1078,6 +1077,7 @@
"-lmbedtls",
"-lmbedx509",
"-lmbedcrypto",
"-ljansson",
);
SDKROOT = macosx;
};
@ -1134,7 +1134,6 @@
"\"$(SRCROOT)/src/nanogui_resources\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/enet/include\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/src\"",
"\"$(SRCROOT)/third_party/json/single_include/nlohmann\"",
"\"$(SRCROOT)/src/switch\"",
/opt/devkitpro/libnx/include2,
);
@ -1167,6 +1166,7 @@
"-lmbedtls",
"-lmbedx509",
"-lmbedcrypto",
"-ljansson",
);
SDKROOT = macosx;
};

View file

@ -79,8 +79,7 @@ void GameStreamClient::connect(const std::string &address, ServerCallback<SERVER
perform_async([this, address, callback] {
// TODO: mem leak here :(
std::string key_dir = Settings::settings()->working_dir() + "/key";
int status = gs_init(&m_server_data[address], (char *)(new std::string(address))->c_str(), key_dir.c_str(), 0, false);
int status = gs_init(&m_server_data[address], (char *)(new std::string(address))->c_str(), Settings::settings()->key_dir().c_str(), 0, false);
nanogui::async([this, address, callback, status] {
if (status == GS_OK) {

View file

@ -1,14 +1,51 @@
#include "Settings.hpp"
#include "Log.h"
#include "json.hpp"
#include <iostream>
#include <fstream>
#include <jansson.h>
#include <algorithm>
#include <string.h>
#include <iomanip>
#include <limits.h>
#include <sys/stat.h>
#define JSON_GET_VALUE(to, json, check, type) \
if (json.check()) { \
to = json.get<type>(); \
static int mkdirtree(const char* directory) {
char buffer[PATH_MAX];
char* p = buffer;
// The passed in string could be a string literal
// so we must copy it first
strncpy(p, directory, PATH_MAX - 1);
buffer[PATH_MAX - 1] = '\0';
while (*p != 0) {
// Find the end of the path element
do {
p++;
} while (*p != 0 && *p != '/');
char oldChar = *p;
*p = 0;
// Create the directory if it doesn't exist already
if (mkdir(buffer, 0775) == -1 && errno != EEXIST) {
return -1;
}
*p = oldChar;
}
return 0;
}
void Settings::set_working_dir(std::string working_dir) {
m_working_dir = working_dir;
m_key_dir = working_dir + "/key";
m_boxart_dir = working_dir + "/boxart";
mkdirtree(m_working_dir.c_str());
mkdirtree(m_key_dir.c_str());
mkdirtree(m_boxart_dir.c_str());
load();
}
void Settings::add_host(const std::string address) {
if (std::find(m_hosts.begin(), m_hosts.end(), address) == m_hosts.end()) {
@ -18,48 +55,91 @@ void Settings::add_host(const std::string address) {
}
void Settings::load() {
try {
std::ifstream stream(m_working_dir + "/settings.json");
if (!stream) {
return;
json_t* root = json_load_file((m_working_dir + "/settings.json").c_str(), 0, NULL);
if (root && json_typeof(root) == JSON_OBJECT) {
if (json_t* hosts = json_object_get(root, "hosts")) {
size_t size = json_array_size(hosts);
for (size_t i = 0; i < size; i++) {
if (json_t* host = json_array_get(hosts, i)) {
if (json_typeof(host) == JSON_STRING) {
m_hosts.push_back(json_string_value(host));
}
}
}
}
nlohmann::json json;
stream >> json;
if (json_t* settings = json_object_get(root, "settings")) {
if (json_t* resolution = json_object_get(settings, "resolution")) {
if (json_typeof(resolution) == JSON_INTEGER) {
m_resolution = (int)json_integer_value(resolution);
}
}
if (json_t* fps = json_object_get(settings, "fps")) {
if (json_typeof(fps) == JSON_INTEGER) {
m_fps = (VideoCodec)json_integer_value(fps);
}
}
if (json_t* video_codec = json_object_get(settings, "video_codec")) {
if (json_typeof(video_codec) == JSON_INTEGER) {
m_video_codec = (VideoCodec)json_integer_value(video_codec);
}
}
if (json_t* bitrate = json_object_get(settings, "bitrate")) {
if (json_typeof(bitrate) == JSON_INTEGER) {
m_bitrate = (int)json_integer_value(bitrate);
}
}
if (json_t* swap_ab_xy = json_object_get(settings, "swap_ab_xy")) {
if (json_typeof(swap_ab_xy) == JSON_TRUE) {
m_swap_ab_xy = true;
} else if (json_typeof(swap_ab_xy) == JSON_FALSE) {
m_swap_ab_xy = false;
}
}
if (json_t* decoder_threads = json_object_get(settings, "decoder_threads")) {
if (json_typeof(decoder_threads) == JSON_INTEGER) {
m_decoder_threads = (int)json_integer_value(decoder_threads);
}
}
}
JSON_GET_VALUE(m_hosts, json["hosts"], is_array, std::vector<std::string>);
JSON_GET_VALUE(m_resolution, json["settings"]["resolution"], is_number_integer, int);
JSON_GET_VALUE(m_fps, json["settings"]["fps"], is_number_integer, int);
JSON_GET_VALUE(m_video_codec, json["settings"]["video_codec"], is_number_integer, VideoCodec);
JSON_GET_VALUE(m_bitrate, json["settings"]["bitrate"], is_number_integer, int);
JSON_GET_VALUE(m_swap_ab_xy, json["settings"]["swap_ab_xy"], is_number_integer, bool);
JSON_GET_VALUE(m_decoder_threads, json["settings"]["decoder_threads"], is_number_integer, int);
//stream.close();
} catch (const std::exception &e) {
LOG_FMT("Load settings error: %s\n", e.what());
json_decref(root);
}
}
void Settings::save() {
try {
nlohmann::json json;
json_t* root = json_object();
if (root) {
if (json_t* hosts = json_array()) {
for (auto host: m_hosts) {
json_array_append(hosts, json_string(host.c_str()));
}
json_object_set(root, "hosts", hosts);
}
json["hosts"] = m_hosts;
json["settings"] = {
{"resolution", m_resolution},
{"fps", m_fps},
{"video_codec", m_video_codec},
{"bitrate", m_bitrate},
{"swap_ab_xy", m_swap_ab_xy},
{"decoder_threads", m_decoder_threads}
};
if (json_t* settings = json_object()) {
json_object_set(root, "resolution", json_integer(m_resolution));
json_object_set(root, "fps", json_integer(m_fps));
json_object_set(root, "video_codec", json_integer(m_video_codec));
json_object_set(root, "bitrate", json_integer(m_bitrate));
json_object_set(root, "decoder_threads", json_integer(m_decoder_threads));
if (m_swap_ab_xy) {
json_object_set(root, "swap_ab_xy", json_true());
} else {
json_object_set(root, "swap_ab_xy", json_false());
}
}
std::ofstream stream(m_working_dir + "/settings.json");
stream << std::setw(4) << json << std::endl;
//stream.close();
} catch (const std::exception &e) {
LOG_FMT("Save settings error: %s\n", e.what());
json_dump_file(root, (m_working_dir + "/settings.json").c_str(), JSON_INDENT(4));
json_decref(root);
}
}

View file

@ -17,13 +17,14 @@ public:
return &settings;
}
std::string working_dir() const {
return m_working_dir;
void set_working_dir(std::string working_dir);
std::string key_dir() const {
return m_key_dir;
}
void set_working_dir(std::string working_dir) {
m_working_dir = std::string(working_dir);
load();
std::string boxart_dir() const {
return m_boxart_dir;
}
std::vector<std::string> hosts() const {
@ -87,6 +88,9 @@ private:
Settings() {};
std::string m_working_dir;
std::string m_key_dir;
std::string m_boxart_dir;
std::vector<std::string> m_hosts;
int m_resolution = 720;
int m_fps = 30;

View file

@ -1,6 +1,5 @@
#include "MbedTLSCryptoManager.hpp"
#include "Settings.hpp"
#include "client.h"
#include <string.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
@ -18,9 +17,8 @@ static bool _generate_new_cert_key_pair();
bool MbedTLSCryptoManager::load_cert_key_pair() {
if (m_key.is_empty() || m_cert.is_empty()) {
auto key_dir = Settings::settings()->working_dir() + "/key/";
Data cert = Data::read_from_file(key_dir + CERTIFICATE_FILE_NAME);
Data key = Data::read_from_file(key_dir + KEY_FILE_NAME);
Data cert = Data::read_from_file(Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME);
Data key = Data::read_from_file(Settings::settings()->key_dir() + "/" + KEY_FILE_NAME);
if (!cert.is_empty() && !key.is_empty()) {
m_cert = cert;
@ -35,10 +33,8 @@ bool MbedTLSCryptoManager::load_cert_key_pair() {
bool MbedTLSCryptoManager::generate_new_cert_key_pair() {
if (_generate_new_cert_key_pair()) {
if (!m_cert.is_empty() && !m_key.is_empty()) {
auto key_dir = Settings::settings()->working_dir() + "/key/";
mkdirtree(key_dir.c_str());
m_cert.write_to_file(key_dir + CERTIFICATE_FILE_NAME);
m_key.write_to_file(key_dir + KEY_FILE_NAME);
m_cert.write_to_file(Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME);
m_key.write_to_file(Settings::settings()->key_dir() + "/" + KEY_FILE_NAME);
return true;
}
}
@ -46,9 +42,8 @@ bool MbedTLSCryptoManager::generate_new_cert_key_pair() {
}
void MbedTLSCryptoManager::remove_cert_key_pair() {
auto key_dir = Settings::settings()->working_dir() + "/key/";
remove((key_dir + CERTIFICATE_FILE_NAME).c_str());
remove((key_dir + KEY_FILE_NAME).c_str());
remove((Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME).c_str());
remove((Settings::settings()->key_dir() + "/" + KEY_FILE_NAME).c_str());
m_cert = Data();
m_key = Data();
}

View file

@ -1,6 +1,5 @@
#include "OpenSSLCryptoManager.hpp"
#include "Settings.hpp"
#include "client.h"
#include <string.h>
#include <cstdlib>
#include <openssl/aes.h>
@ -22,9 +21,8 @@ static bool _generate_new_cert_key_pair();
bool OpenSSLCryptoManager::load_cert_key_pair() {
if (m_key.is_empty() || m_cert.is_empty()) {
auto key_dir = Settings::settings()->working_dir() + "/key/";
Data cert = Data::read_from_file(key_dir + CERTIFICATE_FILE_NAME);
Data key = Data::read_from_file(key_dir + KEY_FILE_NAME);
Data cert = Data::read_from_file(Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME);
Data key = Data::read_from_file(Settings::settings()->key_dir() + "/" + KEY_FILE_NAME);
if (!cert.is_empty() && !key.is_empty()) {
m_cert = cert;
@ -39,10 +37,8 @@ bool OpenSSLCryptoManager::load_cert_key_pair() {
bool OpenSSLCryptoManager::generate_new_cert_key_pair() {
if (_generate_new_cert_key_pair()) {
if (!m_cert.is_empty() && !m_key.is_empty()) {
auto key_dir = Settings::settings()->working_dir() + "/key/";
mkdirtree(key_dir.c_str());
m_cert.write_to_file(key_dir + CERTIFICATE_FILE_NAME);
m_key.write_to_file(key_dir + KEY_FILE_NAME);
m_cert.write_to_file(Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME);
m_key.write_to_file(Settings::settings()->key_dir() + "/" + KEY_FILE_NAME);
return true;
}
}
@ -50,9 +46,8 @@ bool OpenSSLCryptoManager::generate_new_cert_key_pair() {
}
void OpenSSLCryptoManager::remove_cert_key_pair() {
auto key_dir = Settings::settings()->working_dir() + "/key/";
remove((key_dir + CERTIFICATE_FILE_NAME).c_str());
remove((key_dir + KEY_FILE_NAME).c_str());
remove((Settings::settings()->key_dir() + "/" + CERTIFICATE_FILE_NAME).c_str());
remove((Settings::settings()->key_dir() + "/" + KEY_FILE_NAME).c_str());
m_cert = Data();
m_key = Data();
}

View file

@ -10,7 +10,6 @@
#include "Application.hpp"
#include "InputController.hpp"
#include "Settings.hpp"
#include "client.h"
struct retro_hw_render_callback hw_render;
@ -61,7 +60,6 @@ void moonlight_init(int width, int height) {
void retro_init(void) {
#ifdef __LAKKA_SWITCH__
mkdirtree("/storage/system/moonlight");
Settings::settings()->set_working_dir("/storage/system/moonlight");
#endif

1
third_party/json vendored

@ -1 +0,0 @@
Subproject commit a50a14088c5c131d57f6dd6f91741da49c1ce426