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
71
72
73
74
75
76
77
use std::net::SocketAddr;

use async_std::channel::Receiver;
use tracing::{error, info};

use crate::{
    header::{DatagramHeader, HEADER_SIZE},
    protocol::ProtocolSocket,
    MAX_DATAGRAM_SIZE, MAX_PACKAGE_SIZE,
};

pub(crate) struct OutDatagram {
    header: DatagramHeader,
    data: Vec<u8>,
    target: SocketAddr,
}

impl OutDatagram {
    /// # Panics
    ///
    /// * If `data` is empty.
    ///
    /// * If `data` is larger than [`MAX_PACKAGE_SIZE`].
    pub(crate) fn from_slice(header: DatagramHeader, data: &[u8], target: SocketAddr) -> Self {
        assert!(!data.is_empty());
        assert!(data.len() <= MAX_PACKAGE_SIZE);

        let mut full_data = Vec::with_capacity(HEADER_SIZE + data.len());
        full_data.extend([0; HEADER_SIZE]);
        full_data.extend(data);
        Self::new(header, full_data, target)
    }

    /// # Argument
    ///
    /// * `header`
    ///
    /// * `data` - data of the datagram. First [`HEADER_SIZE`] is reserved for
    ///   to-be-written header.
    ///
    /// * `target` - datagram recipient.
    ///
    /// # Panics
    ///
    /// * If `data` length is smaller or equal to [`HEADER_SIZE`].
    ///
    /// * If `data` is larger than [`MAX_DATAGRAM_SIZE`].
    pub(crate) fn new(header: DatagramHeader, data: Vec<u8>, target: SocketAddr) -> Self {
        assert!(data.len() > HEADER_SIZE);
        assert!(data.len() <= MAX_DATAGRAM_SIZE);

        Self {
            header,
            data,
            target,
        }
    }
}

pub(super) async fn run(port: u16, datagrams: Receiver<OutDatagram>, socket: ProtocolSocket) {
    info!("Starting datagram sender on port {port}...");

    loop {
        let Ok(mut datagram) = datagrams.recv().await else {
            break;
        };
        if let Err(err) = socket
            .send(datagram.header, &mut datagram.data, datagram.target)
            .await
        {
            error!("Error while sending a datagram: {err:?}");
            break;
        }
    }

    info!("Datagram sender on port {port} finished.");
}