1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::enc::{EnetDecoder, EnetDecoderError, EnetEncoder, EnetEncoderError};
use enet_proto::{RequestEnvelope, Response};
use futures::{SinkExt, StreamExt};
use thiserror::Error;
use tokio::{
  io,
  net::{
    tcp::{OwnedReadHalf, OwnedWriteHalf},
    TcpStream, ToSocketAddrs,
  },
};
use tokio_util::codec::{FramedRead, FramedWrite};
use tracing::instrument;

pub(crate) struct Connection {
  reader: FramedRead<OwnedReadHalf, EnetDecoder>,
  writer: FramedWrite<OwnedWriteHalf, EnetEncoder>,
}

impl Connection {
  pub(crate) async fn new(addr: impl ToSocketAddrs) -> Result<Self, ConnectError> {
    let stream = TcpStream::connect(addr).await?;
    let (reader, writer) = stream.into_split();

    Ok(Self {
      reader: FramedRead::new(reader, EnetDecoder::new()),
      writer: FramedWrite::new(writer, EnetEncoder::new()),
    })
  }

  #[instrument(level = "debug", target = "enet-client::con", skip(self, message), err)]
  pub(crate) async fn send(&mut self, message: &RequestEnvelope) -> Result<(), SendError> {
    Ok(self.writer.send(message).await?)
  }

  #[instrument(level = "debug", target = "enet-client::con", skip(self), err)]
  pub(crate) async fn recv(&mut self) -> Result<Response, RecvError> {
    match self.reader.next().await {
      Some(result) => Ok(result?),
      None => bail!(ConnectionClosed),
    }
  }
}

#[non_exhaustive]
#[derive(Debug, Error)]
#[error("Failed to connect to gateway.")]
pub enum ConnectError {
  FailedToConnect(#[from] io::Error),
}

#[non_exhaustive]
#[derive(Debug, Error)]
#[error("Failed to send message.")]
pub enum SendError {
  FailedToSend(#[from] EnetEncoderError),
}

#[non_exhaustive]
#[derive(Debug, Error)]
#[error("Failed to receive response.")]
pub enum RecvError {
  DecoderError(#[from] EnetDecoderError),

  Closed(#[from] ConnectionClosed),
}

#[derive(Debug, Error)]
#[error("Connection closed.")]
pub struct ConnectionClosed;