Per client DO/UNDO commands server part - done

This commit is contained in:
Yukino Song
2025-01-22 21:04:29 +08:00
parent f4e445a58b
commit 4403cff32f
6 changed files with 175 additions and 12 deletions

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;