Implement pause/resume commands w/ APOLLO_APP_STATUS envvar
This commit is contained in:
142
src/process.cpp
142
src/process.cpp
@@ -127,7 +127,7 @@ namespace proc {
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::path find_working_directory(const std::string &cmd, boost::process::v1::environment &env) {
|
||||
boost::filesystem::path find_working_directory(const std::string &cmd, const boost::process::v1::environment &env) {
|
||||
// Parse the raw command string into parts to get the actual command portion
|
||||
#ifdef _WIN32
|
||||
auto parts = boost::program_options::split_winmain(cmd);
|
||||
@@ -375,6 +375,7 @@ namespace proc {
|
||||
_env["APOLLO_APP_ID"] = _app.id;
|
||||
_env["APOLLO_APP_NAME"] = _app.name;
|
||||
_env["APOLLO_APP_UUID"] = _app.uuid;
|
||||
_env["APOLLO_APP_STATUS"] = "STARTING";
|
||||
_env["APOLLO_CLIENT_UUID"] = launch_session->unique_id;
|
||||
_env["APOLLO_CLIENT_NAME"] = launch_session->device_name;
|
||||
_env["APOLLO_CLIENT_WIDTH"] = std::to_string(render_width);
|
||||
@@ -457,6 +458,8 @@ namespace proc {
|
||||
}
|
||||
}
|
||||
|
||||
_env["APOLLO_APP_STATUS"] = "RUNNING";
|
||||
|
||||
for (auto &cmd : _app.detached) {
|
||||
boost::filesystem::path working_dir = _app.working_dir.empty() ?
|
||||
find_working_directory(cmd, _env) :
|
||||
@@ -593,16 +596,108 @@ namespace proc {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void proc_t::pause() {
|
||||
if (_app.terminate_on_pause) {
|
||||
terminate();
|
||||
} else {
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
system_tray::update_tray_pausing(proc::proc.get_last_run_app_name());
|
||||
#endif
|
||||
void proc_t::resume() {
|
||||
BOOST_LOG(info) << "Session resuming for app [" << _app_name << "].";
|
||||
|
||||
if (!_app.state_cmds.empty()) {
|
||||
auto exec_thread = std::thread([cmd_list = _app.state_cmds, app_working_dir = _app.working_dir, _env = _env]() mutable {
|
||||
|
||||
_env["APOLLO_APP_STATUS"] = "RESUMING";
|
||||
|
||||
std::error_code ec;
|
||||
auto _state_resume_it = std::begin(cmd_list);
|
||||
|
||||
for (; _state_resume_it != std::end(cmd_list); ++_state_resume_it) {
|
||||
auto &cmd = *_state_resume_it;
|
||||
|
||||
// Skip empty commands
|
||||
if (cmd.do_cmd.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::filesystem::path working_dir = app_working_dir.empty() ?
|
||||
find_working_directory(cmd.do_cmd, _env) :
|
||||
boost::filesystem::path(app_working_dir);
|
||||
BOOST_LOG(info) << "Executing Resume Cmd: ["sv << cmd.do_cmd << "] elevated: " << cmd.elevated;
|
||||
auto child = platf::run_command(cmd.elevated, true, cmd.do_cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||
|
||||
if (ec) {
|
||||
BOOST_LOG(error) << "Couldn't run ["sv << cmd.do_cmd << "]: System: "sv << ec.message();
|
||||
break;
|
||||
}
|
||||
|
||||
child.wait();
|
||||
|
||||
auto ret = child.exit_code();
|
||||
if (ret != 0 && ec != std::errc::permission_denied) {
|
||||
BOOST_LOG(error) << '[' << cmd.do_cmd << "] failed with code ["sv << ret << ']';
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exec_thread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
void proc_t::pause() {
|
||||
if (!running()) {
|
||||
BOOST_LOG(info) << "Session already stopped, do not run pause commands.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_app.terminate_on_pause) {
|
||||
BOOST_LOG(info) << "Terminating app [" << _app_name << "] when all clients are disconnected. Pause commands are skipped.";
|
||||
terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Session pausing for app [" << _app_name << "].";
|
||||
|
||||
if (!_app.state_cmds.empty()) {
|
||||
auto exec_thread = std::thread([cmd_list = _app.state_cmds, app_working_dir = _app.working_dir, _env = _env]() mutable {
|
||||
_env["APOLLO_APP_STATUS"] = "PAUSING";
|
||||
|
||||
std::error_code ec;
|
||||
auto _state_pause_it = std::begin(cmd_list);
|
||||
|
||||
for (; _state_pause_it != std::end(cmd_list); ++_state_pause_it) {
|
||||
auto &cmd = *_state_pause_it;
|
||||
|
||||
// Skip empty commands
|
||||
if (cmd.undo_cmd.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boost::filesystem::path working_dir = app_working_dir.empty() ?
|
||||
find_working_directory(cmd.undo_cmd, _env) :
|
||||
boost::filesystem::path(app_working_dir);
|
||||
BOOST_LOG(info) << "Executing Pause Cmd: ["sv << cmd.undo_cmd << "] elevated: " << cmd.elevated;
|
||||
auto child = platf::run_command(cmd.elevated, true, cmd.undo_cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||
|
||||
if (ec) {
|
||||
BOOST_LOG(error) << "Couldn't run ["sv << cmd.undo_cmd << "]: System: "sv << ec.message();
|
||||
break;
|
||||
}
|
||||
|
||||
child.wait();
|
||||
|
||||
auto ret = child.exit_code();
|
||||
if (ret != 0 && ec != std::errc::permission_denied) {
|
||||
BOOST_LOG(error) << '[' << cmd.undo_cmd << "] failed with code ["sv << ret << ']';
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exec_thread.detach();
|
||||
}
|
||||
|
||||
#if defined SUNSHINE_TRAY && SUNSHINE_TRAY >= 1
|
||||
system_tray::update_tray_pausing(proc::proc.get_last_run_app_name());
|
||||
#endif
|
||||
}
|
||||
|
||||
void proc_t::terminate(bool immediate, bool needs_refresh) {
|
||||
std::error_code ec;
|
||||
placebo = false;
|
||||
@@ -614,6 +709,8 @@ namespace proc {
|
||||
_process = boost::process::v1::child();
|
||||
_process_group = boost::process::v1::group();
|
||||
|
||||
_env["APOLLO_APP_STATUS"] = "TERMINATING";
|
||||
|
||||
for (; _app_prep_it != _app_prep_begin; --_app_prep_it) {
|
||||
auto &cmd = *(_app_prep_it - 1);
|
||||
|
||||
@@ -1195,6 +1292,34 @@ namespace proc {
|
||||
}
|
||||
}
|
||||
|
||||
// Build the list of pause/resume commands.
|
||||
std::vector<proc::cmd_t> state_cmds;
|
||||
bool exclude_global_state_cmds = app_node.value("exclude-global-state-cmd", false);
|
||||
if (!exclude_global_state_cmds) {
|
||||
state_cmds.reserve(config::sunshine.state_cmds.size());
|
||||
for (auto &state_cmd : config::sunshine.state_cmds) {
|
||||
auto do_cmd = parse_env_val(this_env, state_cmd.do_cmd);
|
||||
auto undo_cmd = parse_env_val(this_env, state_cmd.undo_cmd);
|
||||
state_cmds.emplace_back(
|
||||
std::move(do_cmd),
|
||||
std::move(undo_cmd),
|
||||
std::move(state_cmd.elevated)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (app_node.contains("state-cmd") && app_node["state-cmd"].is_array()) {
|
||||
for (auto &prep_node : app_node["state-cmd"]) {
|
||||
std::string do_cmd = parse_env_val(this_env, prep_node.value("do", ""));
|
||||
std::string undo_cmd = parse_env_val(this_env, prep_node.value("undo", ""));
|
||||
bool elevated = prep_node.value("elevated", false);
|
||||
state_cmds.emplace_back(
|
||||
std::move(do_cmd),
|
||||
std::move(undo_cmd),
|
||||
std::move(elevated)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the list of detached commands.
|
||||
std::vector<std::string> detached;
|
||||
if (app_node.contains("detached") && app_node["detached"].is_array()) {
|
||||
@@ -1243,6 +1368,7 @@ namespace proc {
|
||||
|
||||
ctx.name = std::move(name);
|
||||
ctx.prep_cmds = std::move(prep_cmds);
|
||||
ctx.state_cmds = std::move(state_cmds);
|
||||
ctx.detached = std::move(detached);
|
||||
|
||||
apps.emplace_back(std::move(ctx));
|
||||
|
||||
Reference in New Issue
Block a user