mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2025-12-30 09:46:54 +00:00
Groundwork for running different applications
This commit is contained in:
parent
5541f9dca8
commit
d17f37db12
@ -69,12 +69,15 @@ set(SUNSHINE_TARGET_FILES
|
||||
sunshine/stream.cpp
|
||||
sunshine/stream.h
|
||||
sunshine/video.cpp
|
||||
sunshine/video.h sunshine/thread_safe.h
|
||||
sunshine/video.h
|
||||
sunshine/thread_safe.h
|
||||
sunshine/input.cpp
|
||||
sunshine/input.h
|
||||
sunshine/audio.cpp
|
||||
sunshine/audio.h
|
||||
sunshine/platform/common.h
|
||||
sunshine/process.cpp
|
||||
sunshine/process.h
|
||||
${PLATFORM_TARGET_FILES})
|
||||
|
||||
include_directories(
|
||||
|
||||
@ -14,12 +14,36 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "config.h"
|
||||
#include "platform/common.h"
|
||||
|
||||
#include "process.h"
|
||||
|
||||
using namespace std::literals;
|
||||
int main(int argc, char *argv[]) {
|
||||
std::vector<proc::cmd_t> pre_cmds {
|
||||
{ "echo pre-1", "echo post-1" },
|
||||
{ "echo pre-2", "" },
|
||||
{ "echo pre-3", "echo post-3" }
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, proc::ctx_t> map {
|
||||
{ "echo", { std::move(pre_cmds), R"(echo \"middle\")", "output.txt" } }
|
||||
};
|
||||
|
||||
boost::process::environment env = boost::this_process::environment();
|
||||
proc::proc_t proc(std::move(env), std::move(map));
|
||||
|
||||
proc.execute("echo"s);
|
||||
|
||||
std::this_thread::sleep_for(50ms);
|
||||
|
||||
proc.execute("echo"s);
|
||||
|
||||
std::this_thread::sleep_for(50ms);
|
||||
return proc.running();
|
||||
|
||||
if(argc > 1) {
|
||||
if(!std::filesystem::exists(argv[1])) {
|
||||
std::cout << "Error: Couln't find configuration file ["sv << argv[1] << ']' << std::endl;
|
||||
std::cout << "Error: Couldn't find configuration file ["sv << argv[1] << ']' << std::endl;
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@ struct gamepad_state_t {
|
||||
|
||||
std::string get_local_ip();
|
||||
|
||||
void interrupt_process(std::uint64_t handle);
|
||||
|
||||
mic_t microphone();
|
||||
audio_t audio(mic_t &mic, std::uint32_t sample_size);
|
||||
|
||||
|
||||
@ -84,6 +84,10 @@ std::string get_local_ip(int family) {
|
||||
|
||||
std::string get_local_ip() { return get_local_ip(AF_INET); }
|
||||
|
||||
void interrupt_process(std::uint64_t handle) {
|
||||
kill((pid_t)handle, SIGTERM);
|
||||
}
|
||||
|
||||
struct display_attr_t {
|
||||
display_attr_t() : display { XOpenDisplay(nullptr) }, window { DefaultRootWindow(display) }, attr {} {
|
||||
refresh();
|
||||
|
||||
143
sunshine/process.cpp
Normal file
143
sunshine/process.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
//
|
||||
// Created by loki on 12/14/19.
|
||||
//
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "process.h"
|
||||
#include "config.h"
|
||||
#include "utility.h"
|
||||
#include "platform/common.h"
|
||||
|
||||
namespace proc {
|
||||
using namespace std::literals;
|
||||
namespace bp = boost::process;
|
||||
|
||||
template<class Rep, class Period>
|
||||
void process_end(bp::child &proc, const std::chrono::duration<Rep, Period>& rel_time) {
|
||||
if(!proc.running()) {
|
||||
return;
|
||||
}
|
||||
|
||||
platf::interrupt_process((std::uint64_t)proc.native_handle());
|
||||
|
||||
// Force termination if it takes too long
|
||||
if(!proc.wait_for(rel_time)) {
|
||||
proc.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
int exe(const std::string &cmd, bp::environment &env, file_t &file, std::error_code &ec) {
|
||||
if(cmd.empty() || cmd == "null"sv) {
|
||||
return bp::system(cmd, env, bp::std_out > bp::null, bp::std_err > bp::null, ec);
|
||||
}
|
||||
|
||||
return bp::system(cmd, env, bp::std_out > file.get(), bp::std_err > file.get(), ec);
|
||||
}
|
||||
|
||||
int proc_t::execute(const std::string &name) {
|
||||
auto it = _name_to_proc.find(name);
|
||||
|
||||
// Ensure starting from a clean slate
|
||||
_undo_pre_cmd();
|
||||
|
||||
if(it == std::end(_name_to_proc)) {
|
||||
std::cout << "Error: Couldn't find ["sv << name << ']' << std::endl;
|
||||
return 404;
|
||||
}
|
||||
|
||||
auto &proc = it->second;
|
||||
|
||||
_undo_begin = std::begin(proc.pre_cmds);
|
||||
_undo_it = _undo_begin;
|
||||
|
||||
if(!proc.cmd_output.empty() && proc.cmd_output != "null"sv) {
|
||||
_pipe.reset(fopen(proc.cmd_output.c_str(), "a"));
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
//Executed when returning from function
|
||||
auto fg = util::fail_guard([&]() {
|
||||
_undo_pre_cmd();
|
||||
});
|
||||
|
||||
for(; _undo_it != std::end(proc.pre_cmds); ++_undo_it) {
|
||||
auto &cmd = _undo_it->do_cmd;
|
||||
|
||||
std::cout << "Executing: ["sv << cmd << ']' << std::endl;
|
||||
auto ret = exe(cmd, _env, _pipe, ec);
|
||||
|
||||
if(ec) {
|
||||
std::cout << "Error: System: "sv << ec.message() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ret != 0) {
|
||||
std::cout << "Error: return code ["sv << ret << ']';
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Starting ["sv << proc.cmd << ']' << std::endl;
|
||||
if(proc.cmd_output.empty() || proc.cmd_output == "null"sv) {
|
||||
_process = bp::child(proc.cmd, _env, bp::std_out > bp::null, bp::std_err > bp::null, ec);
|
||||
}
|
||||
else {
|
||||
_process = bp::child(proc.cmd, _env, bp::std_out > proc.cmd_output, bp::std_err > proc.cmd_output, ec);
|
||||
}
|
||||
|
||||
if(ec) {
|
||||
std::cout << "Error: System: "sv << ec.message() << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fg.disable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool proc_t::running() {
|
||||
return _process.running();
|
||||
}
|
||||
|
||||
void proc_t::_undo_pre_cmd() {
|
||||
std::error_code ec;
|
||||
|
||||
// Ensure child process is terminated
|
||||
process_end(_process, 10s);
|
||||
|
||||
if(ec) {
|
||||
std::cout << "FATAL Error: System: "sv << ec.message() << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
for(;_undo_it != _undo_begin; --_undo_it) {
|
||||
auto &cmd = (_undo_it - 1)->undo_cmd;
|
||||
|
||||
if(cmd.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "Executing: ["sv << cmd << ']' << std::endl;
|
||||
|
||||
auto ret = exe(cmd, _env, _pipe, ec);
|
||||
|
||||
if(ec) {
|
||||
std::cout << "FATAL Error: System: "sv << ec.message() << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if(ret != 0) {
|
||||
std::cout << "FATAL Error: return code ["sv << ret << ']';
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
_pipe.reset();
|
||||
}
|
||||
proc_t::~proc_t() {
|
||||
_undo_pre_cmd();
|
||||
}
|
||||
}
|
||||
67
sunshine/process.h
Normal file
67
sunshine/process.h
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by loki on 12/14/19.
|
||||
//
|
||||
|
||||
#ifndef SUNSHINE_PROCESS_H
|
||||
#define SUNSHINE_PROCESS_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include "utility.h"
|
||||
|
||||
namespace proc {
|
||||
using file_t = util::safe_ptr_v2<FILE, int, fclose>;
|
||||
|
||||
struct cmd_t {
|
||||
std::string do_cmd;
|
||||
|
||||
// Executed when proc_t has finished running, meant to reverse 'do_cmd' if applicable
|
||||
std::string undo_cmd;
|
||||
};
|
||||
/*
|
||||
* pre_cmds -- guaranteed to be executed unless any of the commands fail.
|
||||
* cmd -- Runs indefinitely until:
|
||||
* No session is running and a different set of commands it to be executed
|
||||
* Command exits
|
||||
* cmd_output --
|
||||
* empty -- The output of the commands are appended to the output of sunshine
|
||||
* "null" -- The output of the commands are discarded
|
||||
* filename -- The output of the commands are appended to filename
|
||||
*/
|
||||
struct ctx_t {
|
||||
std::vector<cmd_t> pre_cmds;
|
||||
|
||||
std::string cmd;
|
||||
std::string cmd_output;
|
||||
};
|
||||
|
||||
class proc_t {
|
||||
public:
|
||||
KITTY_DEFAULT_CONSTR(proc_t)
|
||||
|
||||
proc_t(
|
||||
boost::process::environment &&env,
|
||||
std::unordered_map<std::string, ctx_t> &&name_to_proc) :
|
||||
_env(std::move(env)),
|
||||
_name_to_proc(std::move(name_to_proc)) {}
|
||||
|
||||
int execute(const std::string &name);
|
||||
bool running();
|
||||
|
||||
~proc_t();
|
||||
|
||||
private:
|
||||
void _undo_pre_cmd();
|
||||
|
||||
boost::process::environment _env;
|
||||
std::unordered_map<std::string, ctx_t> _name_to_proc;
|
||||
|
||||
boost::process::child _process;
|
||||
file_t _pipe;
|
||||
std::vector<cmd_t>::const_iterator _undo_it;
|
||||
std::vector<cmd_t>::const_iterator _undo_begin;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //SUNSHINE_PROCESS_H
|
||||
@ -14,12 +14,7 @@
|
||||
namespace safe {
|
||||
template<class T>
|
||||
class event_t {
|
||||
using status_t = util::either_t<
|
||||
(std::is_same_v<T, bool> ||
|
||||
util::instantiation_of_v<std::unique_ptr, T> ||
|
||||
util::instantiation_of_v<std::shared_ptr, T> ||
|
||||
std::is_pointer_v<T>),
|
||||
T, std::optional<T>>;
|
||||
using status_t = util::optional_t<T>;
|
||||
|
||||
public:
|
||||
template<class...Args>
|
||||
@ -82,12 +77,7 @@ private:
|
||||
|
||||
template<class T>
|
||||
class queue_t {
|
||||
using status_t = util::either_t<
|
||||
(std::is_same_v<T, bool> ||
|
||||
util::instantiation_of_v<std::unique_ptr, T> ||
|
||||
util::instantiation_of_v<std::shared_ptr, T> ||
|
||||
std::is_pointer_v<T>),
|
||||
T, std::optional<T>>;
|
||||
using status_t = util::optional_t<T>;
|
||||
|
||||
public:
|
||||
template<class ...Args>
|
||||
|
||||
@ -93,6 +93,14 @@ struct __false_v<T, std::enable_if_t<std::is_same_v<T, bool>>> {
|
||||
template<class T>
|
||||
static constexpr auto false_v = __false_v<T>::value;
|
||||
|
||||
template<class T>
|
||||
using optional_t = either_t<
|
||||
(std::is_same_v<T, bool> ||
|
||||
instantiation_of_v<std::unique_ptr, T> ||
|
||||
instantiation_of_v<std::shared_ptr, T> ||
|
||||
std::is_pointer_v<T>),
|
||||
T, std::optional<T>>;
|
||||
|
||||
template<class T>
|
||||
class FailGuard {
|
||||
public:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user