diff --git a/src/config.cpp b/src/config.cpp index 371e8b24..c320ed6d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -556,8 +556,8 @@ namespace config { true, // client gamepads with touchpads are emulated as DS4 true, // ds5_inputtino_randomize_mac - false, // keyboard disabled (Parsec-style default) - false, // mouse disabled (Parsec-style default) + true, // keyboard enabled + true, // mouse enabled true, // controller enabled true, // always send scancodes true, // high resolution scrolling @@ -1235,8 +1235,6 @@ namespace config { bool_f(vars, "high_resolution_scrolling", input.high_resolution_scrolling); bool_f(vars, "native_pen_touch", input.native_pen_touch); - list_string_f(vars, "owner_client_uuids", input.owner_client_uuids); - bool_f(vars, "notify_pre_releases", sunshine.notify_pre_releases); bool_f(vars, "system_tray", sunshine.system_tray); diff --git a/src/config.h b/src/config.h index c984bce3..e8d1594f 100644 --- a/src/config.h +++ b/src/config.h @@ -203,8 +203,6 @@ namespace config { bool high_resolution_scrolling; bool native_pen_touch; - - std::vector owner_client_uuids; }; namespace flag { diff --git a/src/confighttp.cpp b/src/confighttp.cpp index 599aba0b..85d66077 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -7,18 +7,10 @@ #define BOOST_BIND_GLOBAL_PLACEHOLDERS // standard includes -#include -#include -#include -#include #include #include #include -#include #include -#include -#include -#include // lib includes #include @@ -27,8 +19,6 @@ #include #include #include -#include -#include #ifdef _WIN32 #include "platform/windows/misc.h" @@ -50,7 +40,6 @@ #include "nvhttp.h" #include "platform/common.h" #include "process.h" -#include "stream.h" #include "utility.h" #include "uuid.h" @@ -65,119 +54,6 @@ namespace confighttp { using resp_https_t = std::shared_ptr::Response>; using req_https_t = std::shared_ptr::Request>; - namespace { - struct ws_client_t { - std::unique_ptr socket; - std::mutex write_mutex; - std::atomic_bool alive {true}; - }; - - constexpr std::chrono::seconds WS_TOKEN_TTL {30}; - constexpr std::chrono::milliseconds WS_PUSH_INTERVAL {250}; - constexpr std::string_view WS_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - - std::mutex ws_clients_mutex; - std::vector> ws_clients; - - std::mutex ws_tokens_mutex; - std::unordered_map ws_tokens; - - void cleanup_ws_tokens(const std::chrono::steady_clock::time_point &now) { - for (auto it = ws_tokens.begin(); it != ws_tokens.end();) { - if (it->second <= now) { - it = ws_tokens.erase(it); - } else { - ++it; - } - } - } - - std::string create_ws_token() { - auto now = std::chrono::steady_clock::now(); - auto token = uuid_util::uuid_t::generate().string(); - - std::lock_guard lg {ws_tokens_mutex}; - cleanup_ws_tokens(now); - ws_tokens[token] = now + WS_TOKEN_TTL; - - return token; - } - - bool consume_ws_token(std::string_view token) { - auto now = std::chrono::steady_clock::now(); - - std::lock_guard lg {ws_tokens_mutex}; - cleanup_ws_tokens(now); - - auto it = ws_tokens.find(std::string(token)); - if (it == ws_tokens.end()) { - return false; - } - - ws_tokens.erase(it); - return true; - } - - std::string websocket_accept_key(std::string_view key) { - std::string input; - input.reserve(key.size() + WS_GUID.size()); - input.append(key); - input.append(WS_GUID); - - std::array digest {}; - SHA1(reinterpret_cast(input.data()), input.size(), digest.data()); - - std::array encoded {}; - auto len = EVP_EncodeBlock(encoded.data(), digest.data(), digest.size()); - - return std::string(reinterpret_cast(encoded.data()), len); - } - - std::string websocket_text_frame(const std::string &payload) { - std::string frame; - frame.reserve(payload.size() + 10); - frame.push_back(static_cast(0x81)); - - auto len = payload.size(); - if (len <= 125) { - frame.push_back(static_cast(len)); - } else if (len <= 0xFFFF) { - frame.push_back(static_cast(126)); - frame.push_back(static_cast((len >> 8) & 0xFF)); - frame.push_back(static_cast(len & 0xFF)); - } else { - frame.push_back(static_cast(127)); - for (int i = 7; i >= 0; --i) { - frame.push_back(static_cast((len >> (i * 8)) & 0xFF)); - } - } - - frame.append(payload); - return frame; - } - - void ws_write_http_response(std::unique_ptr &socket, SimpleWeb::StatusCode code, std::string_view body) { - if (!socket) { - return; - } - - std::string response; - response.reserve(256 + body.size()); - response.append("HTTP/1.1 "); - response.append(SimpleWeb::status_code(code)); - response.append("\r\nContent-Type: application/json\r\n"); - response.append("Connection: close\r\n"); - response.append("Content-Length: "); - response.append(std::to_string(body.size())); - response.append("\r\n\r\n"); - response.append(body); - - boost::system::error_code ec; - boost::asio::write(*socket, boost::asio::buffer(response), ec); - socket->lowest_layer().close(ec); - } - } - enum class op_e { ADD, ///< Add client REMOVE ///< Remove client @@ -260,24 +136,6 @@ namespace confighttp { response->write(SimpleWeb::StatusCode::redirection_temporary_redirect, headers); } - bool authenticate_header(std::string_view raw_auth) { - if (raw_auth.size() < "Basic "sv.size() || raw_auth.substr(0, "Basic "sv.size()) != "Basic "sv) { - return false; - } - - auto auth_data = SimpleWeb::Crypto::Base64::decode(std::string(raw_auth.substr("Basic "sv.length()))); - auto index = (int) auth_data.find(':'); - if (index >= auth_data.size() - 1) { - return false; - } - - auto username = auth_data.substr(0, index); - auto password = auth_data.substr(index + 1); - auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); - - return boost::iequals(username, config::sunshine.username) && hash == config::sunshine.password; - } - /** * @brief Authenticate the user. * @param response The HTTP response object. @@ -309,7 +167,19 @@ namespace confighttp { return false; } - if (!authenticate_header(auth->second)) { + auto &rawAuth = auth->second; + auto authData = SimpleWeb::Crypto::Base64::decode(rawAuth.substr("Basic "sv.length())); + + auto index = (int) authData.find(':'); + if (index >= authData.size() - 1) { + return false; + } + + auto username = authData.substr(0, index); + auto password = authData.substr(index + 1); + auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string(); + + if (!boost::iequals(username, config::sunshine.username) || hash != config::sunshine.password) { return false; } @@ -935,93 +805,6 @@ namespace confighttp { send_response(response, output_tree); } - void getActiveSessions(resp_https_t response, req_https_t request) { - if (!authenticate(response, request)) { - return; - } - - print_req(request); - - nlohmann::json output_tree; - output_tree["sessions"] = stream::get_active_sessions_info(); - output_tree["status"] = true; - send_response(response, output_tree); - } - - void getActiveSessionsWsToken(resp_https_t response, req_https_t request) { - if (!authenticate(response, request)) { - return; - } - - print_req(request); - - nlohmann::json output_tree; - output_tree["token"] = create_ws_token(); - output_tree["status"] = true; - send_response(response, output_tree); - } - - void setActiveSessionPolicy(resp_https_t response, req_https_t request) { - if (!check_content_type(response, request, "application/json")) { - return; - } - if (!authenticate(response, request)) { - return; - } - - print_req(request); - - std::stringstream ss; - ss << request->content.rdbuf(); - - try { - nlohmann::json output_tree; - const nlohmann::json input_tree = nlohmann::json::parse(ss); - - if (!input_tree.contains("session_id") || - !input_tree.contains("allow_keyboard") || - !input_tree.contains("allow_mouse") || - !input_tree.contains("allow_gamepad")) { - bad_request(response, request, "Missing required session policy fields"); - return; - } - - const uint32_t session_id = input_tree.at("session_id").get(); - const bool allow_keyboard = input_tree.at("allow_keyboard").get(); - const bool allow_mouse = input_tree.at("allow_mouse").get(); - const bool allow_gamepad = input_tree.at("allow_gamepad").get(); - - bool effective_keyboard; - bool effective_mouse; - bool effective_gamepad; - const bool updated = stream::set_active_session_input_policy( - session_id, - allow_keyboard, - allow_mouse, - allow_gamepad, - &effective_keyboard, - &effective_mouse, - &effective_gamepad); - - output_tree["status"] = updated; - if (!updated) { - output_tree["error"] = "Active session not found"; - } else { - output_tree["session_id"] = session_id; - output_tree["policy"] = { - {"allow_keyboard", effective_keyboard}, - {"allow_mouse", effective_mouse}, - {"allow_gamepad", effective_gamepad}, - }; - } - - send_response(response, output_tree); - } catch (std::exception &e) { - BOOST_LOG(warning) << "SetActiveSessionPolicy: "sv << e.what(); - bad_request(response, request, e.what()); - } - } - /** * @brief Unpair a client. * @param response The HTTP response object. @@ -1671,74 +1454,12 @@ namespace confighttp { server.resource["^/api/clients/unpair-all$"]["POST"] = unpairAll; server.resource["^/api/clients/list$"]["GET"] = getClients; server.resource["^/api/clients/unpair$"]["POST"] = unpair; - server.resource["^/api/sessions/active$"]["GET"] = getActiveSessions; - server.resource["^/api/sessions/ws-token$"]["GET"] = getActiveSessionsWsToken; - server.resource["^/api/sessions/policy$"]["POST"] = setActiveSessionPolicy; server.resource["^/api/apps/close$"]["POST"] = closeApp; server.resource["^/api/covers/upload$"]["POST"] = uploadCover; server.resource["^/api/covers/([0-9]+)$"]["GET"] = getCover; server.resource["^/images/sunshine.ico$"]["GET"] = getFaviconImage; server.resource["^/images/logo-sunshine-45.png$"]["GET"] = getSunshineLogoImage; server.resource["^/assets\\/.+$"]["GET"] = getNodeModules; - - server.on_upgrade = [](std::unique_ptr &socket, req_https_t request) { - if (!socket || request->path != "/api/sessions/active/ws") { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_not_found, R"({"status":false})"); - return; - } - - auto address = net::addr_to_normalized_string(request->remote_endpoint().address()); - if (net::from_address(address) > http::origin_web_ui_allowed) { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_forbidden, R"({"status":false})"); - return; - } - - if (config::sunshine.username.empty()) { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_unauthorized, R"({"status":false})"); - return; - } - - auto auth = request->header.find("Authorization"); - if (auth != request->header.end() && !authenticate_header(auth->second)) { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_unauthorized, R"({"status":false})"); - return; - } - - auto query = request->parse_query_string(); - auto token_it = query.find("token"); - if (token_it == query.end() || !consume_ws_token(token_it->second)) { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_forbidden, R"({"status":false})"); - return; - } - - auto key_it = request->header.find("Sec-WebSocket-Key"); - if (key_it == request->header.end()) { - ws_write_http_response(socket, SimpleWeb::StatusCode::client_error_bad_request, R"({"status":false})"); - return; - } - - std::string response; - response.reserve(256); - response.append("HTTP/1.1 101 Switching Protocols\r\n"); - response.append("Upgrade: websocket\r\n"); - response.append("Connection: Upgrade\r\n"); - response.append("Sec-WebSocket-Accept: "); - response.append(websocket_accept_key(key_it->second)); - response.append("\r\n\r\n"); - - boost::system::error_code ec; - boost::asio::write(*socket, boost::asio::buffer(response), ec); - if (ec) { - socket->lowest_layer().close(ec); - return; - } - - auto client = std::make_shared(); - client->socket = std::move(socket); - - std::lock_guard lg {ws_clients_mutex}; - ws_clients.emplace_back(std::move(client)); - }; server.config.reuse_address = true; server.config.address = net::get_bind_address(address_family); server.config.port = port_https; @@ -1762,58 +1483,11 @@ namespace confighttp { }; std::thread tcp {accept_and_run, &server}; - std::thread ws_broadcast {[&] { - platf::set_thread_name("confighttp::ws"); - - while (!shutdown_event->peek()) { - std::vector> clients; - { - std::lock_guard lg {ws_clients_mutex}; - clients = ws_clients; - } - - if (!clients.empty()) { - nlohmann::json output_tree; - output_tree["sessions"] = stream::get_active_sessions_info(); - output_tree["status"] = true; - auto frame = websocket_text_frame(output_tree.dump()); - - for (auto &client : clients) { - if (!client->alive.load(std::memory_order_relaxed)) { - continue; - } - - std::lock_guard write_lg {client->write_mutex}; - if (!client->socket) { - client->alive.store(false, std::memory_order_relaxed); - continue; - } - - boost::system::error_code ec; - boost::asio::write(*client->socket, boost::asio::buffer(frame), ec); - if (ec) { - client->alive.store(false, std::memory_order_relaxed); - client->socket->lowest_layer().close(ec); - } - } - - std::lock_guard lg {ws_clients_mutex}; - ws_clients.erase(std::remove_if(std::begin(ws_clients), std::end(ws_clients), [](const auto &client) { - return !client->alive.load(std::memory_order_relaxed); - }), std::end(ws_clients)); - } - - std::this_thread::sleep_for(WS_PUSH_INTERVAL); - } - }}; - // Wait for any event shutdown_event->view(); server.stop(); - ws_broadcast.join(); - tcp.join(); } } // namespace confighttp diff --git a/src/input.cpp b/src/input.cpp index 908fec79..82c761af 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -41,18 +41,6 @@ namespace input { #define DISABLE_LEFT_BUTTON_DELAY ((thread_pool_util::ThreadPool::task_id_t) 0x01) #define ENABLE_LEFT_BUTTON_DELAY nullptr - static uint64_t now_ms() { - return std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch() - ).count(); - } - - static inline void touch_activity(std::atomic *ts) { - if (ts) { - ts->store(now_ms(), std::memory_order_relaxed); - } - } - constexpr auto VKEY_SHIFT = 0x10; constexpr auto VKEY_LSHIFT = 0xA0; constexpr auto VKEY_RSHIFT = 0xA1; @@ -184,10 +172,7 @@ namespace input { mouse_left_button_timeout {}, touch_port {{0, 0, 0, 0}, 0, 0, 1.0f, 1.0f, 0, 0}, accumulated_vscroll_delta {}, - accumulated_hscroll_delta {}, - allow_keyboard {true}, - allow_mouse {true}, - allow_gamepad {true} { + accumulated_hscroll_delta {} { } // Keep track of alt+ctrl+shift key combo @@ -208,28 +193,8 @@ namespace input { int32_t accumulated_vscroll_delta; int32_t accumulated_hscroll_delta; - - std::atomic *activity_keyboard_ms = nullptr; - std::atomic *activity_mouse_ms = nullptr; - std::atomic *activity_gamepad_ms = nullptr; - - std::atomic allow_keyboard; - std::atomic allow_mouse; - std::atomic allow_gamepad; }; - static inline bool keyboard_allowed(const std::shared_ptr &input) { - return config::input.keyboard && input->allow_keyboard.load(std::memory_order_relaxed); - } - - static inline bool mouse_allowed(const std::shared_ptr &input) { - return config::input.mouse && input->allow_mouse.load(std::memory_order_relaxed); - } - - static inline bool gamepad_allowed(const std::shared_ptr &input) { - return config::input.controller && input->allow_gamepad.load(std::memory_order_relaxed); - } - /** * @brief Apply shortcut based on VKEY * @param keyCode The VKEY code @@ -477,12 +442,10 @@ namespace input { } void passthrough(std::shared_ptr &input, PNV_REL_MOUSE_MOVE_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - input->mouse_left_button_timeout = DISABLE_LEFT_BUTTON_DELAY; platf::move_mouse(platf_input, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY)); } @@ -576,12 +539,10 @@ namespace input { } void passthrough(std::shared_ptr &input, PNV_ABS_MOUSE_MOVE_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - if (input->mouse_left_button_timeout == DISABLE_LEFT_BUTTON_DELAY) { input->mouse_left_button_timeout = ENABLE_LEFT_BUTTON_DELAY; } @@ -628,12 +589,10 @@ namespace input { } void passthrough(std::shared_ptr &input, PNV_MOUSE_BUTTON_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - auto release = util::endian::little(packet->header.magic) == MOUSE_BUTTON_UP_EVENT_MAGIC_GEN5; auto button = util::endian::big(packet->button); if (button > 0 && button < mouse_press.size()) { @@ -794,12 +753,10 @@ namespace input { } void passthrough(std::shared_ptr &input, PNV_KEYBOARD_PACKET packet) { - if (!keyboard_allowed(input)) { + if (!config::input.keyboard) { return; } - touch_activity(input->activity_keyboard_ms); - auto release = util::endian::little(packet->header.magic) == KEY_UP_EVENT_MAGIC; auto keyCode = packet->keyCode & 0x00FF; @@ -856,12 +813,10 @@ namespace input { * @param packet The scroll packet. */ void passthrough(std::shared_ptr &input, PNV_SCROLL_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - if (config::input.high_resolution_scrolling) { platf::scroll(platf_input, util::endian::big(packet->scrollAmt1)); } else { @@ -881,12 +836,10 @@ namespace input { * @param packet The scroll packet. */ void passthrough(std::shared_ptr &input, PSS_HSCROLL_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - if (config::input.high_resolution_scrolling) { platf::hscroll(platf_input, util::endian::big(packet->scrollAmount)); } else { @@ -900,8 +853,8 @@ namespace input { } } - void passthrough(std::shared_ptr &input, PNV_UNICODE_PACKET packet) { - if (!keyboard_allowed(input)) { + void passthrough(PNV_UNICODE_PACKET packet) { + if (!config::input.keyboard) { return; } @@ -915,12 +868,10 @@ namespace input { * @param packet The controller arrival packet. */ void passthrough(std::shared_ptr &input, PSS_CONTROLLER_ARRIVAL_PACKET packet) { - if (!gamepad_allowed(input)) { + if (!config::input.controller) { return; } - touch_activity(input->activity_gamepad_ms); - if (packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) { BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']'; return; @@ -957,12 +908,10 @@ namespace input { * @param packet The touch packet. */ void passthrough(std::shared_ptr &input, PSS_TOUCH_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - // Convert the client normalized coordinates to touchport coordinates auto coords = client_to_touchport(input, {from_clamped_netfloat(packet->x, 0.0f, 1.0f) * 65535.f, from_clamped_netfloat(packet->y, 0.0f, 1.0f) * 65535.f}, {65535.f, 65535.f}); if (!coords) { @@ -1015,12 +964,10 @@ namespace input { * @param packet The pen packet. */ void passthrough(std::shared_ptr &input, PSS_PEN_PACKET packet) { - if (!mouse_allowed(input)) { + if (!config::input.mouse) { return; } - touch_activity(input->activity_mouse_ms); - // Convert the client normalized coordinates to touchport coordinates auto coords = client_to_touchport(input, {from_clamped_netfloat(packet->x, 0.0f, 1.0f) * 65535.f, from_clamped_netfloat(packet->y, 0.0f, 1.0f) * 65535.f}, {65535.f, 65535.f}); if (!coords) { @@ -1075,12 +1022,10 @@ namespace input { * @param packet The controller touch packet. */ void passthrough(std::shared_ptr &input, PSS_CONTROLLER_TOUCH_PACKET packet) { - if (!gamepad_allowed(input)) { + if (!config::input.controller) { return; } - touch_activity(input->activity_gamepad_ms); - if (packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) { BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']'; return; @@ -1110,12 +1055,10 @@ namespace input { * @param packet The controller motion packet. */ void passthrough(std::shared_ptr &input, PSS_CONTROLLER_MOTION_PACKET packet) { - if (!gamepad_allowed(input)) { + if (!config::input.controller) { return; } - touch_activity(input->activity_gamepad_ms); - if (packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) { BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']'; return; @@ -1144,12 +1087,10 @@ namespace input { * @param packet The controller battery packet. */ void passthrough(std::shared_ptr &input, PSS_CONTROLLER_BATTERY_PACKET packet) { - if (!gamepad_allowed(input)) { + if (!config::input.controller) { return; } - touch_activity(input->activity_gamepad_ms); - if (packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) { BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']'; return; @@ -1171,12 +1112,10 @@ namespace input { } void passthrough(std::shared_ptr &input, PNV_MULTI_CONTROLLER_PACKET packet) { - if (!gamepad_allowed(input)) { + if (!config::input.controller) { return; } - touch_activity(input->activity_gamepad_ms); - if (packet->controllerNumber < 0 || packet->controllerNumber >= input->gamepads.size()) { BOOST_LOG(warning) << "ControllerNumber out of range ["sv << packet->controllerNumber << ']'; @@ -1639,7 +1578,7 @@ namespace input { passthrough(input, (PNV_KEYBOARD_PACKET) payload); break; case UTF8_TEXT_EVENT_MAGIC: - passthrough(input, (PNV_UNICODE_PACKET) payload); + passthrough((PNV_UNICODE_PACKET) payload); break; case MULTI_CONTROLLER_MAGIC_GEN5: passthrough(input, (PNV_MULTI_CONTROLLER_PACKET) payload); @@ -1687,8 +1626,8 @@ namespace input { for (int x = 0; x < mouse_press.size(); ++x) { if (mouse_press[x]) { platf::button_mouse(platf_input, x, true); + mouse_press[x] = false; } - mouse_press[x] = false; } for (auto &kp : key_press) { @@ -1699,10 +1638,7 @@ namespace input { platf::keyboard_update(platf_input, vk_from_kpid(kp.first) & 0x00FF, true, flags_from_kpid(kp.first)); key_press[kp.first] = false; } - - key_press.clear(); - key_press_repeat_id = nullptr; - }).wait(); + }); } class deinit_t: public platf::deinit_t { @@ -1744,24 +1680,4 @@ namespace input { return input; } - - void set_activity_pointers( - std::shared_ptr &input, - std::atomic *keyboard_ms, - std::atomic *mouse_ms, - std::atomic *gamepad_ms) { - input->activity_keyboard_ms = keyboard_ms; - input->activity_mouse_ms = mouse_ms; - input->activity_gamepad_ms = gamepad_ms; - } - - void set_policy( - std::shared_ptr &input, - bool allow_keyboard, - bool allow_mouse, - bool allow_gamepad) { - input->allow_keyboard.store(allow_keyboard, std::memory_order_relaxed); - input->allow_mouse.store(allow_mouse, std::memory_order_relaxed); - input->allow_gamepad.store(allow_gamepad, std::memory_order_relaxed); - } } // namespace input diff --git a/src/input.h b/src/input.h index 9426db71..5b564f04 100644 --- a/src/input.h +++ b/src/input.h @@ -24,18 +24,6 @@ namespace input { std::shared_ptr alloc(safe::mail_t mail); - void set_activity_pointers( - std::shared_ptr &input, - std::atomic *keyboard_ms, - std::atomic *mouse_ms, - std::atomic *gamepad_ms); - - void set_policy( - std::shared_ptr &input, - bool allow_keyboard, - bool allow_mouse, - bool allow_gamepad); - struct touch_port_t: public platf::touch_port_t { int env_width, env_height; diff --git a/src/nvhttp.cpp b/src/nvhttp.cpp index dff43e07..4d8a87b4 100644 --- a/src/nvhttp.cpp +++ b/src/nvhttp.cpp @@ -279,53 +279,6 @@ namespace nvhttp { } } - /** - * @brief Resolve the real paired client UUID from the SSL peer certificate. - * @param request The HTTPS request whose peer cert identifies the client. - * @return The paired client's UUID, or empty string if not found. - * - * Moonlight sends a placeholder uniqueid ("0123456789ABCDEF") in the launch - * query string. The real identity is the SSL client certificate presented - * during the TLS handshake, which we match against our paired device list. - */ - std::string resolve_client_uuid(req_https_t request) { - auto conn = request->connection_shared(); - if (!conn) { - BOOST_LOG(warning) << "resolve_client_uuid: connection expired"sv; - return {}; - } - - auto ssl = conn->socket->native_handle(); - if (!ssl) { - BOOST_LOG(warning) << "resolve_client_uuid: no SSL handle"sv; - return {}; - } - - crypto::x509_t peer_cert { -#if OPENSSL_VERSION_MAJOR >= 3 - SSL_get1_peer_certificate(ssl) -#else - SSL_get_peer_certificate(ssl) -#endif - }; - if (!peer_cert) { - BOOST_LOG(warning) << "resolve_client_uuid: no peer certificate"sv; - return {}; - } - - auto peer_pem = crypto::pem(peer_cert); - - for (const auto &device : client_root.named_devices) { - if (device.cert == peer_pem) { - BOOST_LOG(info) << "resolve_client_uuid: matched paired client '"sv << device.name << "' uuid="sv << device.uuid; - return device.uuid; - } - } - - BOOST_LOG(warning) << "resolve_client_uuid: peer cert did not match any paired device"sv; - return {}; - } - std::shared_ptr make_launch_session(bool host_audio, const args_t &args) { auto launch_session = std::make_shared(); @@ -829,15 +782,6 @@ namespace nvhttp { return named_cert_nodes; } - std::string get_client_name(const std::string &uuid) { - for (auto &named_cert : client_root.named_devices) { - if (named_cert.uuid == uuid) { - return named_cert.name; - } - } - return ""; - } - void applist(resp_https_t response, req_https_t request) { print_req(request); @@ -915,11 +859,6 @@ namespace nvhttp { host_audio = util::from_view(get_arg(args, "localAudioPlayMode")); auto launch_session = make_launch_session(host_audio, args); - auto resolved_uuid = resolve_client_uuid(request); - if (!resolved_uuid.empty()) { - launch_session->unique_id = std::move(resolved_uuid); - } - if (rtsp_stream::session_count() == 0) { // The display should be restored in case something fails as there are no other sessions. revert_display_configuration = true; @@ -1028,11 +967,6 @@ namespace nvhttp { } const auto launch_session = make_launch_session(host_audio, args); - auto resolved_uuid = resolve_client_uuid(request); - if (!resolved_uuid.empty()) { - launch_session->unique_id = std::move(resolved_uuid); - } - if (no_active_sessions) { // We want to prepare display only if there are no active sessions at // the moment. This should be done before probing encoders as it could diff --git a/src/nvhttp.h b/src/nvhttp.h index a0428ec7..63633707 100644 --- a/src/nvhttp.h +++ b/src/nvhttp.h @@ -193,8 +193,6 @@ namespace nvhttp { */ nlohmann::json get_all_clients(); - std::string get_client_name(const std::string &uuid); - /** * @brief Remove all paired clients. * @examples diff --git a/src/platform/linux/wlgrab.cpp b/src/platform/linux/wlgrab.cpp index c989d849..9ef3e09f 100644 --- a/src/platform/linux/wlgrab.cpp +++ b/src/platform/linux/wlgrab.cpp @@ -3,7 +3,6 @@ * @brief Definitions for wlgrab capture. */ // standard includes -#include #include // local includes @@ -58,30 +57,6 @@ namespace wl { if (streamedMonitor >= 0 && streamedMonitor < interface.monitors.size()) { monitor = interface.monitors[streamedMonitor].get(); - } else { - auto by_name = std::find_if( - std::begin(interface.monitors), - std::end(interface.monitors), - [&display_name](const auto &candidate) { - return candidate->name == display_name; - }); - - if (by_name != std::end(interface.monitors)) { - monitor = by_name->get(); - } else { - auto by_description = std::find_if( - std::begin(interface.monitors), - std::end(interface.monitors), - [&display_name](const auto &candidate) { - return candidate->description == display_name; - }); - - if (by_description != std::end(interface.monitors)) { - monitor = by_description->get(); - } else { - BOOST_LOG(warning) << "No Wayland monitor matched output_name='"sv << display_name << "'; falling back to monitor 0"sv; - } - } } } @@ -456,12 +431,8 @@ namespace platf { BOOST_LOG(info) << "Monitor " << x << " is "sv << monitor->name << ": "sv << monitor->description; - if (!monitor->name.empty()) { - display_names.emplace_back(monitor->name); - } else { - display_names.emplace_back(std::to_string(x)); - } - } + display_names.emplace_back(std::to_string(x)); + } BOOST_LOG(info) << "--------- End of Wayland monitor list ---------"sv; diff --git a/src/stream.cpp b/src/stream.cpp index 1af48201..b92e579e 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -4,7 +4,6 @@ */ // standard includes -#include #include #include #include @@ -27,7 +26,6 @@ extern "C" { #include "input.h" #include "logging.h" #include "network.h" -#include "nvhttp.h" #include "platform/common.h" #include "process.h" #include "stream.h" @@ -51,12 +49,6 @@ extern "C" { #define IDX_SET_MOTION_EVENT 13 #define IDX_SET_RGB_LED 14 #define IDX_SET_ADAPTIVE_TRIGGERS 15 -#define IDX_SET_INPUT_POLICY 16 - -#define INPUT_POLICY_REASON_STREAM_START 0 -#define INPUT_POLICY_REASON_USER_TOGGLE 1 -#define INPUT_POLICY_REASON_HOST_ACK 2 -#define INPUT_POLICY_REASON_HOST_OVERRIDE 3 static const short packetTypes[] = { 0x0305, // Start A @@ -75,7 +67,6 @@ static const short packetTypes[] = { 0x5501, // Set motion event (Sunshine protocol extension) 0x5502, // Set RGB LED (Sunshine protocol extension) 0x5503, // Set Adaptive triggers (Sunshine protocol extension) - 0x5504, }; namespace asio = boost::asio; @@ -212,13 +203,6 @@ namespace stream { std::uint8_t right[DS_EFFECT_PAYLOAD_SIZE]; }; - struct control_set_input_policy_t { - std::uint8_t allow_keyboard; - std::uint8_t allow_mouse; - std::uint8_t allow_gamepad; - std::uint8_t reason; - }; - struct control_hdr_mode_t { control_header_v2 header; @@ -356,34 +340,6 @@ namespace stream { control_server_t control_server; }; - /** - * @brief Per-session input policy (which remote input types are allowed). - */ - struct session_input_policy_t { - std::atomic allow_gamepad {true}; - std::atomic allow_keyboard {false}; - std::atomic allow_mouse {false}; - std::atomic is_owner_session {false}; - }; - - /** - * @brief Per-session input activity timestamps (monotonic ms). - */ - struct session_input_activity_t { - std::atomic last_keyboard_ms {0}; - std::atomic last_mouse_ms {0}; - std::atomic last_gamepad_ms {0}; - }; - - /** - * @brief Return current monotonic time in milliseconds. - */ - static uint64_t now_monotonic_ms() { - return std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch() - ).count(); - } - struct session_t { config_t config; @@ -391,12 +347,6 @@ namespace stream { std::shared_ptr input; - // Parsec-style per-session state - std::string client_unique_id; - std::string client_name; - session_input_policy_t input_policy; - session_input_activity_t input_activity; - std::thread audioThread; std::thread videoThread; @@ -462,55 +412,6 @@ namespace stream { std::atomic state; }; - template - static inline std::string_view encode_control(session_t *session, const std::string_view &plaintext, std::array &tagged_cipher); - - static void apply_session_input_policy(session_t *session, bool allow_keyboard, bool allow_mouse, bool allow_gamepad, uint8_t reason) { - auto effective_keyboard = config::input.keyboard && allow_keyboard; - auto effective_mouse = config::input.mouse && allow_mouse; - auto effective_gamepad = config::input.controller && allow_gamepad; - - session->input_policy.allow_keyboard.store(effective_keyboard, std::memory_order_relaxed); - session->input_policy.allow_mouse.store(effective_mouse, std::memory_order_relaxed); - session->input_policy.allow_gamepad.store(effective_gamepad, std::memory_order_relaxed); - - if (session->input) { - input::set_policy(session->input, effective_keyboard, effective_mouse, effective_gamepad); - } - - BOOST_LOG(debug) - << "Session input policy updated [reason="sv << (int) reason << "] kb="sv << effective_keyboard - << " mouse="sv << effective_mouse << " gamepad="sv << effective_gamepad; - } - - static int send_session_input_policy(session_t *session, uint8_t reason) { - if (!session->control.peer) { - return -1; - } - - struct control_set_input_policy_msg_t { - control_header_v2 header; - control_set_input_policy_t payload; - } plaintext; - - plaintext.header.type = packetTypes[IDX_SET_INPUT_POLICY]; - plaintext.header.payloadLength = sizeof(plaintext) - sizeof(control_header_v2); - plaintext.payload.allow_keyboard = session->input_policy.allow_keyboard.load(std::memory_order_relaxed) ? 1 : 0; - plaintext.payload.allow_mouse = session->input_policy.allow_mouse.load(std::memory_order_relaxed) ? 1 : 0; - plaintext.payload.allow_gamepad = session->input_policy.allow_gamepad.load(std::memory_order_relaxed) ? 1 : 0; - plaintext.payload.reason = reason; - - std::array - encrypted_payload; - - auto payload = encode_control(session, util::view(plaintext), encrypted_payload); - if (session->broadcast_ref->control_server.send(payload, session->control.peer)) { - return -1; - } - - return 0; - } - /** * First part of cipher must be struct of type control_encrypted_t * @@ -1029,10 +930,6 @@ namespace stream { server->map(packetTypes[IDX_START_B], [&](session_t *session, const std::string_view &payload) { BOOST_LOG(debug) << "type [IDX_START_B]"sv; - - if (send_session_input_policy(session, INPUT_POLICY_REASON_STREAM_START)) { - BOOST_LOG(warning) << "Unable to send initial session input policy"sv; - } }); server->map(packetTypes[IDX_LOSS_STATS], [&](session_t *session, const std::string_view &payload) { @@ -1162,34 +1059,6 @@ namespace stream { } }); - server->map(packetTypes[IDX_SET_INPUT_POLICY], [](session_t *session, const std::string_view &payload) { - BOOST_LOG(debug) << "type [IDX_SET_INPUT_POLICY]"sv; - - if (payload.size() < sizeof(control_set_input_policy_t)) { - BOOST_LOG(warning) << "Dropping runt input policy payload"sv; - return; - } - - auto *policy = (const control_set_input_policy_t *) payload.data(); - bool is_owner_session = session->input_policy.is_owner_session.load(std::memory_order_relaxed); - if (!is_owner_session) { - BOOST_LOG(info) - << "Ignoring client input policy update from non-owner session [id="sv << session->launch_session_id - << ", client="sv << session->client_unique_id << "]"sv; - } else { - apply_session_input_policy( - session, - policy->allow_keyboard != 0, - policy->allow_mouse != 0, - policy->allow_gamepad != 0, - policy->reason); - } - - if (send_session_input_policy(session, INPUT_POLICY_REASON_HOST_ACK)) { - BOOST_LOG(warning) << "Unable to send input policy acknowledgment"sv; - } - }); - // This thread handles latency-sensitive control messages platf::set_thread_name("stream::controlBroadcast"); platf::adjust_thread_priority(platf::thread_priority_e::critical); @@ -1918,13 +1787,13 @@ namespace stream { audio_packets.reset(); BOOST_LOG(debug) << "Waiting for main listening thread to end..."sv; - if (ctx.recv_thread.joinable()) ctx.recv_thread.join(); + ctx.recv_thread.join(); BOOST_LOG(debug) << "Waiting for main video thread to end..."sv; - if (ctx.video_thread.joinable()) ctx.video_thread.join(); + ctx.video_thread.join(); BOOST_LOG(debug) << "Waiting for main audio thread to end..."sv; - if (ctx.audio_thread.joinable()) ctx.audio_thread.join(); + ctx.audio_thread.join(); BOOST_LOG(debug) << "Waiting for main control thread to end..."sv; - if (ctx.control_thread.joinable()) ctx.control_thread.join(); + ctx.control_thread.join(); BOOST_LOG(debug) << "All broadcasting threads ended"sv; broadcast_shutdown_event->reset(); @@ -2027,114 +1896,6 @@ namespace stream { audio::capture(session->mail, session->config.audio, session); } - namespace session { - extern std::atomic_uint running_sessions; - } - - nlohmann::json get_active_sessions_info() { - auto result = nlohmann::json::array(); - - if (session::running_sessions.load(std::memory_order_relaxed) == 0) { - return result; - } - - auto ref = broadcast.ref(); - if (!ref) { - return result; - } - - auto now = now_monotonic_ms(); - - auto lg = ref->control_server._sessions.lock(); - for (auto *session : *ref->control_server._sessions) { - if (session->state.load(std::memory_order_relaxed) != session::state_e::RUNNING) { - continue; - } - - auto last_kb = session->input_activity.last_keyboard_ms.load(std::memory_order_relaxed); - auto last_mouse = session->input_activity.last_mouse_ms.load(std::memory_order_relaxed); - auto last_gp = session->input_activity.last_gamepad_ms.load(std::memory_order_relaxed); - - nlohmann::json entry; - entry["session_id"] = session->launch_session_id; - entry["client_uuid"] = session->client_unique_id; - entry["client_name"] = session->client_name; - entry["is_owner_session"] = session->input_policy.is_owner_session.load(std::memory_order_relaxed); - - entry["policy"] = { - {"allow_keyboard", session->input_policy.allow_keyboard.load(std::memory_order_relaxed)}, - {"allow_mouse", session->input_policy.allow_mouse.load(std::memory_order_relaxed)}, - {"allow_gamepad", session->input_policy.allow_gamepad.load(std::memory_order_relaxed)}, - }; - - auto kb_ago = last_kb > 0 ? now - last_kb : UINT64_MAX; - auto mouse_ago = last_mouse > 0 ? now - last_mouse : UINT64_MAX; - auto gp_ago = last_gp > 0 ? now - last_gp : UINT64_MAX; - - entry["activity"] = { - {"keyboard_active", kb_ago <= KB_ACTIVE_WINDOW_MS}, - {"mouse_active", mouse_ago <= MOUSE_ACTIVE_WINDOW_MS}, - {"gamepad_active", gp_ago <= GAMEPAD_ACTIVE_WINDOW_MS}, - {"last_keyboard_ms_ago", last_kb > 0 ? (int64_t) kb_ago : (int64_t) -1}, - {"last_mouse_ms_ago", last_mouse > 0 ? (int64_t) mouse_ago : (int64_t) -1}, - {"last_gamepad_ms_ago", last_gp > 0 ? (int64_t) gp_ago : (int64_t) -1}, - }; - - result.push_back(std::move(entry)); - } - - return result; - } - - bool set_active_session_input_policy( - uint32_t session_id, - bool allow_keyboard, - bool allow_mouse, - bool allow_gamepad, - bool *effective_allow_keyboard, - bool *effective_allow_mouse, - bool *effective_allow_gamepad) { - auto ref = broadcast.ref(); - if (!ref) { - return false; - } - - auto lg = ref->control_server._sessions.lock(); - for (auto *session : *ref->control_server._sessions) { - if (session->launch_session_id != session_id || session->state.load(std::memory_order_relaxed) != session::state_e::RUNNING) { - continue; - } - - apply_session_input_policy(session, allow_keyboard, allow_mouse, allow_gamepad, INPUT_POLICY_REASON_HOST_OVERRIDE); - - if (send_session_input_policy(session, INPUT_POLICY_REASON_HOST_OVERRIDE)) { - BOOST_LOG(warning) << "Unable to send host policy override to client"sv; - } - - auto final_allow_keyboard = session->input_policy.allow_keyboard.load(std::memory_order_relaxed); - auto final_allow_mouse = session->input_policy.allow_mouse.load(std::memory_order_relaxed); - auto final_allow_gamepad = session->input_policy.allow_gamepad.load(std::memory_order_relaxed); - - if (effective_allow_keyboard) { - *effective_allow_keyboard = final_allow_keyboard; - } - if (effective_allow_mouse) { - *effective_allow_mouse = final_allow_mouse; - } - if (effective_allow_gamepad) { - *effective_allow_gamepad = final_allow_gamepad; - } - - BOOST_LOG(info) - << "Host input policy override applied [session="sv << session_id << "] kb="sv << final_allow_keyboard - << " mouse="sv << final_allow_mouse << " gamepad="sv << final_allow_gamepad; - - return true; - } - - return false; - } - namespace session { std::atomic_uint running_sessions; @@ -2203,19 +1964,6 @@ namespace stream { int start(session_t &session, const std::string &addr_string) { session.input = input::alloc(session.mail); - input::set_activity_pointers( - session.input, - &session.input_activity.last_keyboard_ms, - &session.input_activity.last_mouse_ms, - &session.input_activity.last_gamepad_ms); - - apply_session_input_policy( - &session, - session.input_policy.allow_keyboard.load(std::memory_order_relaxed), - session.input_policy.allow_mouse.load(std::memory_order_relaxed), - session.input_policy.allow_gamepad.load(std::memory_order_relaxed), - 0); - session.broadcast_ref = broadcast.ref(); if (!session.broadcast_ref) { return -1; @@ -2262,20 +2010,6 @@ namespace stream { session->shutdown_event = mail->event(mail::shutdown); session->launch_session_id = launch_session.id; - session->client_unique_id = launch_session.unique_id; - session->client_name = nvhttp::get_client_name(launch_session.unique_id); - - auto &owner_uuids = config::input.owner_client_uuids; - bool is_owner = std::find(owner_uuids.begin(), owner_uuids.end(), launch_session.unique_id) != owner_uuids.end(); - - session->input_policy.is_owner_session.store(is_owner, std::memory_order_relaxed); - session->input_policy.allow_gamepad.store(true, std::memory_order_relaxed); - session->input_policy.allow_keyboard.store(is_owner, std::memory_order_relaxed); - session->input_policy.allow_mouse.store(is_owner, std::memory_order_relaxed); - - if (is_owner) { - BOOST_LOG(info) << "Owner session detected for client: "sv << launch_session.unique_id; - } session->config = config; diff --git a/src/stream.h b/src/stream.h index ccbb0351..53afff4f 100644 --- a/src/stream.h +++ b/src/stream.h @@ -5,14 +5,10 @@ #pragma once // standard includes -#include -#include #include -#include // lib includes #include -#include // local includes #include "audio.h" @@ -24,23 +20,8 @@ namespace stream { constexpr auto CONTROL_PORT = 10; constexpr auto AUDIO_STREAM_PORT = 11; - constexpr uint64_t KB_ACTIVE_WINDOW_MS = 1500; - constexpr uint64_t MOUSE_ACTIVE_WINDOW_MS = 1500; - constexpr uint64_t GAMEPAD_ACTIVE_WINDOW_MS = 1500; - struct session_t; - nlohmann::json get_active_sessions_info(); - - bool set_active_session_input_policy( - uint32_t session_id, - bool allow_keyboard, - bool allow_mouse, - bool allow_gamepad, - bool *effective_allow_keyboard = nullptr, - bool *effective_allow_mouse = nullptr, - bool *effective_allow_gamepad = nullptr); - struct config_t { audio::config_t audio; video::config_t monitor; diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index fa7ca614..222fba0e 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -203,15 +203,14 @@ "touchpad_as_ds4": "enabled", "ds5_inputtino_randomize_mac": "enabled", "back_button_timeout": -1, - "keyboard": "disabled", + "keyboard": "enabled", "key_repeat_delay": 500, "key_repeat_frequency": 24.9, "always_send_scancodes": "enabled", "key_rightalt_to_key_win": "disabled", - "mouse": "disabled", + "mouse": "enabled", "high_resolution_scrolling": "enabled", "native_pen_touch": "enabled", - "owner_client_uuids": "", "keybindings": "[0x10,0xA0,0x11,0xA2,0x12,0xA4]", // todo: add this to UI }, }, diff --git a/src_assets/common/assets/web/configs/tabs/Inputs.vue b/src_assets/common/assets/web/configs/tabs/Inputs.vue index b7f188a5..7fa76a20 100644 --- a/src_assets/common/assets/web/configs/tabs/Inputs.vue +++ b/src_assets/common/assets/web/configs/tabs/Inputs.vue @@ -118,7 +118,7 @@ const config = ref(props.config) id="keyboard" locale-prefix="config" v-model="config.keyboard" - default="false" + default="true" > @@ -161,7 +161,7 @@ const config = ref(props.config) id="mouse" locale-prefix="config" v-model="config.mouse" - default="false" + default="true" > @@ -181,15 +181,6 @@ const config = ref(props.config) v-model="config.native_pen_touch" default="true" > - -
-
- - -
Comma-separated UUIDs of owner clients. Owner sessions start with keyboard/mouse enabled. Find UUIDs in the Troubleshooting page under paired clients.
-
diff --git a/src_assets/common/assets/web/public/assets/css/sunshine.css b/src_assets/common/assets/web/public/assets/css/sunshine.css index 2f705a4a..970f2e2e 100644 --- a/src_assets/common/assets/web/public/assets/css/sunshine.css +++ b/src_assets/common/assets/web/public/assets/css/sunshine.css @@ -1202,28 +1202,6 @@ p { margin: 0; } -.activity-dot { - display: inline-block; - width: 14px; - height: 14px; - border-radius: 50%; - transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s; - flex-shrink: 0; - vertical-align: middle; - margin-right: 3px; -} - -.dot-green { - background-color: #22c55e; - box-shadow: 0 0 6px #22c55e; - border: 1px solid #16a34a; -} - -.dot-gray { - background-color: #6b7280; - border: 1px solid #d1d5db; -} - /* Log level highlighting */ .log-line-info { color: var(--color-text-base); diff --git a/src_assets/common/assets/web/troubleshooting.html b/src_assets/common/assets/web/troubleshooting.html index 0df895f4..c33b3db2 100644 --- a/src_assets/common/assets/web/troubleshooting.html +++ b/src_assets/common/assets/web/troubleshooting.html @@ -135,21 +135,10 @@
  • -
    -
    {{ client.name !== "" ? client.name : $t('troubleshooting.unpair_single_unknown') }}
    -
    - {{ client.uuid }} -
    -
    -
    - - -
    +
    {{ client.name !== "" ? client.name : $t('troubleshooting.unpair_single_unknown') }}
    +
    @@ -158,84 +147,6 @@
- -
-
-

Live Input Status

-

Per-session input activity and policy. Use the checkboxes to override keyboard, mouse, and gamepad permissions for each active client.

-
-
- No active streaming sessions. -
-
    -
  • -
    -
    - {{ s.client_name || s.client_uuid || 'Unknown' }} - Owner -
    -
    - - - KB - - {{ s.policy.allow_keyboard ? 'ON' : 'OFF' }} - - - - - Mouse - - {{ s.policy.allow_mouse ? 'ON' : 'OFF' }} - - - - - Gamepad - - {{ s.policy.allow_gamepad ? 'ON' : 'OFF' }} - - -
    -
    -
    - Host override: - - - - Saving... - {{ sessionPolicyError[s.session_id] }} -
    -
  • -
-
@@ -318,7 +229,6 @@ }, data() { return { - activeSessions: [], clients: [], closeAppPressed: false, closeAppStatus: null, @@ -327,11 +237,6 @@ logs: 'Loading...', logFilter: null, logInterval: null, - sessionInterval: null, - sessionSocket: null, - sessionReconnectTimer: null, - sessionPolicyBusy: {}, - sessionPolicyError: {}, restartPressed: false, showApplyMessage: false, platform: "", @@ -484,140 +389,13 @@ this.logInterval = setInterval(() => { this.refreshLogs(); }, 5000); - this.sessionInterval = setInterval(() => { - this.refreshActiveSessions(); - }, 5000); this.refreshLogs(); this.refreshClients(); - this.refreshActiveSessions(); - this.connectActiveSessionsSocket(); }, beforeDestroy() { clearInterval(this.logInterval); - clearInterval(this.sessionInterval); - clearTimeout(this.sessionReconnectTimer); - if (this.sessionSocket) { - this.sessionSocket.onclose = null; - this.sessionSocket.close(); - this.sessionSocket = null; - } }, methods: { - isSessionPolicyBusy(sessionId) { - return this.sessionPolicyBusy[sessionId] === true; - }, - updateSessionPolicy(session, field, value) { - if (!session || !session.policy || session.session_id === undefined || session.session_id === null) { - return; - } - - if (!["allow_keyboard", "allow_mouse", "allow_gamepad"].includes(field)) { - return; - } - - const sessionId = session.session_id; - const nextPolicy = { - allow_keyboard: field === "allow_keyboard" ? value : !!session.policy.allow_keyboard, - allow_mouse: field === "allow_mouse" ? value : !!session.policy.allow_mouse, - allow_gamepad: field === "allow_gamepad" ? value : !!session.policy.allow_gamepad, - }; - - this.sessionPolicyBusy[sessionId] = true; - this.sessionPolicyError[sessionId] = ""; - - fetch("./api/sessions/policy", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify({ - session_id: sessionId, - allow_keyboard: nextPolicy.allow_keyboard, - allow_mouse: nextPolicy.allow_mouse, - allow_gamepad: nextPolicy.allow_gamepad, - }) - }) - .then((r) => r.json()) - .then((r) => { - if (!r || r.status !== true || !r.policy) { - throw new Error((r && r.error) ? r.error : "Failed to update session input policy"); - } - - session.policy.allow_keyboard = !!r.policy.allow_keyboard; - session.policy.allow_mouse = !!r.policy.allow_mouse; - session.policy.allow_gamepad = !!r.policy.allow_gamepad; - }) - .catch((e) => { - this.sessionPolicyError[sessionId] = (e && e.message) ? e.message : "Failed to update session input policy"; - this.refreshActiveSessions(); - }) - .finally(() => { - this.sessionPolicyBusy[sessionId] = false; - }); - }, - connectActiveSessionsSocket() { - fetch("./api/sessions/ws-token") - .then((r) => r.json()) - .then((r) => { - if (!r || r.status !== true || !r.token) { - throw new Error("No websocket token"); - } - - const protocol = window.location.protocol === "https:" ? "wss" : "ws"; - const wsUrl = `${protocol}://${window.location.host}/api/sessions/active/ws?token=${encodeURIComponent(r.token)}`; - - this.sessionSocket = new WebSocket(wsUrl); - - this.sessionSocket.onmessage = (event) => { - try { - const payload = JSON.parse(event.data); - if (payload && payload.status === true && payload.sessions) { - this.activeSessions = payload.sessions; - } - } catch (_e) { - return; - } - }; - - this.sessionSocket.onclose = () => { - this.sessionSocket = null; - clearTimeout(this.sessionReconnectTimer); - this.sessionReconnectTimer = setTimeout(() => { - this.connectActiveSessionsSocket(); - }, 1000); - }; - - this.sessionSocket.onerror = () => { - if (this.sessionSocket) { - this.sessionSocket.close(); - } - }; - }) - .catch(() => { - clearTimeout(this.sessionReconnectTimer); - this.sessionReconnectTimer = setTimeout(() => { - this.connectActiveSessionsSocket(); - }, 1000); - }); - }, - refreshActiveSessions() { - if (this.sessionSocket && this.sessionSocket.readyState === WebSocket.OPEN) { - return; - } - - fetch("./api/sessions/active") - .then((r) => r.json()) - .then((r) => { - if (r.status === true && r.sessions) { - this.activeSessions = r.sessions; - } else { - this.activeSessions = []; - } - }) - .catch(() => { - this.activeSessions = []; - }); - }, refreshLogs() { fetch("./api/logs",) .then((r) => r.text()) @@ -688,15 +466,6 @@ clickedApplyBanner() { this.showApplyMessage = false; }, - copyClientUuid(uuid) { - if (!uuid) { - return; - } - - navigator.clipboard.writeText(uuid).catch(() => { - window.prompt("Copy client UUID", uuid); - }); - }, copyLogs() { // Copy the filtered view if a filter is active. navigator.clipboard.writeText(this.actualLogs); diff --git a/third-party/Simple-Web-Server b/third-party/Simple-Web-Server index 99c1f621..546895a9 160000 --- a/third-party/Simple-Web-Server +++ b/third-party/Simple-Web-Server @@ -1 +1 @@ -Subproject commit 99c1f621ebd8d119c5d2dc3a88ecf255058acec0 +Subproject commit 546895a93a29062bb178367b46c7afb72da9881e