use std::cmp;
use async_std::{
net::{SocketAddr, UdpSocket},
sync::Arc,
};
use crate::{errors, result::Result};
const MAX_UDP_LEN: usize = 65507;
pub struct RpcHeader {
flags: u8,
rid: u16,
}
impl RpcHeader {
pub fn request_from_rid(rid: u16) -> Self {
Self {
flags: 0b00000000,
rid,
}
}
pub fn is_request(&self) -> bool {
(self.flags & 0b00000001) == 0
}
pub fn flip_request(&mut self) -> bool {
self.flags |= 0b00000001;
self.is_request()
}
}
pub struct RpcMessage {
header: RpcHeader,
buf: [u8; MAX_UDP_LEN],
len: usize,
}
impl RpcMessage {
pub fn split(self) -> RpcHeader {
self.header
}
pub fn request_id(&self) -> u16 {
self.header.rid
}
pub fn is_request(&self) -> bool {
self.header.is_request()
}
pub async fn write_to_socket(
udp: &Arc<UdpSocket>,
addr: SocketAddr,
header: RpcHeader,
data: &[u8],
) -> Result<usize> {
if data.len() > 65504 {
return Err(errors::invalid_input(
"buffer longer than 65504 bytes",
));
}
let len = data.len() + 3;
let buf = {
let mut buf = [0u8; MAX_UDP_LEN];
let rid_bytes = header.rid.to_be_bytes();
buf[0] = header.flags;
buf[1] = rid_bytes[0];
buf[2] = rid_bytes[1];
buf[3..len].copy_from_slice(data);
buf
};
Ok(udp.send_to(&buf[..len], addr).await? - 3)
}
pub async fn read_from_socket(
udp: &Arc<UdpSocket>,
) -> Result<(Self, SocketAddr)> {
let mut buf = [0u8; MAX_UDP_LEN];
loop {
let (len, addr) = udp.recv_from(&mut buf[..]).await?;
if len < 3 {
continue;
}
let header = {
let flags = buf[0];
let rid = {
let mut bytes = [0u8; 2];
bytes[0] = buf[1];
bytes[1] = buf[2];
u16::from_be_bytes(bytes)
};
RpcHeader { flags, rid }
};
return Ok((RpcMessage { header, buf, len }, addr));
}
}
pub fn write_to_buffer(&self, buf: &mut [u8]) -> usize {
let len = cmp::min(self.len - 3, buf.len());
buf[..len].copy_from_slice(&self.buf[3..self.len]);
len
}
}