Update app id on edit (#670)
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
This commit is contained in:
@@ -375,6 +375,7 @@ set(SUNSHINE_TARGET_FILES
|
|||||||
src/network.cpp
|
src/network.cpp
|
||||||
src/network.h
|
src/network.h
|
||||||
src/move_by_copy.h
|
src/move_by_copy.h
|
||||||
|
src/rand.h
|
||||||
src/task_pool.h
|
src/task_pool.h
|
||||||
src/thread_pool.h
|
src/thread_pool.h
|
||||||
src/thread_safe.h
|
src/thread_safe.h
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <boost/property_tree/json_parser.hpp>
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include <boost/property_tree/ptree.hpp>
|
#include <boost/property_tree/ptree.hpp>
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "nvhttp.h"
|
#include "nvhttp.h"
|
||||||
#include "platform/common.h"
|
#include "platform/common.h"
|
||||||
|
#include "rand.h"
|
||||||
#include "rtsp.h"
|
#include "rtsp.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
@@ -301,6 +303,11 @@ void saveApp(resp_https_t response, req_https_t request) {
|
|||||||
response->write(data.str());
|
response->write(data.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::set<std::string> ids;
|
||||||
|
for(auto const &app : proc::proc.get_apps()) {
|
||||||
|
ids.insert(app.id);
|
||||||
|
}
|
||||||
|
|
||||||
pt::ptree inputTree, fileTree;
|
pt::ptree inputTree, fileTree;
|
||||||
|
|
||||||
BOOST_LOG(fatal) << config::stream.file_apps;
|
BOOST_LOG(fatal) << config::stream.file_apps;
|
||||||
@@ -309,6 +316,14 @@ void saveApp(resp_https_t response, req_https_t request) {
|
|||||||
pt::read_json(ss, inputTree);
|
pt::read_json(ss, inputTree);
|
||||||
pt::read_json(config::stream.file_apps, fileTree);
|
pt::read_json(config::stream.file_apps, fileTree);
|
||||||
|
|
||||||
|
// Moonlight checks the id of an item to determine if an item was changed
|
||||||
|
// Needs to be a 32-bit positive integer due to client limitations, "0" indicates no app
|
||||||
|
auto id = util::generate_int32(1, std::numeric_limits<std::int32_t>::max());
|
||||||
|
while(ids.count(std::to_string(id)) > 0) {
|
||||||
|
id = util::generate_int32(1, std::numeric_limits<std::int32_t>::max());
|
||||||
|
}
|
||||||
|
inputTree.put("id", id);
|
||||||
|
|
||||||
if(inputTree.get_child("prep-cmd").empty()) {
|
if(inputTree.get_child("prep-cmd").empty()) {
|
||||||
inputTree.erase("prep-cmd");
|
inputTree.erase("prep-cmd");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
std::string read_file(const char *path) {
|
std::string read_file(const char *path) {
|
||||||
if(!std::filesystem::exists(path)) {
|
if(!std::filesystem::exists(path)) {
|
||||||
|
BOOST_LOG(debug) << "Missing file: " << path;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-9
@@ -640,8 +640,8 @@ void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> res
|
|||||||
}
|
}
|
||||||
auto current_appid = proc::proc.running();
|
auto current_appid = proc::proc.running();
|
||||||
tree.put("root.PairStatus", pair_status);
|
tree.put("root.PairStatus", pair_status);
|
||||||
tree.put("root.currentgame", current_appid >= 0 ? current_appid + 1 : 0);
|
tree.put("root.currentgame", current_appid);
|
||||||
tree.put("root.state", current_appid >= 0 ? "SUNSHINE_SERVER_BUSY" : "SUNSHINE_SERVER_FREE");
|
tree.put("root.state", current_appid > 0 ? "SUNSHINE_SERVER_BUSY" : "SUNSHINE_SERVER_FREE");
|
||||||
|
|
||||||
std::ostringstream data;
|
std::ostringstream data;
|
||||||
|
|
||||||
@@ -683,13 +683,12 @@ void applist(resp_https_t response, req_https_t request) {
|
|||||||
|
|
||||||
apps.put("<xmlattr>.status_code", 200);
|
apps.put("<xmlattr>.status_code", 200);
|
||||||
|
|
||||||
int x = 0;
|
|
||||||
for(auto &proc : proc::proc.get_apps()) {
|
for(auto &proc : proc::proc.get_apps()) {
|
||||||
pt::ptree app;
|
pt::ptree app;
|
||||||
|
|
||||||
app.put("IsHdrSupported"s, config::video.hevc_mode == 3 ? 1 : 0);
|
app.put("IsHdrSupported"s, config::video.hevc_mode == 3 ? 1 : 0);
|
||||||
app.put("AppTitle"s, proc.name);
|
app.put("AppTitle"s, proc.name);
|
||||||
app.put("ID"s, ++x);
|
app.put("ID", proc.id);
|
||||||
|
|
||||||
apps.push_back(std::make_pair("App", std::move(app)));
|
apps.push_back(std::make_pair("App", std::move(app)));
|
||||||
}
|
}
|
||||||
@@ -727,17 +726,17 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto appid = util::from_view(get_arg(args, "appid")) - 1;
|
auto appid = util::from_view(get_arg(args, "appid"));
|
||||||
|
|
||||||
auto current_appid = proc::proc.running();
|
auto current_appid = proc::proc.running();
|
||||||
if(current_appid != -1) {
|
if(current_appid > 0) {
|
||||||
tree.put("root.resume", 0);
|
tree.put("root.resume", 0);
|
||||||
tree.put("root.<xmlattr>.status_code", 400);
|
tree.put("root.<xmlattr>.status_code", 400);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(appid >= 0) {
|
if(appid > 0) {
|
||||||
auto err = proc::proc.execute(appid);
|
auto err = proc::proc.execute(appid);
|
||||||
if(err) {
|
if(err) {
|
||||||
tree.put("root.<xmlattr>.status_code", err);
|
tree.put("root.<xmlattr>.status_code", err);
|
||||||
@@ -777,7 +776,7 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto current_appid = proc::proc.running();
|
auto current_appid = proc::proc.running();
|
||||||
if(current_appid == -1) {
|
if(current_appid == 0) {
|
||||||
tree.put("root.resume", 0);
|
tree.put("root.resume", 0);
|
||||||
tree.put("root.<xmlattr>.status_code", 503);
|
tree.put("root.<xmlattr>.status_code", 503);
|
||||||
|
|
||||||
@@ -826,7 +825,7 @@ void cancel(resp_https_t response, req_https_t request) {
|
|||||||
tree.put("root.cancel", 1);
|
tree.put("root.cancel", 1);
|
||||||
tree.put("root.<xmlattr>.status_code", 200);
|
tree.put("root.<xmlattr>.status_code", 200);
|
||||||
|
|
||||||
if(proc::proc.running() != -1) {
|
if(proc::proc.running() > 0) {
|
||||||
proc::proc.terminate();
|
proc::proc.terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-12
@@ -84,14 +84,17 @@ int proc_t::execute(int app_id) {
|
|||||||
// Ensure starting from a clean slate
|
// Ensure starting from a clean slate
|
||||||
terminate();
|
terminate();
|
||||||
|
|
||||||
if(app_id < 0 || app_id >= _apps.size()) {
|
auto iter = std::find_if(_apps.begin(), _apps.end(), [&app_id](const auto app) {
|
||||||
BOOST_LOG(error) << "Couldn't find app with ID ["sv << app_id << ']';
|
return app.id == std::to_string(app_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(iter == _apps.end()) {
|
||||||
|
BOOST_LOG(error) << "Couldn't find app with ID ["sv << app_id << ']';
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
_app_id = app_id;
|
_app_id = app_id;
|
||||||
auto &proc = _apps[app_id];
|
auto &proc = *iter;
|
||||||
|
|
||||||
_undo_begin = std::begin(proc.prep_cmds);
|
_undo_begin = std::begin(proc.prep_cmds);
|
||||||
_undo_it = _undo_begin;
|
_undo_it = _undo_begin;
|
||||||
@@ -182,7 +185,7 @@ int proc_t::running() {
|
|||||||
terminate();
|
terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void proc_t::terminate() {
|
void proc_t::terminate() {
|
||||||
@@ -230,16 +233,15 @@ std::vector<ctx_t> &proc_t::get_apps() {
|
|||||||
// Returns default image if image configuration is not set.
|
// Returns default image if image configuration is not set.
|
||||||
// Returns http content-type header compatible image type.
|
// Returns http content-type header compatible image type.
|
||||||
std::string proc_t::get_app_image(int app_id) {
|
std::string proc_t::get_app_image(int app_id) {
|
||||||
auto app_index = app_id - 1;
|
|
||||||
if(app_index < 0 || app_index >= _apps.size()) {
|
|
||||||
BOOST_LOG(error) << "Couldn't find app with ID ["sv << app_id << ']';
|
|
||||||
return SUNSHINE_ASSETS_DIR "/box.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto default_image = SUNSHINE_ASSETS_DIR "/box.png";
|
auto default_image = SUNSHINE_ASSETS_DIR "/box.png";
|
||||||
auto app_image_path = _apps[app_index].image_path;
|
|
||||||
|
auto iter = std::find_if(_apps.begin(), _apps.end(), [&app_id](const auto app) {
|
||||||
|
return app.id == std::to_string(app_id);
|
||||||
|
});
|
||||||
|
auto app_image_path = iter == _apps.end() ? std::string() : iter->image_path;
|
||||||
|
|
||||||
if(app_image_path.empty()) {
|
if(app_image_path.empty()) {
|
||||||
// image is empty, return default box image
|
BOOST_LOG(warning) << "Couldn't find app image for ID ["sv << app_id << ']';
|
||||||
return default_image;
|
return default_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +370,7 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
|
|||||||
this_env[name] = parse_env_val(this_env, val.get_value<std::string>());
|
this_env[name] = parse_env_val(this_env, val.get_value<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int app_index = 1; // Start at 1, 0 indicates no app running
|
||||||
std::vector<proc::ctx_t> apps;
|
std::vector<proc::ctx_t> apps;
|
||||||
for(auto &[_, app_node] : apps_node) {
|
for(auto &[_, app_node] : apps_node) {
|
||||||
proc::ctx_t ctx;
|
proc::ctx_t ctx;
|
||||||
@@ -379,6 +382,7 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
|
|||||||
auto cmd = app_node.get_optional<std::string>("cmd"s);
|
auto cmd = app_node.get_optional<std::string>("cmd"s);
|
||||||
auto image_path = app_node.get_optional<std::string>("image-path"s);
|
auto image_path = app_node.get_optional<std::string>("image-path"s);
|
||||||
auto working_dir = app_node.get_optional<std::string>("working-dir"s);
|
auto working_dir = app_node.get_optional<std::string>("working-dir"s);
|
||||||
|
auto id = app_node.get_optional<std::string>("id"s);
|
||||||
|
|
||||||
std::vector<proc::cmd_t> prep_cmds;
|
std::vector<proc::cmd_t> prep_cmds;
|
||||||
if(prep_nodes_opt) {
|
if(prep_nodes_opt) {
|
||||||
@@ -424,6 +428,15 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
|
|||||||
ctx.image_path = parse_env_val(this_env, *image_path);
|
ctx.image_path = parse_env_val(this_env, *image_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(id) {
|
||||||
|
ctx.id = parse_env_val(this_env, *id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.id = std::to_string(app_index);
|
||||||
|
}
|
||||||
|
// Always increment index to avoid order shuffling in moonlight
|
||||||
|
app_index++;
|
||||||
|
|
||||||
ctx.name = std::move(name);
|
ctx.name = std::move(name);
|
||||||
ctx.prep_cmds = std::move(prep_cmds);
|
ctx.prep_cmds = std::move(prep_cmds);
|
||||||
ctx.detached = std::move(detached);
|
ctx.detached = std::move(detached);
|
||||||
|
|||||||
+5
-2
@@ -54,6 +54,7 @@ struct ctx_t {
|
|||||||
std::string working_dir;
|
std::string working_dir;
|
||||||
std::string output;
|
std::string output;
|
||||||
std::string image_path;
|
std::string image_path;
|
||||||
|
std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class proc_t {
|
class proc_t {
|
||||||
@@ -62,14 +63,14 @@ public:
|
|||||||
|
|
||||||
proc_t(
|
proc_t(
|
||||||
boost::process::environment &&env,
|
boost::process::environment &&env,
|
||||||
std::vector<ctx_t> &&apps) : _app_id(-1),
|
std::vector<ctx_t> &&apps) : _app_id(0),
|
||||||
_env(std::move(env)),
|
_env(std::move(env)),
|
||||||
_apps(std::move(apps)) {}
|
_apps(std::move(apps)) {}
|
||||||
|
|
||||||
int execute(int app_id);
|
int execute(int app_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return _app_id if a process is running, otherwise returns -1
|
* @return _app_id if a process is running, otherwise returns 0
|
||||||
*/
|
*/
|
||||||
int running();
|
int running();
|
||||||
|
|
||||||
@@ -96,6 +97,8 @@ private:
|
|||||||
file_t _pipe;
|
file_t _pipe;
|
||||||
std::vector<cmd_t>::const_iterator _undo_it;
|
std::vector<cmd_t>::const_iterator _undo_it;
|
||||||
std::vector<cmd_t>::const_iterator _undo_begin;
|
std::vector<cmd_t>::const_iterator _undo_begin;
|
||||||
|
|
||||||
|
int app_index_from_id(int app_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
void refresh(const std::string &file_name);
|
void refresh(const std::string &file_name);
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef SUNSHINE_RAND_H
|
||||||
|
#define SUNSHINE_RAND_H
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
static int32_t generate_int32(std::default_random_engine &engine, int32_t min, int32_t max) {
|
||||||
|
std::uniform_int_distribution<std::int32_t> dist(min, max);
|
||||||
|
|
||||||
|
return dist(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t generate_int32(int32_t min, int32_t max) {
|
||||||
|
std::random_device r;
|
||||||
|
|
||||||
|
std::default_random_engine engine { r() };
|
||||||
|
|
||||||
|
return util::generate_int32(engine, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
#endif // SUNSHINE_RAND_H
|
||||||
+1
-1
@@ -776,7 +776,7 @@ void controlBroadcastThread(control_server_t *server) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if(proc::proc.running() == -1) {
|
if(proc::proc.running() == 0) {
|
||||||
BOOST_LOG(debug) << "Process terminated"sv;
|
BOOST_LOG(debug) << "Process terminated"sv;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user