mirror of
https://github.com/rustdesk/hbb_common.git
synced 2026-10-12 03:33:59 +00:00
webrtc: add an answerer example for the web client's e2e
Reads a `webrtc://` offer from stdin, answers it, bridges ICE candidates as JSON lines over stdin/stdout and echoes every message. rustdesk-web-js drives it from Chrome (js/e2e/webrtc) to check that the browser transport and WebRTCStream still agree on the envelope, the signed fingerprint, the candidate JSON and the fragment framing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXJJGEGdgu26wgCppvUXdZ
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
00f0a720b5
commit
98d256d1b9
@@ -0,0 +1,80 @@
|
||||
// Temporary e2e helper for the web client: answers a browser offer read from
|
||||
// stdin, bridges ICE candidates over stdin/stdout as JSON lines, then echoes
|
||||
// every message it receives.
|
||||
extern crate hbb_common;
|
||||
|
||||
#[cfg(feature = "webrtc")]
|
||||
#[hbb_common::tokio::main]
|
||||
async fn main() -> hbb_common::anyhow::Result<()> {
|
||||
use hbb_common::{
|
||||
anyhow::anyhow,
|
||||
serde_json::{self, json, Value},
|
||||
tokio,
|
||||
webrtc::WebRTCStream,
|
||||
};
|
||||
use std::io::BufRead;
|
||||
|
||||
let mut offer = String::new();
|
||||
std::io::stdin().lock().read_line(&mut offer)?;
|
||||
if offer.trim().is_empty() {
|
||||
return Err(anyhow!("no offer"));
|
||||
}
|
||||
let mut stream = WebRTCStream::new(offer.trim(), false, 30000).await?;
|
||||
let out = json!({
|
||||
"answer": stream.local_endpoint(),
|
||||
"session_key": stream.session_key(),
|
||||
"local_fingerprint": stream.local_dtls_fingerprint().await?,
|
||||
"remote_fingerprint": stream.remote_dtls_fingerprint().await?,
|
||||
});
|
||||
println!("{}", out);
|
||||
let mut ice_rx = stream
|
||||
.take_local_ice_rx()
|
||||
.ok_or_else(|| anyhow!("no ice rx"))?;
|
||||
tokio::spawn(async move {
|
||||
while let Some(c) = ice_rx.recv().await {
|
||||
println!("{}", json!({ "candidate": c }));
|
||||
}
|
||||
});
|
||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<String>();
|
||||
std::thread::spawn(move || {
|
||||
let stdin = std::io::stdin();
|
||||
for line in stdin.lock().lines().flatten() {
|
||||
if tx.send(line).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
let for_ice = stream.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(line) = rx.recv().await {
|
||||
let Ok(v) = serde_json::from_str::<Value>(&line) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(c) = v.get("candidate").and_then(Value::as_str) {
|
||||
if let Err(e) = for_ice.add_remote_ice_candidate(c).await {
|
||||
eprintln!("add_remote_ice_candidate failed: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
stream.wait_connected(30000).await?;
|
||||
println!(
|
||||
"{}",
|
||||
json!({
|
||||
"connected": true,
|
||||
"relayed": stream.is_relayed().await,
|
||||
"remote_ipv6": stream.is_remote_ipv6().await,
|
||||
})
|
||||
);
|
||||
while let Some(res) = stream.next().await {
|
||||
let bytes = res?;
|
||||
let len = bytes.len();
|
||||
stream.send_bytes(bytes.freeze()).await?;
|
||||
eprintln!("echoed {len} bytes");
|
||||
}
|
||||
stream.close().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "webrtc"))]
|
||||
fn main() {}
|
||||
Reference in New Issue
Block a user