Per client DO/UNDO commands server part - done
This commit is contained in:
@@ -1062,8 +1062,10 @@ namespace confighttp {
|
||||
pt::read_json(ss, inputTree);
|
||||
std::string uuid = inputTree.get<std::string>("uuid");
|
||||
std::string name = inputTree.get<std::string>("name");
|
||||
auto do_cmds = nvhttp::extract_command_entries(inputTree, "do");
|
||||
auto undo_cmds = nvhttp::extract_command_entries(inputTree, "undo");
|
||||
auto perm = (crypto::PERM)inputTree.get<uint32_t>("perm") & crypto::PERM::_all;
|
||||
outputTree.put("status", nvhttp::update_device_info(uuid, name, perm));
|
||||
outputTree.put("status", nvhttp::update_device_info(uuid, name, do_cmds, undo_cmds, perm));
|
||||
send_response(response, outputTree);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
|
||||
18
src/crypto.h
18
src/crypto.h
@@ -5,11 +5,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
namespace crypto {
|
||||
@@ -78,10 +81,25 @@ namespace crypto {
|
||||
return static_cast<uint32_t>(p) == 0;
|
||||
}
|
||||
|
||||
struct command_entry_t {
|
||||
std::string cmd;
|
||||
bool elevated;
|
||||
|
||||
// Serialize method
|
||||
static inline boost::property_tree::ptree serialize(const command_entry_t& entry) {
|
||||
boost::property_tree::ptree node;
|
||||
node.put("cmd", entry.cmd);
|
||||
node.put("elevated", entry.elevated);
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct named_cert_t {
|
||||
std::string name;
|
||||
std::string uuid;
|
||||
std::string cert;
|
||||
std::list<command_entry_t> do_cmds;
|
||||
std::list<command_entry_t> undo_cmds;
|
||||
PERM perm;
|
||||
};
|
||||
|
||||
|
||||
@@ -168,6 +168,34 @@ namespace nvhttp {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Helper function to extract command entries
|
||||
cmd_list_t
|
||||
extract_command_entries(const pt::ptree& pt, const std::string& key) {
|
||||
cmd_list_t commands;
|
||||
|
||||
// Check if the specified key exists
|
||||
auto it = pt.find(key);
|
||||
if (it != pt.not_found()) {
|
||||
// Traverse the array and extract entries
|
||||
for (const auto& item : pt.get_child(key)) {
|
||||
try {
|
||||
// Extract "cmd" and "elevated" fields
|
||||
std::string cmd = item.second.get<std::string>("cmd");
|
||||
bool elevated = item.second.get<bool>("elevated");
|
||||
|
||||
// Add to the list of commands
|
||||
commands.push_back({cmd, elevated});
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG(warning) << "Error parsing entry: " << e.what();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG(debug) << "Key \"" << key << "\" not found in the JSON.";
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
void
|
||||
save_state() {
|
||||
pt::ptree root;
|
||||
@@ -209,6 +237,25 @@ namespace nvhttp {
|
||||
named_cert_node.put("cert"s, named_cert_p->cert);
|
||||
named_cert_node.put("uuid"s, named_cert_p->uuid);
|
||||
named_cert_node.put("perm"s, (uint32_t)named_cert_p->perm);
|
||||
|
||||
// Add "do" commands
|
||||
if (!named_cert_p->do_cmds.empty()) {
|
||||
pt::ptree do_cmds_node;
|
||||
for (const auto& cmd : named_cert_p->do_cmds) {
|
||||
do_cmds_node.push_back(std::make_pair(""s, crypto::command_entry_t::serialize(cmd)));
|
||||
}
|
||||
named_cert_node.add_child("do", do_cmds_node);
|
||||
}
|
||||
|
||||
// Add "undo" commands
|
||||
if (!named_cert_p->undo_cmds.empty()) {
|
||||
pt::ptree undo_cmds_node;
|
||||
for (const auto& cmd : named_cert_p->undo_cmds) {
|
||||
undo_cmds_node.push_back(std::make_pair(""s, crypto::command_entry_t::serialize(cmd)));
|
||||
}
|
||||
named_cert_node.add_child("undo", undo_cmds_node);
|
||||
}
|
||||
|
||||
named_cert_nodes.push_back(std::make_pair(""s, named_cert_node));
|
||||
}
|
||||
}
|
||||
@@ -235,9 +282,8 @@ namespace nvhttp {
|
||||
try {
|
||||
pt::read_json(config::nvhttp.file_state, tree);
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG(error) << "Couldn't read "sv << config::nvhttp.file_state << ": "sv << e.what();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,11 +303,11 @@ namespace nvhttp {
|
||||
// Import from old format
|
||||
if (root.get_child_optional("devices")) {
|
||||
auto device_nodes = root.get_child("devices");
|
||||
for (auto &[_, device_node] : device_nodes) {
|
||||
for (auto& [_, device_node] : device_nodes) {
|
||||
auto uniqID = device_node.get<std::string>("uniqueid");
|
||||
|
||||
if (device_node.count("certs")) {
|
||||
for (auto &[_, el] : device_node.get_child("certs")) {
|
||||
for (auto& [_, el] : device_node.get_child("certs")) {
|
||||
auto named_cert_p = std::make_shared<crypto::named_cert_t>();
|
||||
named_cert_p->name = ""s;
|
||||
named_cert_p->cert = el.get_value<std::string>();
|
||||
@@ -274,19 +320,24 @@ namespace nvhttp {
|
||||
}
|
||||
|
||||
if (root.count("named_devices")) {
|
||||
for (auto &[_, el] : root.get_child("named_devices")) {
|
||||
for (auto& [_, el] : root.get_child("named_devices")) {
|
||||
auto named_cert_p = std::make_shared<crypto::named_cert_t>();
|
||||
named_cert_p->name = el.get<std::string>("name");
|
||||
named_cert_p->cert = el.get<std::string>("cert");
|
||||
named_cert_p->uuid = el.get<std::string>("uuid");
|
||||
named_cert_p->perm = (PERM)el.get("perm", (uint32_t)PERM::_all) & PERM::_all;
|
||||
|
||||
// Load commands
|
||||
named_cert_p->do_cmds = extract_command_entries(el, "do");
|
||||
named_cert_p->undo_cmds = extract_command_entries(el, "undo");
|
||||
|
||||
client.named_devices.emplace_back(named_cert_p);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty certificate chain and import certs from file
|
||||
cert_chain.clear();
|
||||
for (auto &named_cert : client.named_devices) {
|
||||
for (auto& named_cert : client.named_devices) {
|
||||
cert_chain.add(named_cert);
|
||||
}
|
||||
|
||||
@@ -366,6 +417,9 @@ namespace nvhttp {
|
||||
launch_session->virtual_display = util::from_view(get_arg(args, "virtualDisplay", "0"));
|
||||
launch_session->scale_factor = util::from_view(get_arg(args, "scaleFactor", "100"));
|
||||
|
||||
launch_session->client_do_cmds = named_cert_p->do_cmds;
|
||||
launch_session->client_undo_cmds = named_cert_p->undo_cmds;
|
||||
|
||||
return launch_session;
|
||||
}
|
||||
|
||||
@@ -932,6 +986,24 @@ namespace nvhttp {
|
||||
named_cert_node.put("uuid"s, named_cert_p->uuid);
|
||||
named_cert_node.put("perm", (uint32_t)named_cert_p->perm);
|
||||
|
||||
// Add "do" commands
|
||||
if (!named_cert_p->do_cmds.empty()) {
|
||||
pt::ptree do_cmds_node;
|
||||
for (const auto& cmd : named_cert_p->do_cmds) {
|
||||
do_cmds_node.push_back(std::make_pair(""s, crypto::command_entry_t::serialize(cmd)));
|
||||
}
|
||||
named_cert_node.add_child("do", do_cmds_node);
|
||||
}
|
||||
|
||||
// Add "undo" commands
|
||||
if (!named_cert_p->undo_cmds.empty()) {
|
||||
pt::ptree undo_cmds_node;
|
||||
for (const auto& cmd : named_cert_p->undo_cmds) {
|
||||
undo_cmds_node.push_back(std::make_pair(""s, crypto::command_entry_t::serialize(cmd)));
|
||||
}
|
||||
named_cert_node.add_child("undo", undo_cmds_node);
|
||||
}
|
||||
|
||||
if (connected_uuids.empty()) {
|
||||
named_cert_node.put("connected"s, false);
|
||||
} else {
|
||||
@@ -1563,7 +1635,13 @@ namespace nvhttp {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool update_device_info(const std::string& uuid, const std::string& name, const crypto::PERM newPerm) {
|
||||
bool update_device_info(
|
||||
const std::string& uuid,
|
||||
const std::string& name,
|
||||
const cmd_list_t& do_cmds,
|
||||
const cmd_list_t& undo_cmds,
|
||||
const crypto::PERM newPerm
|
||||
) {
|
||||
find_and_udpate_session_info(uuid, name, newPerm);
|
||||
|
||||
client_t &client = client_root;
|
||||
@@ -1573,6 +1651,8 @@ namespace nvhttp {
|
||||
if (named_cert_p->uuid == uuid) {
|
||||
named_cert_p->name = name;
|
||||
named_cert_p->perm = newPerm;
|
||||
named_cert_p->do_cmds = do_cmds;
|
||||
named_cert_p->undo_cmds = undo_cmds;
|
||||
save_state();
|
||||
return true;
|
||||
}
|
||||
|
||||
24
src/nvhttp.h
24
src/nvhttp.h
@@ -8,6 +8,7 @@
|
||||
// standard includes
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
|
||||
// lib includes
|
||||
#include <Simple-Web-Server/server_https.hpp>
|
||||
@@ -26,6 +27,7 @@ using namespace std::chrono_literals;
|
||||
namespace nvhttp {
|
||||
|
||||
using args_t = SimpleWeb::CaseInsensitiveMultimap;
|
||||
using cmd_list_t = std::list<crypto::command_entry_t>;
|
||||
|
||||
/**
|
||||
* @brief The protocol version.
|
||||
@@ -63,6 +65,10 @@ namespace nvhttp {
|
||||
std::string
|
||||
get_arg(const args_t &args, const char *name, const char *default_value = nullptr);
|
||||
|
||||
// Helper function to extract command entries
|
||||
cmd_list_t
|
||||
extract_command_entries(const boost::property_tree::ptree& pt, const std::string& key);
|
||||
|
||||
std::shared_ptr<rtsp_stream::launch_session_t>
|
||||
make_launch_session(bool host_audio, int appid, const args_t &args, const crypto::named_cert_t* named_cert_p);
|
||||
|
||||
@@ -262,9 +268,19 @@ namespace nvhttp {
|
||||
/**
|
||||
* @brief Update device info
|
||||
*
|
||||
* @param[in] uuid The uuid string
|
||||
* @param[in] name New name
|
||||
* @param[in] newPerm New permission
|
||||
* @param[in] uuid The uuid string
|
||||
* @param[in] name New name
|
||||
* @param[in] do_cmds The do commands
|
||||
* @param[in] undo_cmds The undo commands
|
||||
* @param[in] newPerm New permission
|
||||
*
|
||||
* @return Whether the update is successful
|
||||
*/
|
||||
bool update_device_info(const std::string& uuid, const std::string& name, const crypto::PERM newPerm);
|
||||
bool update_device_info(
|
||||
const std::string& uuid,
|
||||
const std::string& name,
|
||||
const cmd_list_t& do_cmds,
|
||||
const cmd_list_t& undo_cmds,
|
||||
const crypto::PERM newPerm
|
||||
);
|
||||
} // namespace nvhttp
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace rtsp_stream {
|
||||
std::string rtsp_url_scheme;
|
||||
uint32_t rtsp_iv_counter;
|
||||
|
||||
std::list<crypto::command_entry_t> client_do_cmds;
|
||||
std::list<crypto::command_entry_t> client_undo_cmds;
|
||||
|
||||
#ifdef _WIN32
|
||||
GUID display_guid{};
|
||||
#endif
|
||||
|
||||
@@ -409,6 +409,9 @@ namespace stream {
|
||||
std::string device_uuid;
|
||||
crypto::PERM permission;
|
||||
|
||||
std::list<crypto::command_entry_t> do_cmds;
|
||||
std::list<crypto::command_entry_t> undo_cmds;
|
||||
|
||||
safe::mail_raw_t::event_t<bool> shutdown_event;
|
||||
safe::signal_t controlEnd;
|
||||
|
||||
@@ -2076,6 +2079,25 @@ namespace stream {
|
||||
BOOST_LOG(debug) << "Resetting Input..."sv;
|
||||
input::reset(session.input);
|
||||
|
||||
if (!session.undo_cmds.empty()) {
|
||||
auto exec_thread = std::thread([cmd_list = session.undo_cmds]{
|
||||
for (auto &cmd : cmd_list) {
|
||||
std::error_code ec;
|
||||
auto env = proc::proc.get_env();
|
||||
boost::filesystem::path working_dir = proc::find_working_directory(cmd.cmd, env);
|
||||
auto child = platf::run_command(cmd.elevated, true, cmd.cmd, working_dir, env, nullptr, ec, nullptr);
|
||||
BOOST_LOG(info) << "Spawning client undo command ["sv << cmd.cmd << "] in ["sv << working_dir << ']';
|
||||
if (ec) {
|
||||
BOOST_LOG(warning) << "Couldn't spawn ["sv << cmd.cmd << "]: System: "sv << ec.message();
|
||||
} else {
|
||||
child.detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exec_thread.detach();
|
||||
}
|
||||
|
||||
// If this is the last session, invoke the platform callbacks
|
||||
if (--running_sessions == 0) {
|
||||
if (proc::proc.running()) {
|
||||
@@ -2130,6 +2152,25 @@ namespace stream {
|
||||
platf::streaming_will_start();
|
||||
}
|
||||
|
||||
if (!session.do_cmds.empty()) {
|
||||
auto exec_thread = std::thread([cmd_list = session.do_cmds]{
|
||||
for (auto &cmd : cmd_list) {
|
||||
std::error_code ec;
|
||||
auto env = proc::proc.get_env();
|
||||
boost::filesystem::path working_dir = proc::find_working_directory(cmd.cmd, env);
|
||||
auto child = platf::run_command(cmd.elevated, true, cmd.cmd, working_dir, env, nullptr, ec, nullptr);
|
||||
BOOST_LOG(info) << "Spawning client do command ["sv << cmd.cmd << "] in ["sv << working_dir << ']';
|
||||
if (ec) {
|
||||
BOOST_LOG(warning) << "Couldn't spawn ["sv << cmd.cmd << "]: System: "sv << ec.message();
|
||||
} else {
|
||||
child.detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exec_thread.detach();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2145,6 +2186,9 @@ namespace stream {
|
||||
session->device_uuid = launch_session.unique_id;
|
||||
session->permission = launch_session.perm;
|
||||
|
||||
session->do_cmds = std::move(launch_session.client_do_cmds);
|
||||
session->undo_cmds = std::move(launch_session.client_undo_cmds);
|
||||
|
||||
session->config = config;
|
||||
|
||||
session->control.connect_data = launch_session.control_connect_data;
|
||||
|
||||
Reference in New Issue
Block a user