use std::{borrow::Cow, str::FromStr, time::Duration};
use magic_wormhole::{
rendezvous::{RendezvousError, DEFAULT_RENDEZVOUS_SERVER},
AppConfig, AppID, Code, MailboxConnection, Wormhole, WormholeError,
};
use serde::{Deserialize, Serialize};
use tracing::Level;
use tracing_subscriber::FmtSubscriber;
#[derive(Clone, Serialize, Deserialize)]
pub struct WormholeAppVersion {
bm_exp_ver: u8,
}
pub const APP_CONFIG: AppConfig<WormholeAppVersion> = AppConfig {
id: AppID(Cow::Borrowed("org.timmc.breakmancer.experiments")),
rendezvous_url: Cow::Borrowed(DEFAULT_RENDEZVOUS_SERVER),
app_version: WormholeAppVersion { bm_exp_ver: 1 },
};
pub const PREDEFINED_CODE: &str = "12097-abcw3i2tyiv";
async fn experiment_connect1() {
let code = Code::from_str(PREDEFINED_CODE).unwrap();
println!("Making mailbox connection...");
let mc = MailboxConnection::connect(APP_CONFIG, code, true)
.await
.unwrap();
println!("...done");
tokio::time::sleep(Duration::from_secs(5)).await;
println!("Making wormhole...");
let w = Wormhole::connect(mc).await.unwrap();
println!("...done");
dbg!(w.peer_version());
tokio::time::sleep(Duration::from_secs(20)).await;
w.close().await.unwrap();
}
async fn experiment_connect2_controller() {
loop {
let code = Code::from_str(PREDEFINED_CODE).unwrap();
println!("Making mailbox connection (allocate if necessary)...");
let mc = MailboxConnection::connect(APP_CONFIG, code, true)
.await
.unwrap();
println!("...done");
tokio::time::sleep(Duration::from_secs(5)).await;
println!("Making wormhole...");
let w = Wormhole::connect(mc).await.unwrap();
println!("...done");
tokio::time::sleep(Duration::from_secs(20)).await;
w.close().await.unwrap();
println!("Closed wormhole.");
println!("Will try to connect to another breakpoint.");
}
}
async fn experiment_connect2_breakpoint() {
let mc = loop {
let code = Code::from_str(PREDEFINED_CODE).unwrap();
println!("Attempting mailbox connection (no allocate)...");
match MailboxConnection::connect(APP_CONFIG, code, false).await {
Ok(mc) => break mc,
Err(err) => match err {
WormholeError::UnclaimedNameplate(_) => {
println!("Nameplate not yet allocated by controller; sleeping.");
tokio::time::sleep(Duration::from_secs(5)).await;
continue;
}
WormholeError::ServerError(RendezvousError::Server(err)) => {
if &*err == "crowded" {
println!("Nameplate busy with another breakpoint; sleeping.");
tokio::time::sleep(Duration::from_secs(5)).await;
continue;
} else {
panic!("Unexpected server error: {err}");
}
}
err => panic!("Unexpected error: {err:?}"),
},
}
};
println!("...done");
tokio::time::sleep(Duration::from_secs(5)).await;
println!("Making wormhole...");
let w = Wormhole::connect(mc).await.unwrap();
println!("...done");
tokio::time::sleep(Duration::from_secs(20)).await;
w.close().await.unwrap();
}
#[tokio::main]
async fn main() {
let trace_subscriber = FmtSubscriber::builder()
.with_max_level(Level::DEBUG)
.finish();
tracing::subscriber::set_global_default(trace_subscriber).unwrap();
let args: Vec<String> = std::env::args().collect();
match args[1].as_str() {
"1" => experiment_connect1().await,
"2" => match args[2].as_str() {
"c" => experiment_connect2_controller().await,
"b" => experiment_connect2_breakpoint().await,
_ => unimplemented!(),
},
_ => unimplemented!(),
}
}