Support launching app with UUID

This commit is contained in:
Yukino Song
2025-05-13 18:17:44 +08:00
parent 96968b8bb2
commit 1798887e86
5 changed files with 44 additions and 27 deletions

View File

@@ -368,7 +368,7 @@ namespace nvhttp {
}
}
std::shared_ptr<rtsp_stream::launch_session_t> make_launch_session(bool host_audio, bool input_only, int appid, const args_t &args, const crypto::named_cert_t* named_cert_p) {
std::shared_ptr<rtsp_stream::launch_session_t> make_launch_session(bool host_audio, bool input_only, const args_t &args, const crypto::named_cert_t* named_cert_p) {
auto launch_session = std::make_shared<rtsp_stream::launch_session_t>();
launch_session->id = ++session_id_counter;
@@ -443,7 +443,6 @@ namespace nvhttp {
launch_session->device_name = named_cert_p->name.empty() ? "ApolloDisplay"s : named_cert_p->name;
launch_session->unique_id = named_cert_p->uuid;
launch_session->perm = named_cert_p->perm;
launch_session->appid = appid;
launch_session->enable_sops = util::from_view(get_arg(args, "sops", "0"));
launch_session->surround_info = util::from_view(get_arg(args, "surroundAudioInfo", "196610"));
launch_session->surround_params = (get_arg(args, "surroundParams", ""));
@@ -983,9 +982,11 @@ namespace nvhttp {
current_appid = 0;
}
tree.put("root.currentgame", current_appid);
tree.put("root.currentgameuuid", proc::proc.get_running_app_uuid());
tree.put("root.state", current_appid > 0 ? "SUNSHINE_SERVER_BUSY" : "SUNSHINE_SERVER_FREE");
} else {
tree.put("root.currentgame", 0);
tree.put("root.currentgameuuid", "");
tree.put("root.state", "SUNSHINE_SERVER_FREE");
}
@@ -1126,16 +1127,22 @@ namespace nvhttp {
auto args = request->parse_query_string();
auto appid_str = get_arg(args, "appid");
auto appid_str = get_arg(args, "appid", "0");
auto appuuid_str = get_arg(args, "appuuid", "");
auto appid = util::from_view(appid_str);
auto current_appid = proc::proc.running();
auto current_app_uuid = proc::proc.get_running_app_uuid();
bool is_input_only = config::input.enable_input_only_mode && appid == proc::input_only_app_id;
auto named_cert_p = get_verified_cert(request);
auto perm = PERM::launch;
// If we have already launched an app, we should allow clients with view permission to join the input only or current app's session.
if (current_appid > 0 && appid != proc::terminate_app_id && (is_input_only || appid == current_appid)) {
if (
current_appid > 0
&& (appuuid_str != TERMINATE_APP_UUID || appid != proc::terminate_app_id)
&& (is_input_only || appid == current_appid || (!appuuid_str.empty() && appuuid_str == current_app_uuid))
) {
perm = PERM::_allow_view;
}
@@ -1152,7 +1159,7 @@ namespace nvhttp {
args.find("rikey"s) == std::end(args) ||
args.find("rikeyid"s) == std::end(args) ||
args.find("localAudioPlayMode"s) == std::end(args) ||
args.find("appid"s) == std::end(args)
(args.find("appid"s) == std::end(args) && args.find("appuuid"s) == std::end(args))
) {
tree.put("root.resume", 0);
tree.put("root.<xmlattr>.status_code", 400);
@@ -1163,7 +1170,10 @@ namespace nvhttp {
if (!is_input_only) {
// Special handling for the "terminate" app
if (config::input.enable_input_only_mode && appid == proc::terminate_app_id) {
if (
(config::input.enable_input_only_mode && appid == proc::terminate_app_id)
|| appuuid_str == TERMINATE_APP_UUID
) {
proc::proc.terminate();
tree.put("root.resume", 0);
@@ -1173,7 +1183,14 @@ namespace nvhttp {
return;
}
if (current_appid > 0 && current_appid != proc::input_only_app_id && appid != current_appid) {
if (
current_appid > 0
&& current_appid != proc::input_only_app_id
&& (
(appid > 0 && appid != current_appid)
|| (!appuuid_str.empty() && appuuid_str != current_app_uuid)
)
) {
tree.put("root.resume", 0);
tree.put("root.<xmlattr>.status_code", 400);
tree.put("root.<xmlattr>.status_message", "An app is already running on this host");
@@ -1183,7 +1200,7 @@ namespace nvhttp {
}
host_audio = util::from_view(get_arg(args, "localAudioPlayMode"));
auto launch_session = make_launch_session(host_audio, is_input_only, appid, args, named_cert_p);
auto launch_session = make_launch_session(host_audio, is_input_only, args, named_cert_p);
auto encryption_mode = net::encryption_mode_for_address(request->remote_endpoint().address());
if (!launch_session->rtsp_cipher && encryption_mode == config::ENCRYPTION_MODE_MANDATORY) {
@@ -1212,8 +1229,8 @@ namespace nvhttp {
proc::proc.launch_input_only();
}
}
} else if (appid > 0) {
if (appid == current_appid) {
} else if (appid > 0 || !appuuid_str.empty()) {
if (appid == current_appid || (!appuuid_str.empty() && appuuid_str == current_app_uuid)) {
// We're basically resuming the same app
if (!proc::proc.allow_client_commands) {
launch_session->client_do_cmds.clear();
@@ -1236,12 +1253,12 @@ namespace nvhttp {
}
} else {
const auto& apps = proc::proc.get_apps();
auto app_iter = std::find_if(apps.begin(), apps.end(), [&appid_str](const auto _app) {
return _app.id == appid_str;
auto app_iter = std::find_if(apps.begin(), apps.end(), [&appid_str, &appuuid_str](const auto _app) {
return _app.id == appid_str || _app.uuid == appuuid_str;
});
if (app_iter == apps.end()) {
BOOST_LOG(error) << "Couldn't find app with ID ["sv << appid_str << ']';
BOOST_LOG(error) << "Couldn't find app with ID ["sv << appid_str << "] or UUID ["sv << appuuid_str << ']';
tree.put("root.<xmlattr>.status_code", 404);
tree.put("root.<xmlattr>.status_message", "Cannot find requested application");
tree.put("root.gamesession", 0);
@@ -1253,7 +1270,7 @@ namespace nvhttp {
launch_session->client_undo_cmds.clear();
}
auto err = proc::proc.execute(appid, *app_iter, launch_session);
auto err = proc::proc.execute(*app_iter, launch_session);
if (err) {
tree.put("root.<xmlattr>.status_code", err);
tree.put(
@@ -1330,7 +1347,7 @@ namespace nvhttp {
if (no_active_sessions && args.find("localAudioPlayMode"s) != std::end(args)) {
host_audio = util::from_view(get_arg(args, "localAudioPlayMode"));
}
auto launch_session = make_launch_session(host_audio, false, 0, args, named_cert_p);
auto launch_session = make_launch_session(host_audio, false, args, named_cert_p);
if (!proc::proc.allow_client_commands) {
launch_session->client_do_cmds.clear();