server: Remove VNC support

Also adds references to libretro crates.
This commit is contained in:
Lily Tsuru 2024-10-10 04:30:23 -04:00
parent a4d791f1df
commit 9b696d3f8b
5 changed files with 149 additions and 574 deletions

325
server/Cargo.lock generated
View file

@ -17,12 +17,6 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -49,16 +43,6 @@ dependencies = [
"syn",
]
[[package]]
name = "async_io_stream"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
dependencies = [
"futures",
"rustc_version",
]
[[package]]
name = "autocfg"
version = "1.3.0"
@ -146,7 +130,7 @@ dependencies = [
"cc",
"cfg-if",
"libc",
"miniz_oxide 0.7.4",
"miniz_oxide",
"object",
"rustc-demangle",
]
@ -192,12 +176,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "byteorder"
version = "1.5.0"
@ -254,15 +232,6 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -304,6 +273,12 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "ffmpeg-next"
version = "7.0.0"
@ -327,16 +302,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "flate2"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
dependencies = [
"crc32fast",
"miniz_oxide 0.8.0",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -468,12 +433,38 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "gl"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404"
dependencies = [
"gl_generator",
]
[[package]]
name = "gl_generator"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
dependencies = [
"khronos_api",
"log",
"xml-rs",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]]
name = "heck"
version = "0.4.1"
@ -576,6 +567,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.12.1"
@ -592,13 +593,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.70"
name = "khronos_api"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "lazy_static"
@ -612,6 +610,14 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "letsplay_gpu"
version = "0.1.0"
dependencies = [
"gl",
"gl_generator",
]
[[package]]
name = "libc"
version = "0.2.158"
@ -628,6 +634,15 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "libretro-sys"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "207b060b02cecbcee6df3d0f5ed38691d5c4df1379dd1acd5c49c9b25d20b439"
dependencies = [
"libc",
]
[[package]]
name = "lock_api"
version = "0.4.12"
@ -677,15 +692,6 @@ dependencies = [
"adler",
]
[[package]]
name = "miniz_oxide"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.2"
@ -895,6 +901,27 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "retro_frontend"
version = "0.1.0"
dependencies = [
"cc",
"libc",
"libloading",
"libretro-sys",
"rgb565",
"serde",
"thiserror",
"toml",
"tracing",
]
[[package]]
name = "rgb565"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43e85498d0bb728f77a88b4313eaf4ed21673f3f8a05c36e835cf6c9c0d066"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -907,15 +934,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.17"
@ -934,12 +952,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
version = "1.0.209"
@ -982,6 +994,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -1132,17 +1153,6 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-stream"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.21.0"
@ -1156,17 +1166,37 @@ dependencies = [
]
[[package]]
name = "tokio-util"
version = "0.7.12"
name = "toml"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
"bytes",
"futures-core",
"futures-io",
"futures-sink",
"pin-project-lite",
"tokio",
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
@ -1304,22 +1334,6 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vnc-rs"
version = "0.5.1"
source = "git+https://github.com/computernewb/vnc-rs.git#f238a4e65b788403226d9c68da9b29a6fb942c1e"
dependencies = [
"async_io_stream",
"flate2",
"futures",
"thiserror",
"tokio",
"tokio-stream",
"tokio-util",
"tracing",
"wasm-bindgen-futures",
]
[[package]]
name = "vncstream_server"
version = "0.1.0"
@ -1330,11 +1344,12 @@ dependencies = [
"ffmpeg-next",
"futures",
"futures-util",
"letsplay_gpu",
"rand",
"retro_frontend",
"serde",
"serde_json",
"tokio",
"vnc-rs",
]
[[package]]
@ -1343,83 +1358,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "web-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -1493,6 +1431,21 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
dependencies = [
"memchr",
]
[[package]]
name = "xml-rs"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26"
[[package]]
name = "zerocopy"
version = "0.7.35"

View file

@ -7,8 +7,10 @@ edition = "2021"
anyhow = "1.0.86"
# vnc
vnc-rs = { git = "https://github.com/computernewb/vnc-rs.git" }
letsplay_gpu.path = "/home/lily/source/lets-play/crates/letsplay_gpu"
retro_frontend.path = "/home/lily/source/lets-play/crates/retro_frontend"
# async
tokio = { version = "1.39.3", features = ["full"] }
#ws

