Rust RDP service: ironrdp client with full connection handshake (TCP -> TLS -> CredSSP -> NLA), pixel buffer frame delivery, mouse/keyboard input via scancode mapping, graceful disconnect. Runs in dedicated thread with own tokio runtime to avoid Send lifetime issues with ironrdp trait objects. Vue frontend: RdpView canvas renderer with 30fps polling, mouse/keyboard capture, RdpToolbar with Ctrl+Alt+Del and clipboard. SessionContainer handles both SSH and RDP tabs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95 lines
2.5 KiB
Rust
95 lines
2.5 KiB
Rust
//! Tauri commands for RDP session management.
|
|
//!
|
|
//! Mirrors the pattern used by `ssh_commands.rs` — thin command wrappers that
|
|
//! delegate to the `RdpService` via `State<AppState>`.
|
|
|
|
use serde::Deserialize;
|
|
use tauri::State;
|
|
|
|
use crate::rdp::{RdpConfig, RdpSessionInfo};
|
|
use crate::AppState;
|
|
|
|
/// Connect to an RDP server.
|
|
///
|
|
/// Performs the full connection handshake (TCP -> TLS -> CredSSP -> RDP) and
|
|
/// starts streaming frame updates in the background.
|
|
///
|
|
/// Returns the session UUID.
|
|
#[tauri::command]
|
|
pub fn connect_rdp(
|
|
config: RdpConfig,
|
|
state: State<'_, AppState>,
|
|
) -> Result<String, String> {
|
|
state.rdp.connect(config)
|
|
}
|
|
|
|
/// Get the current frame buffer as a base64-encoded RGBA string.
|
|
///
|
|
/// The frontend decodes this and draws it onto a `<canvas>` element.
|
|
/// Pixel format: RGBA, 4 bytes per pixel, row-major, top-left origin.
|
|
#[tauri::command]
|
|
pub async fn rdp_get_frame(
|
|
session_id: String,
|
|
state: State<'_, AppState>,
|
|
) -> Result<String, String> {
|
|
state.rdp.get_frame(&session_id).await
|
|
}
|
|
|
|
/// Send a mouse event to an RDP session.
|
|
///
|
|
/// `flags` uses MS-RDPBCGR mouse event flags:
|
|
/// - 0x0800 = move
|
|
/// - 0x1000 = left button
|
|
/// - 0x2000 = right button
|
|
/// - 0x4000 = middle button
|
|
/// - 0x8000 = button pressed (absence = released)
|
|
/// - 0x0200 = vertical wheel
|
|
/// - 0x0100 = negative wheel direction
|
|
/// - 0x0400 = horizontal wheel
|
|
#[tauri::command]
|
|
pub async fn rdp_send_mouse(
|
|
session_id: String,
|
|
x: u16,
|
|
y: u16,
|
|
flags: u32,
|
|
state: State<'_, AppState>,
|
|
) -> Result<(), String> {
|
|
state.rdp.send_mouse(&session_id, x, y, flags)
|
|
}
|
|
|
|
/// Send a keyboard event to an RDP session.
|
|
///
|
|
/// `scancode` is the RDP hardware scancode (from the scancode map in
|
|
/// `rdp::input`). For extended keys (e.g. arrows, numpad enter), the high
|
|
/// byte is 0xE0.
|
|
///
|
|
/// `pressed` is `true` for key-down, `false` for key-up.
|
|
#[tauri::command]
|
|
pub async fn rdp_send_key(
|
|
session_id: String,
|
|
scancode: u16,
|
|
pressed: bool,
|
|
state: State<'_, AppState>,
|
|
) -> Result<(), String> {
|
|
state.rdp.send_key(&session_id, scancode, pressed)
|
|
}
|
|
|
|
/// Disconnect an RDP session.
|
|
///
|
|
/// Sends a graceful shutdown to the RDP server and removes the session.
|
|
#[tauri::command]
|
|
pub async fn disconnect_rdp(
|
|
session_id: String,
|
|
state: State<'_, AppState>,
|
|
) -> Result<(), String> {
|
|
state.rdp.disconnect(&session_id)
|
|
}
|
|
|
|
/// List all active RDP sessions (metadata only).
|
|
#[tauri::command]
|
|
pub async fn list_rdp_sessions(
|
|
state: State<'_, AppState>,
|
|
) -> Result<Vec<RdpSessionInfo>, String> {
|
|
Ok(state.rdp.list_sessions())
|
|
}
|