1use crate::error::Result;
2use crate::rpc::RpcClient;
3use crate::tunnelrpc_capnp;
4
5pub const REGISTRATION_SERVER_INTERFACE_ID: u64 = 0xf716_95ec_7fe8_5497;
7pub const METHOD_REGISTER_CONNECTION: u16 = 0;
9pub const METHOD_UNREGISTER_CONNECTION: u16 = 1;
11pub const METHOD_UPDATE_LOCAL_CONFIGURATION: u16 = 2;
13
14#[derive(Debug, Clone, Default)]
16pub struct ClientInformation {
17 pub client_identifier: Vec<u8>,
19 pub features: Vec<String>,
21 pub version: String,
23 pub arch: String,
25}
26
27#[derive(Debug, Clone, Default)]
29pub struct ConnectionOptions {
30 pub client: ClientInformation,
32 pub origin_local_ip: Vec<u8>,
34 pub replace_existing: bool,
36 pub compression_quality: u8,
38 pub number_previous_attempts: u8,
40}
41
42#[derive(Debug, Clone, Default)]
44pub struct TunnelAuth {
45 pub account_tag: String,
47 pub tunnel_secret: Vec<u8>,
49}
50
51#[derive(Debug, Clone)]
53pub struct ConnectionError {
54 pub cause: String,
56 pub retry_after: i64,
58 pub should_retry: bool,
60}
61
62#[derive(Debug, Clone)]
64pub struct ConnectionDetails {
65 pub uuid: Vec<u8>,
67 pub location_name: String,
69 pub tunnel_is_remotely_managed: bool,
71}
72
73#[derive(Debug, Clone)]
75pub enum ConnectionResponse {
76 Error(ConnectionError),
78 Details(ConnectionDetails),
80}
81
82pub struct TunnelClient<S> {
87 rpc: RpcClient<S>,
88}
89
90impl<S: crate::io::AsyncStream + Unpin> TunnelClient<S> {
91 pub fn new(rpc: RpcClient<S>) -> Self {
93 Self { rpc }
94 }
95
96 pub async fn bootstrap(&mut self) -> Result<()> {
98 self.rpc.bootstrap().await.map(|_| ())
99 }
100
101 pub async fn register_connection(
103 &mut self,
104 auth: TunnelAuth,
105 tunnel_identifier: &[u8],
106 connection_index: u8,
107 options: &ConnectionOptions,
108 ) -> Result<ConnectionResponse> {
109 let auth_ = auth;
110 let tunnel_identifier = tunnel_identifier.to_vec();
111 let options = options.clone();
112 self.rpc
113 .call(
114 0,
115 REGISTRATION_SERVER_INTERFACE_ID,
116 METHOD_REGISTER_CONNECTION,
117 |payload| {
118 let mut parameters = payload
119 .reborrow()
120 .init_content()
121 .init_as::<tunnelrpc_capnp::registration_server::register_connection_params::Builder>();
122 {
123 let mut a = parameters.reborrow().init_auth();
124 a.set_account_tag(&auth_.account_tag);
125 a.set_tunnel_secret(&auth_.tunnel_secret);
126 }
127 parameters.set_tunnel_id(&tunnel_identifier);
128 parameters.set_conn_index(connection_index);
129 {
130 let mut o = parameters.reborrow().init_options();
131 let mut c = o.reborrow().init_client();
132 c.set_client_id(&options.client.client_identifier);
133 let mut features = c
134 .reborrow()
135 .init_features(options.client.features.len() as u32);
136 for (i, f) in options.client.features.iter().enumerate() {
137 features.set(i as u32, f);
138 }
139 c.set_version(&options.client.version);
140 c.set_arch(&options.client.arch);
141 o.set_origin_local_ip(&options.origin_local_ip);
142 o.set_replace_existing(options.replace_existing);
143 o.set_compression_quality(options.compression_quality);
144 o.set_num_previous_attempts(options.number_previous_attempts);
145 }
146 payload.reborrow().init_cap_table(0);
147 Ok(())
148 },
149 |results| {
150 let results_reader = results
151 .reborrow()
152 .get_content()
153 .get_as::<tunnelrpc_capnp::registration_server::register_connection_results::Reader<'_>>()?;
154 let connection_response = results_reader.reborrow().get_result()?;
155 match connection_response.reborrow().get_result().which()? { tunnelrpc_capnp::connection_response::result::Error(e) => {
156 let e = e?;
157 Ok(ConnectionResponse::Error(ConnectionError {
158 cause: e.get_cause()?.to_str()?.to_string(),
159 retry_after: e.get_retry_after(),
160 should_retry: e.get_should_retry(),
161 }))
162 }
163 tunnelrpc_capnp::connection_response::result::ConnectionDetails(d) => {
164 let d = d?;
165 Ok(ConnectionResponse::Details(ConnectionDetails {
166 uuid: d.get_uuid()?.to_vec(),
167 location_name: d.get_location_name()?.to_str()?.to_string(),
168 tunnel_is_remotely_managed: d
169 .get_tunnel_is_remotely_managed(),
170 }))
171 }
172 }
173 },
174 )
175 .await
176 }
177
178 pub async fn unregister_connection(&mut self) -> Result<()> {
180 self.rpc
181 .call(
182 0,
183 REGISTRATION_SERVER_INTERFACE_ID,
184 METHOD_UNREGISTER_CONNECTION,
185 |payload| {
186 payload
187 .reborrow()
188 .init_content()
189 .init_as::<tunnelrpc_capnp::registration_server::unregister_connection_params::Builder>();
190 payload.reborrow().init_cap_table(0);
191 Ok(())
192 },
193 |_results| Ok(()),
194 )
195 .await
196 }
197
198 pub async fn update_local_configuration(&mut self, configuration: &[u8]) -> Result<()> {
201 let configuration = configuration.to_vec();
202 self.rpc
203 .call(
204 0,
205 REGISTRATION_SERVER_INTERFACE_ID,
206 METHOD_UPDATE_LOCAL_CONFIGURATION,
207 |payload| {
208 let mut parameters = payload
209 .reborrow()
210 .init_content()
211 .init_as::<tunnelrpc_capnp::registration_server::update_local_configuration_params::Builder>();
212 parameters.set_config(&configuration);
213 payload.reborrow().init_cap_table(0);
214 Ok(())
215 },
216 |_results| Ok(()),
217 )
218 .await
219 }
220
221 pub fn into_inner(self) -> RpcClient<S> {
224 self.rpc
225 }
226
227 pub async fn close(self) -> Result<S> {
230 self.rpc.close().await
231 }
232}
233
234impl ConnectionResponse {
238 pub fn into_result(self) -> std::result::Result<ConnectionDetails, RegistrationFailure> {
240 match self {
241 Self::Details(d) => Ok(d),
242 Self::Error(e) => Err(RegistrationFailure::from(e)),
243 }
244 }
245}
246
247#[derive(Debug, Clone)]
249pub enum RegistrationFailure {
250 Retryable {
252 cause: String,
254 retry_after: i64,
256 },
257 Permanent(String),
259}
260
261impl From<ConnectionError> for RegistrationFailure {
262 fn from(e: ConnectionError) -> Self {
263 if e.should_retry {
264 Self::Retryable {
265 cause: e.cause,
266 retry_after: e.retry_after,
267 }
268 } else {
269 Self::Permanent(e.cause)
270 }
271 }
272}
273
274impl std::fmt::Display for RegistrationFailure {
275 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
276 match self {
277 Self::Retryable { cause, retry_after } => {
278 write!(
279 f,
280 "retryable registration failure ({cause}, retry after {retry_after}ns)"
281 )
282 }
283 Self::Permanent(cause) => write!(f, "permanent registration failure: {cause}"),
284 }
285 }
286}
287
288impl std::error::Error for RegistrationFailure {}