exoplanet/src/state.rs

211 lines
5.7 KiB
Rust

use crate::pronouns::Pronouns;
use crate::protocol::*;
use protocol::*;
use std::collections::VecDeque;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult};
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::Arc;
pub struct Identity {
pub username: String,
pub about: String,
pub pronouns: Option<Pronouns>,
}
pub struct LoginInfo {
pub identity: Identity,
pub listen_port: u16,
}
pub struct LocalSocket {
pub listen_socket: UdpSocket,
}
impl LocalSocket {
pub fn new(port: u16) -> Result<Self, IoError> {
let ip = Ipv4Addr::UNSPECIFIED.into();
let addr = SocketAddr::new(ip, port);
let listen_socket = UdpSocket::bind(addr)?;
listen_socket.set_nonblocking(true)?;
Ok(Self { listen_socket })
}
}
pub struct State {
pub local_socket: Arc<LocalSocket>,
pub connections: Vec<Connection>,
pub identity: Identity,
pub next_uid: usize,
}
impl State {
pub fn new(info: LoginInfo) -> Result<Self, IoError> {
let LoginInfo {
identity,
listen_port,
} = info;
let local_socket = Arc::new(LocalSocket::new(listen_port)?);
let connections = Vec::new();
let identity = identity;
let next_uid = 0;
Ok(Self {
local_socket,
connections,
identity,
next_uid,
})
}
pub fn poll(&mut self) -> Result<(), IoError> {
let mut buf = [0u8; 65507];
loop {
match self.local_socket.listen_socket.recv_from(&mut buf) {
Ok((len, from)) => {
let packet = &buf[0..len];
self.on_packet(from, packet)?;
}
Err(e) if e.kind() == IoErrorKind::WouldBlock => break,
Err(e) => return Err(e),
}
}
Ok(())
}
pub fn get_packet_kind(reader: &mut impl std::io::Read) -> IoResult<PacketKind> {
let kind = Var::<u16>::decode(reader)?.0;
kind.try_into()
.map_err(|_| IoErrorKind::InvalidInput.into())
}
pub fn on_packet(&mut self, from: SocketAddr, mut packet: &[u8]) -> IoResult<()> {
let kind = Self::get_packet_kind(&mut packet)?;
let connection = self.connections.iter_mut().find(|c| c.other_addr == from);
if let Some(connection) = connection {
connection.on_packet(kind, &mut packet)?;
} else if kind == PacketKind::HandshakeRequest {
let sock = self.local_socket.to_owned();
let uid = self.next_uid;
let connection = Connection::new_requested(sock, uid, from);
self.connections.push(connection);
self.next_uid += 1;
}
Ok(())
}
pub fn connect(&mut self, to: SocketAddr) -> IoResult<()> {
let sock = self.local_socket.to_owned();
let uid = self.next_uid;
let connection = Connection::connect(sock, uid, to)?;
self.connections.push(connection);
self.next_uid += 1;
Ok(())
}
}
pub struct Connection {
/// A handle to the local socket this connection is using.
pub local_socket: Arc<LocalSocket>,
/// Local unique identifier for this connection.
pub uid: usize,
/// The remote address of the other end of this connection.
pub other_addr: SocketAddr,
/// The current state.
pub state: ConnectionState,
}
impl Connection {
pub fn connect(
local_socket: Arc<LocalSocket>,
uid: usize,
other_addr: SocketAddr,
) -> IoResult<Self> {
let connection = Self {
local_socket,
uid,
other_addr,
state: ConnectionState::Connecting,
};
connection.send_empty_packet(PacketKind::HandshakeRequest)?;
Ok(connection)
}
pub fn new_requested(
local_socket: Arc<LocalSocket>,
uid: usize,
other_addr: SocketAddr,
) -> Self {
Self {
local_socket,
uid,
other_addr,
state: ConnectionState::Pending,
}
}
pub fn on_packet(&mut self, kind: PacketKind, mut packet: &[u8]) -> Result<(), IoError> {
match self.state {
ConnectionState::Connecting => match kind {
PacketKind::HandshakeAccept => {
self.state = ConnectionState::Connected;
self.send_empty_packet(PacketKind::HandshakeFinal)?;
}
_ => {}
},
ConnectionState::Pending => {}
ConnectionState::Accepted => match kind {
PacketKind::HandshakeFinal => {
self.state = ConnectionState::Connected;
}
_ => {}
},
ConnectionState::Connected => match kind {
PacketKind::Ping => self.send_empty_packet(PacketKind::Pong)?,
PacketKind::Pong => {}
PacketKind::Message => {
let message = Message::decode(&mut packet)?;
eprintln!("message: {:?}", message);
}
_ => {}
},
}
Ok(())
}
pub fn send_packet(
&self,
kind: PacketKind,
encode: impl FnOnce(&mut Vec<u8>) -> std::io::Result<()>,
) -> IoResult<()> {
let mut buf = Vec::new();
Var(kind as u16).encode(&mut buf)?;
encode(&mut buf)?;
self.local_socket
.listen_socket
.send_to(&buf, self.other_addr)?;
Ok(())
}
pub fn send_empty_packet(&self, kind: PacketKind) -> IoResult<()> {
self.send_packet(kind, |_| Ok(()))
}
}
#[derive(PartialEq, Eq)]
pub enum ConnectionState {
Connecting,
Pending,
Accepted,
Connected,
}