vnc/
lib.rs

1//! # VNC-RS
2//!
3//! ## Description
4//! + An async implementation of VNC client side protocol
5//!
6//! ## Simple example
7//!
8//! ```no_run
9//! use anyhow::{Context, Result};
10//! use minifb::{Window, WindowOptions};
11//! use tokio::{self, net::TcpStream};
12//! use tracing::Level;
13//! use vnc::{PixelFormat, Rect, VncConnector, VncEvent, X11Event};
14//!
15//! #[tokio::main]
16//! async fn main() -> Result<()> {
17//!     // Create tracing subscriber
18//!     #[cfg(debug_assertions)]
19//!     let subscriber = tracing_subscriber::FmtSubscriber::builder()
20//!         .with_max_level(Level::TRACE)
21//!         .finish();
22//!     #[cfg(not(debug_assertions))]
23//!     let subscriber = tracing_subscriber::FmtSubscriber::builder()
24//!         .with_max_level(Level::INFO)
25//!         .finish();
26//!
27//!     tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
28//!
29//!     let tcp = TcpStream::connect("127.0.0.1:5900").await?;
30//!     let vnc = VncConnector::new(tcp)
31//!         .set_auth_method(async move { Ok("123".to_string()) })
32//!         .add_encoding(vnc::VncEncoding::Tight)
33//!         .add_encoding(vnc::VncEncoding::Zrle)
34//!         .add_encoding(vnc::VncEncoding::CopyRect)
35//!         .add_encoding(vnc::VncEncoding::Raw)
36//!         .allow_shared(true)
37//!         .set_pixel_format(PixelFormat::bgra())
38//!         .build()?
39//!         .try_start()
40//!         .await?
41//!         .finish()?;
42//!
43//!     let mut canvas = CanvasUtils::new()?;
44//!
45//!     let mut now = std::time::Instant::now();
46//!     loop {
47//!         match vnc.poll_event().await {
48//!             Ok(Some(e)) => {
49//!                 let _ = canvas.hande_vnc_event(e);
50//!             }
51//!             Ok(None) => (),
52//!             Err(e) => {
53//!                 tracing::error!("{}", e.to_string());
54//!                 break;
55//!             }
56//!         }
57//!         if now.elapsed().as_millis() > 16 {
58//!             let _ = canvas.flush();
59//!             let _ = vnc.input(X11Event::Refresh).await;
60//!             now = std::time::Instant::now();
61//!         }
62//!     }
63//!     canvas.close();
64//!     let _ = vnc.close().await;
65//!     Ok(())
66//! }
67//!
68//! struct CanvasUtils {
69//!     window: Window,
70//!     video: Vec<u32>,
71//!     width: u32,
72//!     height: u32,
73//! }
74//!
75//! impl CanvasUtils {
76//!     fn new() -> Result<Self> {
77//!         Ok(Self {
78//!             window: Window::new(
79//!                 "mstsc-rs Remote Desktop in Rust",
80//!                 800_usize,
81//!                 600_usize,
82//!                 WindowOptions::default(),
83//!             )
84//!             .with_context(|| "Unable to create window".to_string())?,
85//!             video: vec![],
86//!             width: 800,
87//!             height: 600,
88//!         })
89//!     }
90//!
91//!     fn init(&mut self, width: u32, height: u32) -> Result<()> {
92//!         let mut window = Window::new(
93//!             "mstsc-rs Remote Desktop in Rust",
94//!             width as usize,
95//!             height as usize,
96//!             WindowOptions::default(),
97//!         )
98//!         .with_context(|| "Unable to create window")?;
99//!         window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
100//!         self.window = window;
101//!         self.width = width;
102//!         self.height = height;
103//!         self.video.resize(height as usize * width as usize, 0);
104//!         Ok(())
105//!     }
106//!
107//!     fn draw(&mut self, rect: Rect, data: Vec<u8>) -> Result<()> {
108//!         // since we set the PixelFormat as bgra
109//!         // the pixels must be sent in [blue, green, red, alpha] in the network order
110//!
111//!         let mut s_idx = 0;
112//!         for y in rect.y..rect.y + rect.height {
113//!             let mut d_idx = y as usize * self.width as usize + rect.x as usize;
114//!
115//!             for _ in rect.x..rect.x + rect.width {
116//!                 self.video[d_idx] =
117//!                     u32::from_le_bytes(data[s_idx..s_idx + 4].try_into().unwrap()) & 0x00_ff_ff_ff;
118//!                 s_idx += 4;
119//!                 d_idx += 1;
120//!             }
121//!         }
122//!         Ok(())
123//!     }
124//!
125//!     fn flush(&mut self) -> Result<()> {
126//!         self.window
127//!             .update_with_buffer(&self.video, self.width as usize, self.height as usize)
128//!             .with_context(|| "Unable to update screen buffer")?;
129//!         Ok(())
130//!     }
131//!
132//!     fn copy(&mut self, dst: Rect, src: Rect) -> Result<()> {
133//!         println!("Copy");
134//!         let mut tmp = vec![0; src.width as usize * src.height as usize];
135//!         let mut tmp_idx = 0;
136//!         for y in 0..src.height as usize {
137//!             let mut s_idx = (src.y as usize + y) * self.width as usize + src.x as usize;
138//!             for _ in 0..src.width {
139//!                 tmp[tmp_idx] = self.video[s_idx];
140//!                 tmp_idx += 1;
141//!                 s_idx += 1;
142//!             }
143//!         }
144//!         tmp_idx = 0;
145//!         for y in 0..src.height as usize {
146//!             let mut d_idx = (dst.y as usize + y) * self.width as usize + dst.x as usize;
147//!             for _ in 0..src.width {
148//!                 self.video[d_idx] = tmp[tmp_idx];
149//!                 tmp_idx += 1;
150//!                 d_idx += 1;
151//!             }
152//!         }
153//!         Ok(())
154//!     }
155//!
156//!     fn close(&self) {}
157//!
158//!     fn hande_vnc_event(&mut self, event: VncEvent) -> Result<()> {
159//!         match event {
160//!             VncEvent::SetResolution(screen) => {
161//!                 tracing::info!("Resize {:?}", screen);
162//!                 self.init(screen.width as u32, screen.height as u32)?
163//!             }
164//!             VncEvent::RawImage(rect, data) => {
165//!                 self.draw(rect, data)?;
166//!             }
167//!             VncEvent::Bell => {
168//!                 tracing::warn!("Bell event got, but ignore it");
169//!             }
170//!             VncEvent::SetPixelFormat(_) => unreachable!(),
171//!             VncEvent::Copy(dst, src) => {
172//!                 self.copy(dst, src)?;
173//!             }
174//!             VncEvent::JpegImage(_rect, _data) => {
175//!                 tracing::warn!("Jpeg event got, but ignore it");
176//!             }
177//!             VncEvent::SetCursor(rect, data) => {
178//!                 if rect.width != 0 {
179//!                     self.draw(rect, data)?;
180//!                 }
181//!             }
182//!             VncEvent::Text(string) => {
183//!                 tracing::info!("Got clipboard message {}", string);
184//!             }
185//!             _ => unreachable!(),
186//!         }
187//!         Ok(())
188//!     }
189//! }
190//!
191//! ```
192//!
193//! ## License
194//!
195//! Licensed under either of
196//!
197//!  * Apache License, Version 2.0
198//!    ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
199//!  * MIT license
200//!    ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
201//!
202//! at your option.
203//!
204//! ## Contribution
205//!
206//! Unless you explicitly state otherwise, any contribution intentionally submitted
207//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
208//! dual licensed as above, without any additional terms or conditions.
209
210pub mod client;
211mod codec;
212pub mod config;
213pub mod error;
214pub mod event;
215
216pub use client::VncClient;
217pub use client::VncConnector;
218pub use config::*;
219pub use error::*;
220pub use event::*;