1use std::io;
2
3use ombrac::prelude::*;
4use ombrac_transport::{Initiator, Reliable};
5
6#[cfg(feature = "datagram")]
7use ombrac_transport::Unreliable;
8
9pub struct Client<T> {
10 secret: Secret,
11 transport: T,
12}
13
14impl<T: Initiator> Client<T> {
15 pub fn new(secret: Secret, transport: T) -> Self {
16 Self { secret, transport }
17 }
18
19 pub async fn tcp_connect<A>(&self, addr: A) -> io::Result<impl Reliable + '_>
20 where
21 A: Into<Address>,
22 {
23 use tokio::io::AsyncWriteExt;
24
25 let mut stream = self.transport.open_bidirectional().await?;
26 let request = Connect::with(self.secret, addr).to_bytes()?;
27
28 stream.write_all(&request).await?;
29
30 Ok(stream)
31 }
32
33 #[cfg(feature = "datagram")]
34 pub async fn udp_associate(&self) -> io::Result<Datagram<impl Unreliable + '_>> {
35 let stream = self.transport.open_datagram().await?;
36
37 Ok(Datagram::with(self.secret, stream))
38 }
39}
40
41#[cfg(feature = "datagram")]
42pub struct Datagram<U: Unreliable>(Secret, U);
43
44#[cfg(feature = "datagram")]
45impl<U: Unreliable> Datagram<U> {
46 fn with(secret: Secret, stream: U) -> Self {
47 Self(secret, stream)
48 }
49
50 pub async fn send<A, B>(&self, addr: A, data: B) -> io::Result<()>
51 where
52 A: Into<Address>,
53 B: Into<bytes::Bytes>,
54 {
55 let packet = Packet::with(self.0, addr, data).to_bytes()?;
56
57 if let Err(error) = self.1.send(packet).await {
58 return Err(io::Error::other(error.to_string()));
59 };
60
61 Ok(())
62 }
63
64 pub async fn recv(&self) -> io::Result<(Address, bytes::Bytes)> {
65 match self.1.recv().await {
66 Ok(mut data) => {
67 let packet = Packet::from_bytes(&mut data)?;
68 Ok((packet.address, packet.data))
69 }
70 Err(error) => Err(io::Error::other(error.to_string())),
71 }
72 }
73}