add comment

This commit is contained in:
SoLongAndThanksForAllThePizza
2022-05-28 03:56:42 +08:00
parent 7eb3a43f33
commit 9dd6e40003
7 changed files with 363 additions and 10 deletions

View File

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