mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2026-08-07 20:44:35 +00:00
Pass stream parameters to the apps.json
This commit is contained in:
parent
e4c9c292e5
commit
4fe9f3d145
@ -4,9 +4,9 @@
|
||||
},
|
||||
"apps":[
|
||||
{
|
||||
"name":"Low Res Desktop",
|
||||
"name":"Change Resolution Desktop",
|
||||
"prep-cmd":[
|
||||
{ "do":"xrandr --output HDMI-1 --mode 1920x1080", "undo":"xrandr --output HDMI-1 --mode 1920x1200" }
|
||||
{ "do":"xrandr --mode $[width]x$[height]", "undo":"xrandr --auto" }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@ -93,8 +93,8 @@ bool authenticate(resp_https_t response, req_https_t request) {
|
||||
}
|
||||
|
||||
//If credentials are shown, redirect the user to a /welcome page
|
||||
if(config::sunshine.username.empty()){
|
||||
send_redirect(response,request,"/welcome");
|
||||
if(config::sunshine.username.empty()) {
|
||||
send_redirect(response, request, "/welcome");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -202,8 +202,8 @@ void getPasswordPage(resp_https_t response, req_https_t request) {
|
||||
|
||||
void getWelcomePage(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
if(!config::sunshine.username.empty()){
|
||||
send_redirect(response,request,"/");
|
||||
if(!config::sunshine.username.empty()) {
|
||||
send_redirect(response, request, "/");
|
||||
return;
|
||||
}
|
||||
std::string header = read_file(WEB_DIR "header-no-nav.html");
|
||||
@ -453,16 +453,18 @@ void savePassword(resp_https_t response, req_https_t request) {
|
||||
auto newPassword = inputTree.count("newPassword") > 0 ? inputTree.get<std::string>("newPassword") : "";
|
||||
auto confirmPassword = inputTree.count("confirmNewPassword") > 0 ? inputTree.get<std::string>("confirmNewPassword") : "";
|
||||
if(newUsername.length() == 0) newUsername = username;
|
||||
if(newUsername.length() == 0){
|
||||
if(newUsername.length() == 0) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Invalid Username");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string();
|
||||
if(config::sunshine.username.empty() || (username == config::sunshine.username && hash == config::sunshine.password)) {
|
||||
if(newPassword.empty() || newPassword != confirmPassword) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Password Mismatch");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword);
|
||||
http::reload_user_creds(config::sunshine.credentials_file);
|
||||
outputTree.put("status", true);
|
||||
@ -512,9 +514,9 @@ void savePin(resp_https_t response, req_https_t request) {
|
||||
}
|
||||
}
|
||||
|
||||
void unpairAll(resp_https_t response, req_https_t request){
|
||||
void unpairAll(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
|
||||
print_req(request);
|
||||
|
||||
pt::ptree outputTree;
|
||||
@ -528,9 +530,9 @@ void unpairAll(resp_https_t response, req_https_t request){
|
||||
outputTree.put("status", true);
|
||||
}
|
||||
|
||||
void closeApp(resp_https_t response, req_https_t request){
|
||||
void closeApp(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
|
||||
print_req(request);
|
||||
|
||||
pt::ptree outputTree;
|
||||
@ -541,7 +543,11 @@ void closeApp(resp_https_t response, req_https_t request){
|
||||
response->write(data.str());
|
||||
});
|
||||
|
||||
proc::proc.terminate();
|
||||
{
|
||||
auto lg = proc::proc.lock();
|
||||
proc::proc->terminate();
|
||||
}
|
||||
|
||||
outputTree.put("status", true);
|
||||
}
|
||||
|
||||
|
||||
@ -186,7 +186,7 @@ void update_id_client(const std::string &uniqueID, std::string &&cert, op_e op)
|
||||
}
|
||||
}
|
||||
|
||||
stream::launch_session_t make_launch_session(bool host_audio, const args_t &args) {
|
||||
stream::launch_session_t make_launch_session(bool host_audio, int appid, const args_t &args) {
|
||||
stream::launch_session_t launch_session;
|
||||
|
||||
launch_session.host_audio = host_audio;
|
||||
@ -197,6 +197,8 @@ stream::launch_session_t make_launch_session(bool host_audio, const args_t &args
|
||||
auto next = std::copy(prepend_iv_p, prepend_iv_p + sizeof(prepend_iv), std::begin(launch_session.iv));
|
||||
std::fill(next, std::end(launch_session.iv), 0);
|
||||
|
||||
launch_session.appid = appid;
|
||||
|
||||
return launch_session;
|
||||
}
|
||||
|
||||
@ -568,7 +570,8 @@ void serverinfo(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> res
|
||||
if(!config::nvhttp.resolutions.empty()) {
|
||||
tree.add_child("root.SupportedDisplayMode", display_nodes);
|
||||
}
|
||||
auto current_appid = proc::proc.running();
|
||||
|
||||
auto current_appid = proc::proc->running();
|
||||
tree.put("root.PairStatus", pair_status);
|
||||
tree.put("root.currentgame", current_appid >= 0 ? current_appid + 1 : 0);
|
||||
tree.put("root.state", current_appid >= 0 ? "SUNSHINE_SERVER_BUSY" : "SUNSHINE_SERVER_FREE");
|
||||
@ -614,7 +617,7 @@ void applist(resp_https_t response, req_https_t request) {
|
||||
apps.put("<xmlattr>.status_code", 200);
|
||||
|
||||
int x = 0;
|
||||
for(auto &proc : proc::proc.get_apps()) {
|
||||
for(auto &proc : proc::proc->get_apps()) { // apps don't change between invocations
|
||||
pt::ptree app;
|
||||
|
||||
app.put("IsHdrSupported"s, config::video.hevc_mode == 3 ? 1 : 0);
|
||||
@ -659,7 +662,7 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||
|
||||
auto appid = util::from_view(args.at("appid")) - 1;
|
||||
|
||||
auto current_appid = proc::proc.running();
|
||||
auto current_appid = proc::proc->running();
|
||||
if(current_appid != -1) {
|
||||
tree.put("root.resume", 0);
|
||||
tree.put("root.<xmlattr>.status_code", 400);
|
||||
@ -667,18 +670,9 @@ void launch(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(appid >= 0) {
|
||||
auto err = proc::proc.execute(appid);
|
||||
if(err) {
|
||||
tree.put("root.<xmlattr>.status_code", err);
|
||||
tree.put("root.gamesession", 0);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
host_audio = util::from_view(args.at("localAudioPlayMode"));
|
||||
stream::launch_session_raise(make_launch_session(host_audio, args));
|
||||
stream::launch_session_raise(make_launch_session(host_audio, appid, args));
|
||||
|
||||
tree.put("root.<xmlattr>.status_code", 200);
|
||||
tree.put("root.sessionUrl0", "rtsp://"s + request->local_endpoint_address() + ':' + std::to_string(map_port(stream::RTSP_SETUP_PORT)));
|
||||
@ -706,7 +700,7 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto current_appid = proc::proc.running();
|
||||
auto current_appid = proc::proc->running();
|
||||
if(current_appid == -1) {
|
||||
tree.put("root.resume", 0);
|
||||
tree.put("root.<xmlattr>.status_code", 503);
|
||||
@ -725,7 +719,7 @@ void resume(bool &host_audio, resp_https_t response, req_https_t request) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream::launch_session_raise(make_launch_session(host_audio, args));
|
||||
stream::launch_session_raise(make_launch_session(host_audio, -1, args));
|
||||
|
||||
tree.put("root.<xmlattr>.status_code", 200);
|
||||
tree.put("root.sessionUrl0", "rtsp://"s + request->local_endpoint_address() + ':' + std::to_string(map_port(stream::RTSP_SETUP_PORT)));
|
||||
@ -756,8 +750,9 @@ void cancel(resp_https_t response, req_https_t request) {
|
||||
tree.put("root.cancel", 1);
|
||||
tree.put("root.<xmlattr>.status_code", 200);
|
||||
|
||||
if(proc::proc.running() != -1) {
|
||||
proc::proc.terminate();
|
||||
auto lg = proc::proc.lock();
|
||||
if(proc::proc->running() != -1) {
|
||||
proc::proc->terminate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,7 +923,7 @@ void start() {
|
||||
tcp.join();
|
||||
}
|
||||
|
||||
void erase_all_clients(){
|
||||
void erase_all_clients() {
|
||||
map_id_client.clear();
|
||||
save_state();
|
||||
}
|
||||
|
||||
@ -9,9 +9,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "utility.h"
|
||||
@ -21,7 +21,85 @@ using namespace std::literals;
|
||||
namespace bp = boost::process;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
proc_t proc;
|
||||
util::sync_t<proc_t> proc;
|
||||
|
||||
std::string_view::iterator find_match(char in, char out, std::string_view::iterator begin, std::string_view::iterator end) {
|
||||
int stack = 0;
|
||||
|
||||
--begin;
|
||||
do {
|
||||
++begin;
|
||||
|
||||
if(*begin == in) {
|
||||
++stack;
|
||||
}
|
||||
else if(*begin == out) {
|
||||
--stack;
|
||||
}
|
||||
} while(begin != end && stack != 0);
|
||||
|
||||
if(begin == end) {
|
||||
throw std::out_of_range("Missing closing character \'" + out + '\'');
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
template<class F>
|
||||
std::string parse(char in, char out, const std::string_view &val_raw, F &&f) {
|
||||
auto pos = std::begin(val_raw);
|
||||
auto dollar = std::find(pos, std::end(val_raw), '$');
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
while(dollar != std::end(val_raw)) {
|
||||
auto next = dollar + 1;
|
||||
if(next != std::end(val_raw)) {
|
||||
if(*next == in) {
|
||||
ss.write(pos, (dollar - pos));
|
||||
auto var_begin = next + 1;
|
||||
auto var_end = find_match(in, out, next, std::end(val_raw));
|
||||
|
||||
ss << f(var_begin, var_end);
|
||||
|
||||
pos = var_end + 1;
|
||||
next = var_end;
|
||||
}
|
||||
else if(*next == '$') {
|
||||
ss.write(pos, (next - pos));
|
||||
pos = next + 1;
|
||||
++next;
|
||||
}
|
||||
|
||||
dollar = std::find(next, std::end(val_raw), '$');
|
||||
}
|
||||
else {
|
||||
dollar = next;
|
||||
}
|
||||
}
|
||||
|
||||
ss.write(pos, (dollar - pos));
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string parse_env_val(bp::native_environment &env, const std::string_view &val_raw) {
|
||||
return parse('(', ')', val_raw, [&](const char *begin, const char *end) -> std::string {
|
||||
return env[std::string { begin, end }].to_string();
|
||||
});
|
||||
}
|
||||
|
||||
std::string parse_command(const std::string_view &cmd, const std::unordered_map<std::string_view, std::string_view> &args) {
|
||||
return parse('[', ']', cmd, [&](const char *begin, const char *end) -> std::string {
|
||||
std::string_view arg { begin, (std::size_t)(end - begin) };
|
||||
|
||||
auto val = args.find(arg);
|
||||
if(val == std::end(args)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::string { val->second.data(), val->second.size() };
|
||||
});
|
||||
}
|
||||
|
||||
void process_end(bp::child &proc, bp::group &proc_handle) {
|
||||
if(!proc.running()) {
|
||||
@ -43,7 +121,7 @@ int exe(const std::string &cmd, bp::environment &env, file_t &file, std::error_c
|
||||
return bp::system(cmd, env, bp::std_out > file.get(), bp::std_err > file.get(), ec);
|
||||
}
|
||||
|
||||
int proc_t::execute(int app_id) {
|
||||
int proc_t::execute(int app_id, const std::unordered_map<std::string_view, std::string_view> &args) {
|
||||
if(!running() && _app_id != -1) {
|
||||
// previous process exited on it's own, reset _process_handle
|
||||
_process_handle = bp::group();
|
||||
@ -77,7 +155,7 @@ int proc_t::execute(int app_id) {
|
||||
});
|
||||
|
||||
for(; _undo_it != std::end(proc.prep_cmds); ++_undo_it) {
|
||||
auto &cmd = _undo_it->do_cmd;
|
||||
auto cmd = parse_command(_undo_it->do_cmd, args);
|
||||
|
||||
BOOST_LOG(info) << "Executing: ["sv << cmd << ']';
|
||||
auto ret = exe(cmd, _env, _pipe, ec);
|
||||
@ -93,7 +171,9 @@ int proc_t::execute(int app_id) {
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &cmd : proc.detached) {
|
||||
for(auto &cmd_raw : proc.detached) {
|
||||
auto cmd = parse_command(cmd_raw, args);
|
||||
|
||||
BOOST_LOG(info) << "Spawning ["sv << cmd << ']';
|
||||
if(proc.output.empty() || proc.output == "null"sv) {
|
||||
bp::spawn(cmd, _env, bp::std_out > bp::null, bp::std_err > bp::null, ec);
|
||||
@ -107,24 +187,28 @@ int proc_t::execute(int app_id) {
|
||||
}
|
||||
}
|
||||
|
||||
auto cmd = parse_command(proc.cmd, args);
|
||||
if(proc.cmd.empty()) {
|
||||
BOOST_LOG(debug) << "Executing [Desktop]"sv;
|
||||
placebo = true;
|
||||
} else {
|
||||
boost::filesystem::path working_dir = proc.working_dir.empty() ?
|
||||
boost::filesystem::path(proc.cmd).parent_path() : boost::filesystem::path(proc.working_dir);
|
||||
}
|
||||
else {
|
||||
boost::filesystem::path working_dir = proc.working_dir.empty() ?
|
||||
boost::filesystem::path(proc.cmd).parent_path() :
|
||||
boost::filesystem::path(proc.working_dir);
|
||||
|
||||
if(proc.output.empty() || proc.output == "null"sv) {
|
||||
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
|
||||
_process = bp::child(_process_handle, proc.cmd, _env, bp::start_dir(working_dir), bp::std_out > bp::null, bp::std_err > bp::null, ec);
|
||||
BOOST_LOG(info) << "Executing: ["sv << cmd << ']';
|
||||
_process = bp::child(_process_handle, cmd, _env, bp::start_dir(working_dir), bp::std_out > bp::null, bp::std_err > bp::null, ec);
|
||||
}
|
||||
else {
|
||||
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
|
||||
_process = bp::child(_process_handle, proc.cmd, _env, bp::start_dir(working_dir), bp::std_out > _pipe.get(), bp::std_err > _pipe.get(), ec);
|
||||
BOOST_LOG(info) << "Executing: ["sv << cmd << ']';
|
||||
_process = bp::child(_process_handle, cmd, _env, bp::start_dir(working_dir), bp::std_out > _pipe.get(), bp::std_err > _pipe.get(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
if(ec) {
|
||||
BOOST_LOG(warning) << "Couldn't run ["sv << proc.cmd << "]: System: "sv << ec.message();
|
||||
BOOST_LOG(warning) << "Couldn't run ["sv << cmd << "]: System: "sv << ec.message();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -193,68 +277,6 @@ proc_t::~proc_t() {
|
||||
terminate();
|
||||
}
|
||||
|
||||
std::string_view::iterator find_match(std::string_view::iterator begin, std::string_view::iterator end) {
|
||||
int stack = 0;
|
||||
|
||||
--begin;
|
||||
do {
|
||||
++begin;
|
||||
switch(*begin) {
|
||||
case '(':
|
||||
++stack;
|
||||
break;
|
||||
case ')':
|
||||
--stack;
|
||||
}
|
||||
} while(begin != end && stack != 0);
|
||||
|
||||
if(begin == end) {
|
||||
throw std::out_of_range("Missing closing bracket \')\'");
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
std::string parse_env_val(bp::native_environment &env, const std::string_view &val_raw) {
|
||||
auto pos = std::begin(val_raw);
|
||||
auto dollar = std::find(pos, std::end(val_raw), '$');
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
while(dollar != std::end(val_raw)) {
|
||||
auto next = dollar + 1;
|
||||
if(next != std::end(val_raw)) {
|
||||
switch(*next) {
|
||||
case '(': {
|
||||
ss.write(pos, (dollar - pos));
|
||||
auto var_begin = next + 1;
|
||||
auto var_end = find_match(next, std::end(val_raw));
|
||||
|
||||
ss << env[std::string { var_begin, var_end }].to_string();
|
||||
|
||||
pos = var_end + 1;
|
||||
next = var_end;
|
||||
|
||||
break;
|
||||
}
|
||||
case '$':
|
||||
ss.write(pos, (next - pos));
|
||||
pos = next + 1;
|
||||
++next;
|
||||
break;
|
||||
}
|
||||
|
||||
dollar = std::find(next, std::end(val_raw), '$');
|
||||
}
|
||||
else {
|
||||
dollar = next;
|
||||
}
|
||||
}
|
||||
|
||||
ss.write(pos, (dollar - pos));
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::optional<proc::proc_t> parse(const std::string &file_name) {
|
||||
pt::ptree tree;
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include "utility.h"
|
||||
#include "sync.h"
|
||||
|
||||
namespace proc {
|
||||
using file_t = util::safe_ptr_v2<FILE, int, fclose>;
|
||||
@ -63,11 +64,12 @@ public:
|
||||
|
||||
proc_t(
|
||||
boost::process::environment &&env,
|
||||
std::vector<ctx_t> &&apps) : _app_id(-1),
|
||||
_env(std::move(env)),
|
||||
_apps(std::move(apps)) {}
|
||||
std::vector<ctx_t> &&apps)
|
||||
: _app_id(-1),
|
||||
_env(std::move(env)),
|
||||
_apps(std::move(apps)) {}
|
||||
|
||||
int execute(int app_id);
|
||||
int execute(int app_id, const std::unordered_map<std::string_view, std::string_view> &args);
|
||||
|
||||
/**
|
||||
* @return _app_id if a process is running, otherwise returns -1
|
||||
@ -101,6 +103,6 @@ private:
|
||||
void refresh(const std::string &file_name);
|
||||
std::optional<proc::proc_t> parse(const std::string &file_name);
|
||||
|
||||
extern proc_t proc;
|
||||
extern util::sync_t<proc_t> proc;
|
||||
} // namespace proc
|
||||
#endif //SUNSHINE_PROCESS_H
|
||||
|
||||
@ -18,6 +18,7 @@ extern "C" {
|
||||
#include "input.h"
|
||||
#include "main.h"
|
||||
#include "network.h"
|
||||
#include "process.h"
|
||||
#include "rtsp.h"
|
||||
#include "stream.h"
|
||||
#include "sync.h"
|
||||
@ -653,6 +654,23 @@ void cmd_announce(rtsp_server_t *server, tcp::socket &sock, msg_t &&req) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto appid = launch_session->appid;
|
||||
if(appid >= 0) {
|
||||
// Special variables.
|
||||
|
||||
args.emplace("height"sv, args.at("x-nv-video[0].clientViewportHt"sv));
|
||||
args.emplace("width"sv, args.at("x-nv-video[0].clientViewportWd"sv));
|
||||
args.emplace("fps"sv, args.at("x-nv-video[0].maxFPS"sv));
|
||||
|
||||
auto lg = proc::proc.lock();
|
||||
auto err = proc::proc->execute(appid, args);
|
||||
if(err) {
|
||||
respond(sock, &option, 500, "Couldn't launch application: Internal Server Error", req->sequenceNumber, {});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto session = session::alloc(config, launch_session->gcm_key, launch_session->iv);
|
||||
|
||||
auto slot = server->accept(session);
|
||||
|
||||
@ -17,6 +17,8 @@ struct launch_session_t {
|
||||
crypto::aes_t gcm_key;
|
||||
crypto::aes_t iv;
|
||||
|
||||
int appid;
|
||||
|
||||
bool host_audio;
|
||||
};
|
||||
|
||||
|
||||
@ -757,7 +757,7 @@ void controlBroadcastThread(control_server_t *server) {
|
||||
})
|
||||
}
|
||||
|
||||
if(proc::proc.running() == -1) {
|
||||
if(proc::proc->running() == -1) {
|
||||
BOOST_LOG(debug) << "Process terminated"sv;
|
||||
|
||||
break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user