View file

@ -1,8 +1,6 @@
mod surface;
mod types;
mod video;
mod vnc_engine;
use video::ffmpeg;
use video::h264_encoder::H264Encoder;
@ -17,8 +15,6 @@ use tokio::sync::{
mpsc::{self, error::TryRecvError},
Mutex as TokioMutex,
};
use vnc_engine::VncMessageOutput;
use std::net::SocketAddr;
use axum::{
@ -35,9 +31,6 @@ use axum::{
use futures::{sink::SinkExt, stream::StreamExt};
struct AppState {
/// Channel for sending things to the VNC engine
/// should later be used for control
engine_tx: mpsc::Sender<vnc_engine::VncMessageInput>,
encoder_tx: Arc<TokioMutex<mpsc::Sender<()>>>,
websocket_broadcast_tx: broadcast::Sender<ws::Message>,
@ -46,12 +39,10 @@ struct AppState {
impl AppState {
fn new(
engine_tx: mpsc::Sender<vnc_engine::VncMessageInput>,
encoder_tx: mpsc::Sender<()>,
) -> Self {
let (chat_tx, _chat_rx) = broadcast::channel(10);
Self {
engine_tx: engine_tx,
encoder_tx: Arc::new(TokioMutex::new(encoder_tx)),
websocket_broadcast_tx: chat_tx,
websocket_count: TokioMutex::const_new(0usize),
@ -134,154 +125,12 @@ impl EncoderState {
async fn main() -> anyhow::Result<()> {
let surface = Arc::new(Mutex::new(surface::Surface::new()));
let (engine_output_tx, mut engine_output_rx) = mpsc::channel(32);
let (engine_input_tx, engine_input_rx) = mpsc::channel(16);
let encoder_state = Arc::new(TokioMutex::new(EncoderState::new()));
// H.264 encoder related
//let frame: Arc<Mutex<Option<ffmpeg::frame::Video>>> = Arc::new(Mutex::new(None));
let encoder_state = Arc::new(TokioMutex::new(EncoderState::new()));
let (encoder_tx, mut encoder_rx) = mpsc::channel(8);
let state = Arc::new(AppState::new(engine_input_tx, encoder_tx));
let state = Arc::new(AppState::new(encoder_tx));
// VNC related
let mut vnc_client =
vnc_engine::Client::new(engine_output_tx, engine_input_rx, surface.clone());
// vnc client task
tokio::spawn(async move {
let addr = vnc_engine::Address::Tcp("10.16.0.1:5930".parse().expect("its over"));
//let addr = vnc_engine::Address::Tcp("127.0.0.1:6930".parse().expect("its over"));
vnc_client.connect_and_run(addr).await
});
// vnc recv task
let state_clone = state.clone();
let encoder_state_clone = encoder_state.clone();
let vnc_recv_handle = tokio::spawn(async move {
let surface_clone = surface.clone();
// first frame is always a key frame
let mut pts = 0u64;
let mut force_keyframe = true;
let mut frame_update = false;
let mut connected = false;
loop {
match encoder_rx.try_recv() {
Ok(()) => {
if connected {
// force keyframe
force_keyframe = true;
frame_update = true;
}
}
Err(TryRecvError::Disconnected) => break,
Err(TryRecvError::Empty) => {}
}
match engine_output_rx.try_recv() {
Ok(msg) => match msg {
VncMessageOutput::Connect => {
println!("connected");
connected = true;
}
VncMessageOutput::Disconnect => {
println!("disconnect");
}
VncMessageOutput::FramebufferUpdate => {
// let's encode a frame
// First we copy the current VNC framebuffer to the shared
// frame between the encoder thread and ffmpeg
{
let mut state_locked = encoder_state_clone.lock().await;
let mut_frame = state_locked.frame();
let width = mut_frame.width();
let height = mut_frame.height();
let mut surf = surface_clone.lock().expect(
"locking the VNC surface to paint it to the ffmpeg frame failed",
);
let surf_buf = surf.get_buffer();
let buf_ptr =
unsafe { (*(*mut_frame.as_mut_ptr()).buf[0]).data as *mut u32 };
for y in 0..height {
let line_stride = (y * width) as usize;
// Make a slice for the line
// SAFETY: The allocation is guaranteed to be large enough
// for this to work from y = 0..height
let dest_line_slice = unsafe {
let dest_line_ptr = buf_ptr.add(line_stride);
std::slice::from_raw_parts_mut(dest_line_ptr, width as usize)
};
dest_line_slice.copy_from_slice(
&surf_buf[line_stride..line_stride + width as usize],
);
}
}
frame_update = true;
}
VncMessageOutput::FramebufferResized(size) => {
{
let mut state_locked = encoder_state_clone.lock().await;
state_locked.init(size).expect("fuck you");
// reset our internal state
pts = 0;
force_keyframe = true;
frame_update = false;
}
}
},
Err(TryRecvError::Disconnected) => break,
Err(TryRecvError::Empty) => {}
}
// send frame if we should.
if frame_update && connected {
let mut state_locked = encoder_state_clone.lock().await;
match state_locked.send_frame(pts, force_keyframe) {
Some(mut packet) => {
let vec = {
let data = packet.data_mut().expect("packet is empty somehow");
data.to_vec()
};
let _ = state_clone
.websocket_broadcast_tx
.send(ws::Message::Binary(vec));
pts += 1;
if force_keyframe {
force_keyframe = false;
}
}
None => {}
}
frame_update = false;
}
tokio::time::sleep(Duration::from_millis(2)).await;
}
});
// Axum websocket server
let app: Router<()> = Router::new()
@ -312,9 +161,6 @@ async fn main() -> anyhow::Result<()> {
println!("axum died");
}
_ = vnc_recv_handle => {
println!("VNC client disconnected, exiting");
}
}
Ok(())
@ -414,13 +260,13 @@ async fn handle_socket(socket: WebSocket, who: SocketAddr, state: Arc<AppState>)
let keysym = json["keysym"].as_u64().unwrap() as u32;
let pressed = json["pressed"].as_u64().unwrap() == 1;
let _ = recv_clone
/*let _ = recv_clone
.engine_tx
.send(vnc_engine::VncMessageInput::KeyEvent {
keysym: keysym,
pressed: pressed,
})
.await;
.await;*/
}
"mouse" => {
@ -440,13 +286,13 @@ async fn handle_socket(socket: WebSocket, who: SocketAddr, state: Arc<AppState>)
let y = json["y"].as_u64().unwrap() as u32;
let mask = json["mask"].as_u64().unwrap() as u8;
let _ = recv_clone
/*let _ = recv_clone
.engine_tx
.send(vnc_engine::VncMessageInput::MouseEvent {
pt: types::Point { x: x, y: y },
buttons: mask,
})
.await;
.await;*/
}
_ => {}
}

View file

@ -8,17 +8,6 @@ pub struct Rect {
pub height: u32,
}
impl From<vnc::Rect> for Rect {
fn from(value: vnc::Rect) -> Self {
Self {
x: value.x as u32,
y: value.y as u32,
width: value.width as u32,
height: value.height as u32,
}
}
}
#[derive(Debug)]
pub struct Point {
pub x: u32,

View file

@ -1,215 +0,0 @@
//! Native-side VNC client. This is usually run in another OS thread.
use super::surface::Surface;
use super::types::*;
use std::{
sync::{Arc, Mutex},
time::Duration,
};
use tokio::{
io::{AsyncRead, AsyncWrite},
net::{TcpStream, UnixStream},
sync::mpsc::{error::TryRecvError, Receiver, Sender},
};
use vnc::{ClientKeyEvent, ClientMouseEvent, PixelFormat, VncConnector, VncEvent, X11Event};
pub enum Address {
Tcp(std::net::SocketAddr),
Unix(std::path::PathBuf),
}
/// Output message
#[derive(Debug)]
pub enum VncMessageOutput {
Connect,
Disconnect,
// this will contain a single annex B packet
FramebufferUpdate,
FramebufferResized(Size),
}
#[derive(Debug)]
pub enum VncMessageInput {
KeyEvent { keysym: u32, pressed: bool },
MouseEvent { pt: Point, buttons: u8 },
}
pub struct Client {
surf: Arc<Mutex<Surface>>,
out_tx: Sender<VncMessageOutput>,
in_rx: Receiver<VncMessageInput>,
rects_in_frame: Vec<Rect>,
}
impl Client {
/// Creates a new VNC client.
pub fn new(
out_tx: Sender<VncMessageOutput>,
in_rx: Receiver<VncMessageInput>,
surface: Arc<Mutex<Surface>>,
) -> Box<Self> {
let client_obj = Box::new(Self {
surf: surface,
out_tx,
in_rx,
rects_in_frame: Vec::new(),
});
client_obj
}
pub async fn connect_and_run(&mut self, address: Address) -> anyhow::Result<()> {
match address {
Address::Tcp(addr) => {
let stream = TcpStream::connect(addr).await?;
self.connect_and_run_impl(stream).await?
}
Address::Unix(uds) => {
let stream = UnixStream::connect(uds).await?;
self.connect_and_run_impl(stream).await?
}
}
Ok(())
}
async fn connect_and_run_impl<S>(&mut self, stream: S) -> anyhow::Result<()>
where
S: AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static,
{
// the builder pattern should have stayed in java
let vnc = VncConnector::new(stream)
.set_auth_method(async move { Ok("".into()) })
//.add_encoding(vnc::VncEncoding::Tight)
//.add_encoding(vnc::VncEncoding::Zrle)
//.add_encoding(vnc::VncEncoding::CopyRect)
.add_encoding(vnc::VncEncoding::DesktopSizePseudo)
.add_encoding(vnc::VncEncoding::Raw)
.allow_shared(true)
.set_pixel_format(PixelFormat::bgra())
.build()?
.try_start()
.await?
.finish()?;
self.out_tx.send(VncMessageOutput::Connect).await?;
loop {
// Pull a event and act on it. If none are there, it's fine and we can just move on to
// advancing the vnc client, but if the channel is closed, that means we are to disconnect
//
// Note that we do not timeout because we will eventually wait for a event later
// either way.
match self.in_rx.try_recv() {
Ok(val) => match val {
VncMessageInput::KeyEvent { keysym, pressed } => {
vnc.input(X11Event::KeyEvent(ClientKeyEvent {
keycode: keysym,
down: pressed,
}))
.await?;
}
VncMessageInput::MouseEvent { pt, buttons } => {
vnc.input(X11Event::PointerEvent(ClientMouseEvent {
position_x: pt.x as u16,
position_y: pt.y as u16,
bottons: buttons,
}))
.await?;
}
},
Err(TryRecvError::Empty) => {}
// On disconnection from the client input channel
// we just give up and disconnect early.
Err(TryRecvError::Disconnected) => {
break;
}
}
// pull events until there is no more event to pull
match vnc.poll_event().await {
Ok(Some(e)) => {
match e {
VncEvent::SetResolution(res) => {
{
let mut lk = self.surf.lock().expect("couldn't lock Surface");
lk.resize(Size {
width: res.width as u32,
height: res.height as u32,
});
}
let cvm_size = Size {
width: res.width as u32,
height: res.height as u32,
};
self.out_tx
.send(VncMessageOutput::FramebufferResized(cvm_size))
.await?;
}
// TODO: implement copyrect support in Surface
//VncEvent::Copy(dest_rect, src_rect) => {
// TODO copy rect
//}
VncEvent::RawImage(rects) => {
let mut lk = self.surf.lock().expect("couldn't lock Surface");
for rect in rects.iter() {
let cvm_rect = Rect::from(rect.rect);
// blit onto the surface
lk.blit_buffer(cvm_rect.clone(), unsafe {
std::slice::from_raw_parts(
rect.data.as_ptr() as *const u32,
rect.data.len() / core::mem::size_of::<u32>(),
)
});
self.rects_in_frame.push(cvm_rect);
}
}
_ => {}
}
}
// No events, so let's request some more and push what we got in the meantime
Ok(None) => {
vnc.input(X11Event::Refresh).await?;
if !self.rects_in_frame.is_empty() {
// We don't care what rects ARE there, but
// if none were pressent then we probably need not bother
self.out_tx
.send(VncMessageOutput::FramebufferUpdate)
.await?;
self.rects_in_frame.clear();
}
}
// TODO: we might want to pass this to js at some point
Err(_e) => {
break;
}
}
tokio::time::sleep(Duration::from_millis(2)).await;
}
// Disconnect if we exit. We don't care about errors in this path
let _ = vnc.close().await;
self.out_tx.send(VncMessageOutput::Disconnect).await?;
Ok(())
}
}