webterm_agent/models/
handshaker.rs

1use crate::agent_version::agent_version_to_flatbuffers;
2use crate::config::Config;
3use crate::messaging::process_r2a_handshake::process_r2a_handshake;
4use crate::models::agent_error::AgentError;
5use crate::models::relay::Relay;
6use reqwest::Client;
7use std::sync::Arc;
8use tracing::info;
9use webterm_core::flatbuffers_helpers::read_message;
10use webterm_core::generated::flatbuffers_schema::handshake_v1::R2aHandshakeRoot;
11use webterm_core::serialisers::handshake_v1::a2r_handshake_builder::A2rHandshakeBuilder;
12
13pub struct Handshaker {
14    pub result_relay: Arc<Relay>,
15    pub result_nonce: String,
16}
17
18impl Handshaker {
19    pub async fn run(config: Arc<Config>) -> Result<Self, AgentError> {
20        let relay = config.random_relay();
21        let mut subname = config.original_device_subname().to_string();
22        loop {
23            let result = initiate(config.clone(), relay.clone(), subname).await;
24
25            match result {
26                Ok((relay, nonce)) => {
27                    return Ok(Self {
28                        result_nonce: nonce,
29                        result_relay: relay,
30                    });
31                }
32                Err(AgentError::RelayErrorAgentAlreadyExists) => {
33                    subname = config.try_new_device_subname()
34                }
35                Err(e) => {
36                    return Err(e);
37                }
38            }
39        }
40    }
41}
42
43async fn initiate(
44    config: Arc<Config>,
45    relay: Arc<Relay>,
46    subname: String,
47) -> Result<(Arc<Relay>, String), AgentError> {
48    info!(
49        "Starting handshake: {} with device {}/{}",
50        relay.host(),
51        config.device_name(),
52        subname
53    );
54    let payload = A2rHandshakeBuilder::new()
55        .root_request_connection(config.device_name(), &subname)
56        .to_flatbuffers(agent_version_to_flatbuffers());
57    let url = relay.handshake_url();
58
59    let client = Client::new();
60    let response = client.post(url).body(payload.0).send().await?;
61
62    let body = response.bytes().await?;
63    let message = read_message::<R2aHandshakeRoot>(&body)?;
64    let output = process_r2a_handshake(message).await?;
65
66    Ok((relay, output.auth_nonce))
67}