mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-13 23:21:27 +03:00
add comment
This commit is contained in:
187
src/client.rs
187
src/client.rs
@@ -39,6 +39,7 @@ pub mod helper;
|
||||
pub use helper::LatencyController;
|
||||
pub const SEC30: Duration = Duration::from_secs(30);
|
||||
|
||||
/// Client of the remote desktop.
|
||||
pub struct Client;
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
@@ -106,6 +107,7 @@ impl Drop for OboePlayer {
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Start a new connection.
|
||||
pub async fn start(
|
||||
peer: &str,
|
||||
key: &str,
|
||||
@@ -125,6 +127,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a new connection.
|
||||
async fn _start(
|
||||
peer: &str,
|
||||
key: &str,
|
||||
@@ -259,6 +262,7 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Connect to the peer.
|
||||
async fn connect(
|
||||
local_addr: SocketAddr,
|
||||
peer: SocketAddr,
|
||||
@@ -345,6 +349,7 @@ impl Client {
|
||||
Ok((conn, direct))
|
||||
}
|
||||
|
||||
/// Establish secure connection with the server.
|
||||
async fn secure_connection(
|
||||
peer_id: &str,
|
||||
signed_id_pk: Vec<u8>,
|
||||
@@ -422,6 +427,7 @@ impl Client {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Request a relay connection to the server.
|
||||
async fn request_relay(
|
||||
peer: &str,
|
||||
relay_server: String,
|
||||
@@ -478,6 +484,7 @@ impl Client {
|
||||
Self::create_relay(peer, uuid, relay_server, key, conn_type).await
|
||||
}
|
||||
|
||||
/// Create a relay connection to the server.
|
||||
async fn create_relay(
|
||||
peer: &str,
|
||||
uuid: String,
|
||||
@@ -505,6 +512,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
/// Audio handler for the [`Client`].
|
||||
#[derive(Default)]
|
||||
pub struct AudioHandler {
|
||||
audio_decoder: Option<(AudioDecoder, Vec<f32>)>,
|
||||
@@ -522,6 +530,7 @@ pub struct AudioHandler {
|
||||
}
|
||||
|
||||
impl AudioHandler {
|
||||
/// Create a new audio handler.
|
||||
pub fn new(latency_controller: Arc<Mutex<LatencyController>>) -> Self {
|
||||
AudioHandler {
|
||||
latency_controller,
|
||||
@@ -529,6 +538,7 @@ impl AudioHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the audio playback.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
||||
use psimple::Simple;
|
||||
@@ -558,6 +568,7 @@ impl AudioHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start the audio playback.
|
||||
#[cfg(target_os = "android")]
|
||||
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
||||
self.oboe = Some(OboePlayer::new(
|
||||
@@ -568,6 +579,7 @@ impl AudioHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start the audio playback.
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
fn start_audio(&mut self, format0: AudioFormat) -> ResultType<()> {
|
||||
let device = AUDIO_HOST
|
||||
@@ -592,6 +604,7 @@ impl AudioHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle audio format and create an audio decoder.
|
||||
pub fn handle_format(&mut self, f: AudioFormat) {
|
||||
match AudioDecoder::new(f.sample_rate, if f.channels > 1 { Stereo } else { Mono }) {
|
||||
Ok(d) => {
|
||||
@@ -606,6 +619,7 @@ impl AudioHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle audio frame and play it.
|
||||
pub fn handle_frame(&mut self, frame: AudioFrame) {
|
||||
if frame.timestamp != 0 {
|
||||
if self
|
||||
@@ -673,6 +687,7 @@ impl AudioHandler {
|
||||
});
|
||||
}
|
||||
|
||||
/// Build audio output stream for current device.
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
fn build_output_stream<T: cpal::Sample>(
|
||||
&mut self,
|
||||
@@ -708,6 +723,7 @@ impl AudioHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Video handler for the [`Client`].
|
||||
pub struct VideoHandler {
|
||||
decoder: Decoder,
|
||||
latency_controller: Arc<Mutex<LatencyController>>,
|
||||
@@ -715,6 +731,7 @@ pub struct VideoHandler {
|
||||
}
|
||||
|
||||
impl VideoHandler {
|
||||
/// Create a new video handler.
|
||||
pub fn new(latency_controller: Arc<Mutex<LatencyController>>) -> Self {
|
||||
VideoHandler {
|
||||
decoder: Decoder::new(VideoCodecId::VP9, (num_cpus::get() / 2) as _).unwrap(),
|
||||
@@ -723,8 +740,10 @@ impl VideoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle a new video frame.
|
||||
pub fn handle_frame(&mut self, vf: VideoFrame) -> ResultType<bool> {
|
||||
if vf.timestamp != 0 {
|
||||
// Update the lantency controller with the latest timestamp.
|
||||
self.latency_controller
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -736,6 +755,7 @@ impl VideoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle a VP9S frame.
|
||||
pub fn handle_vp9s(&mut self, vp9s: &VP9s) -> ResultType<bool> {
|
||||
let mut last_frame = Image::new();
|
||||
for vp9 in vp9s.frames.iter() {
|
||||
@@ -756,11 +776,13 @@ impl VideoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the decoder.
|
||||
pub fn reset(&mut self) {
|
||||
self.decoder = Decoder::new(VideoCodecId::VP9, 1).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Login config handler for [`Client`].
|
||||
#[derive(Default)]
|
||||
pub struct LoginConfigHandler {
|
||||
id: String,
|
||||
@@ -783,12 +805,24 @@ impl Deref for LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Load [`PeerConfig`] from id.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - id of peer
|
||||
#[inline]
|
||||
pub fn load_config(id: &str) -> PeerConfig {
|
||||
PeerConfig::load(id)
|
||||
}
|
||||
|
||||
impl LoginConfigHandler {
|
||||
/// Initialize the login config handler.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - id of peer
|
||||
/// * `is_file_transfer` - Whether the connection is file transfer.
|
||||
/// * `is_port_forward` - Whether the connection is port forward.
|
||||
pub fn initialize(&mut self, id: String, is_file_transfer: bool, is_port_forward: bool) {
|
||||
self.id = id;
|
||||
self.is_file_transfer = is_file_transfer;
|
||||
@@ -798,6 +832,8 @@ impl LoginConfigHandler {
|
||||
self.config = config;
|
||||
}
|
||||
|
||||
/// Check if the client should auto login.
|
||||
/// Return password if the client should auto login, otherwise return empty string.
|
||||
pub fn should_auto_login(&self) -> String {
|
||||
let l = self.lock_after_session_end;
|
||||
let a = !self.get_option("auto-login").is_empty();
|
||||
@@ -809,27 +845,49 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Load [`PeerConfig`].
|
||||
fn load_config(&self) -> PeerConfig {
|
||||
load_config(&self.id)
|
||||
}
|
||||
|
||||
/// Save a [`PeerConfig`] into the handler.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `config` - [`PeerConfig`] to save.
|
||||
pub fn save_config(&mut self, config: PeerConfig) {
|
||||
config.store(&self.id);
|
||||
self.config = config;
|
||||
}
|
||||
|
||||
/// Set an option for handler's [`PeerConfig`].
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `k` - key of option
|
||||
/// * `v` - value of option
|
||||
pub fn set_option(&mut self, k: String, v: String) {
|
||||
let mut config = self.load_config();
|
||||
config.options.insert(k, v);
|
||||
self.save_config(config);
|
||||
}
|
||||
|
||||
/// Save view style to the current config.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value` - The view style to be saved.
|
||||
pub fn save_view_style(&mut self, value: String) {
|
||||
let mut config = self.load_config();
|
||||
config.view_style = value;
|
||||
self.save_config(config);
|
||||
}
|
||||
|
||||
/// Toggle an option in the handler.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name of the option to toggle.
|
||||
pub fn toggle_option(&mut self, name: String) -> Option<Message> {
|
||||
let mut option = OptionMessage::default();
|
||||
let mut config = self.load_config();
|
||||
@@ -905,6 +963,12 @@ impl LoginConfigHandler {
|
||||
Some(msg_out)
|
||||
}
|
||||
|
||||
/// Get [`OptionMessage`] of the current [`LoginConfigHandler`].
|
||||
/// Return `None` if there's no option, for example, when the session is only for file transfer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ignore_default` - If `true`, ignore the default value of the option.
|
||||
fn get_option_message(&self, ignore_default: bool) -> Option<OptionMessage> {
|
||||
if self.is_port_forward || self.is_file_transfer {
|
||||
return None;
|
||||
@@ -958,6 +1022,13 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the image quality option.
|
||||
/// Return [`ImageQuality`] if the option is valid, otherwise return `None`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `q` - The image quality option.
|
||||
/// * `ignore_default` - Ignore the default value.
|
||||
fn get_image_quality_enum(&self, q: &str, ignore_default: bool) -> Option<ImageQuality> {
|
||||
if q == "low" {
|
||||
Some(ImageQuality::Low)
|
||||
@@ -974,6 +1045,11 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the status of a toggle option.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name of the toggle option.
|
||||
pub fn get_toggle_option(&self, name: &str) -> bool {
|
||||
if name == "show-remote-cursor" {
|
||||
self.config.show_remote_cursor
|
||||
@@ -992,6 +1068,7 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [`Message`] for refreshing video.
|
||||
pub fn refresh() -> Message {
|
||||
let mut misc = Misc::new();
|
||||
misc.set_refresh_video(true);
|
||||
@@ -1000,6 +1077,12 @@ impl LoginConfigHandler {
|
||||
msg_out
|
||||
}
|
||||
|
||||
/// Create a [`Message`] for saving custom image quality.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `bitrate` - The given bitrate.
|
||||
/// * `quantizer` - The given quantizer.
|
||||
pub fn save_custom_image_quality(&mut self, bitrate: i32, quantizer: i32) -> Message {
|
||||
let mut misc = Misc::new();
|
||||
misc.set_option(OptionMessage {
|
||||
@@ -1015,6 +1098,11 @@ impl LoginConfigHandler {
|
||||
msg_out
|
||||
}
|
||||
|
||||
/// Save the given image quality to the config.
|
||||
/// Return a [`Message`] that contains image quality, or `None` if the image quality is not valid.
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value` - The image quality.
|
||||
pub fn save_image_quality(&mut self, value: String) -> Option<Message> {
|
||||
let mut res = None;
|
||||
if let Some(q) = self.get_image_quality_enum(&value, false) {
|
||||
@@ -1041,6 +1129,8 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle login error.
|
||||
/// Return true if the password is wrong, return false if there's an actual error.
|
||||
pub fn handle_login_error(&mut self, err: &str, interface: &impl Interface) -> bool {
|
||||
if err == "Wrong Password" {
|
||||
self.password = Default::default();
|
||||
@@ -1052,6 +1142,12 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get user name.
|
||||
/// Return the name of the given peer. If the peer has no name, return the name in the config.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pi` - peer info.
|
||||
pub fn get_username(&self, pi: &PeerInfo) -> String {
|
||||
return if pi.username.is_empty() {
|
||||
self.info.username.clone()
|
||||
@@ -1060,6 +1156,12 @@ impl LoginConfigHandler {
|
||||
};
|
||||
}
|
||||
|
||||
/// Handle peer info.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `username` - The name of the peer.
|
||||
/// * `pi` - The peer info.
|
||||
pub fn handle_peer_info(&mut self, username: String, pi: PeerInfo) {
|
||||
if !pi.version.is_empty() {
|
||||
self.version = hbb_common::get_version_number(&pi.version);
|
||||
@@ -1109,6 +1211,7 @@ impl LoginConfigHandler {
|
||||
serde_json::to_string::<HashMap<String, String>>(&x).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Create a [`Message`] for login.
|
||||
fn create_login_msg(&self, password: Vec<u8>) -> Message {
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let my_id = Config::get_id_or(crate::common::MOBILE_INFO1.lock().unwrap().clone());
|
||||
@@ -1141,6 +1244,7 @@ impl LoginConfigHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Media data.
|
||||
pub enum MediaData {
|
||||
VideoFrame(VideoFrame),
|
||||
AudioFrame(AudioFrame),
|
||||
@@ -1150,6 +1254,12 @@ pub enum MediaData {
|
||||
|
||||
pub type MediaSender = mpsc::Sender<MediaData>;
|
||||
|
||||
/// Start video and audio thread.
|
||||
/// Return two [`MediaSender`], they should be given to the media producer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `video_callback` - The callback for video frame. Being called when a video frame is ready.
|
||||
pub fn start_video_audio_threads<F>(video_callback: F) -> (MediaSender, MediaSender)
|
||||
where
|
||||
F: 'static + FnMut(&[u8]) + Send,
|
||||
@@ -1204,6 +1314,12 @@ where
|
||||
return (video_sender, audio_sender);
|
||||
}
|
||||
|
||||
/// Handle latency test.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `t` - The latency test message.
|
||||
/// * `peer` - The peer.
|
||||
pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) {
|
||||
if !t.from_client {
|
||||
let mut msg_out = Message::new();
|
||||
@@ -1212,9 +1328,21 @@ pub async fn handle_test_delay(t: TestDelay, peer: &mut Stream) {
|
||||
}
|
||||
}
|
||||
|
||||
// mask = buttons << 3 | type
|
||||
// type, 1: down, 2: up, 3: wheel
|
||||
// buttons, 1: left, 2: right, 4: middle
|
||||
/// Send mouse data.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `mask` - Mouse event.
|
||||
/// * mask = buttons << 3 | type
|
||||
/// * type, 1: down, 2: up, 3: wheel
|
||||
/// * buttons, 1: left, 2: right, 4: middle
|
||||
/// * `x` - X coordinate.
|
||||
/// * `y` - Y coordinate.
|
||||
/// * `alt` - Whether the alt key is pressed.
|
||||
/// * `ctrl` - Whether the ctrl key is pressed.
|
||||
/// * `shift` - Whether the shift key is pressed.
|
||||
/// * `command` - Whether the command key is pressed.
|
||||
/// * `interface` - The interface for sending data.
|
||||
#[inline]
|
||||
pub fn send_mouse(
|
||||
mask: i32,
|
||||
@@ -1249,6 +1377,11 @@ pub fn send_mouse(
|
||||
interface.send(Data::Message(msg_out));
|
||||
}
|
||||
|
||||
/// Avtivate OS by sending mouse movement.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `interface` - The interface for sending data.
|
||||
fn activate_os(interface: &impl Interface) {
|
||||
send_mouse(0, 0, 0, false, false, false, false, interface);
|
||||
std::thread::sleep(Duration::from_millis(50));
|
||||
@@ -1267,12 +1400,26 @@ fn activate_os(interface: &impl Interface) {
|
||||
*/
|
||||
}
|
||||
|
||||
/// Input the OS's password.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `p` - The password.
|
||||
/// * `avtivate` - Whether to activate OS.
|
||||
/// * `interface` - The interface for sending data.
|
||||
pub fn input_os_password(p: String, activate: bool, interface: impl Interface) {
|
||||
std::thread::spawn(move || {
|
||||
_input_os_password(p, activate, interface);
|
||||
});
|
||||
}
|
||||
|
||||
/// Input the OS's password.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `p` - The password.
|
||||
/// * `avtivate` - Whether to activate OS.
|
||||
/// * `interface` - The interface for sending data.
|
||||
fn _input_os_password(p: String, activate: bool, interface: impl Interface) {
|
||||
if activate {
|
||||
activate_os(&interface);
|
||||
@@ -1289,6 +1436,15 @@ fn _input_os_password(p: String, activate: bool, interface: impl Interface) {
|
||||
interface.send(Data::Message(msg_out));
|
||||
}
|
||||
|
||||
/// Handle hash message sent by peer.
|
||||
/// Hash will be used for login.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `lc` - Login config.
|
||||
/// * `hash` - Hash sent by peer.
|
||||
/// * `interface` - [`Interface`] for sending data.
|
||||
/// * `peer` - [`Stream`] for communicating with peer.
|
||||
pub async fn handle_hash(
|
||||
lc: Arc<RwLock<LoginConfigHandler>>,
|
||||
hash: Hash,
|
||||
@@ -1312,11 +1468,26 @@ pub async fn handle_hash(
|
||||
lc.write().unwrap().hash = hash;
|
||||
}
|
||||
|
||||
/// Send login message to peer.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `lc` - Login config.
|
||||
/// * `password` - Password.
|
||||
/// * `peer` - [`Stream`] for communicating with peer.
|
||||
async fn send_login(lc: Arc<RwLock<LoginConfigHandler>>, password: Vec<u8>, peer: &mut Stream) {
|
||||
let msg_out = lc.read().unwrap().create_login_msg(password);
|
||||
allow_err!(peer.send(&msg_out).await);
|
||||
}
|
||||
|
||||
/// Handle login request made from ui.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `lc` - Login config.
|
||||
/// * `password` - Password.
|
||||
/// * `remember` - Whether to remember password.
|
||||
/// * `peer` - [`Stream`] for communicating with peer.
|
||||
pub async fn handle_login_from_ui(
|
||||
lc: Arc<RwLock<LoginConfigHandler>>,
|
||||
password: String,
|
||||
@@ -1335,6 +1506,7 @@ pub async fn handle_login_from_ui(
|
||||
send_login(lc.clone(), hasher2.finalize()[..].into(), peer).await;
|
||||
}
|
||||
|
||||
/// Interface for client to send data and commands.
|
||||
#[async_trait]
|
||||
pub trait Interface: Send + Clone + 'static + Sized {
|
||||
fn send(&self, data: Data);
|
||||
@@ -1346,6 +1518,7 @@ pub trait Interface: Send + Clone + 'static + Sized {
|
||||
async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream);
|
||||
}
|
||||
|
||||
/// Data used by the client interface.
|
||||
#[derive(Clone)]
|
||||
pub enum Data {
|
||||
Close,
|
||||
@@ -1368,6 +1541,7 @@ pub enum Data {
|
||||
ResumeJob((i32, bool)),
|
||||
}
|
||||
|
||||
/// Keycode for key events.
|
||||
#[derive(Clone)]
|
||||
pub enum Key {
|
||||
ControlKey(ControlKey),
|
||||
@@ -1498,6 +1672,13 @@ lazy_static::lazy_static! {
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
/// Check if the given message is an error and can be retried.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `msgtype` - The message type.
|
||||
/// * `title` - The title of the message.
|
||||
/// * `text` - The text of the message.
|
||||
#[inline]
|
||||
pub fn check_if_retry(msgtype: &str, title: &str, text: &str) -> bool {
|
||||
msgtype == "error"
|
||||
|
||||
Reference in New Issue
Block a user