diff --git a/src/lib.rs b/src/lib.rs index c6eebbb..fb103b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ +#![feature(iter_map_windows)] + pub mod proto; pub mod server; diff --git a/src/proto/finger_protocol.rs b/src/proto/finger_protocol.rs index 8b13789..b857590 100644 --- a/src/proto/finger_protocol.rs +++ b/src/proto/finger_protocol.rs @@ -1 +1,107 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(C)] +pub struct FingerRequest { + long: bool, + name: String, +} +impl FingerRequest { + pub fn new(long: bool, name: String) -> Self { + Self { long, name } + } + + pub fn to_bytes(&self) -> Vec { + let mut result = Vec::new(); + if self.long { + result.extend(b"/W "); + } + + result.extend(self.name.as_bytes()); + result.extend(b"\r\n"); + + result + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + let (long, name) = if &bytes[..3] == b"/W " { + (true, &bytes[3..]) + } else { + (false, bytes) + }; + + let name = match name.strip_suffix(b"\r\n") { + Some(new_name) => new_name, + None => name, + }; + + Self::new(long, String::from_utf8_lossy(name).to_string()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FingerResponse(String); + +impl FingerResponse { + pub fn new(content: String) -> Self { + Self(content) + } + + pub fn get_inner(&self) -> &str { + &self.0 + } + + pub fn into_inner(self) -> String { + self.0 + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + if bytes.is_empty() { + return Self(String::new()); + } + + fn normalize(c: u8) -> u8 { + if c == (b'\r' | 0x80) || c == (b'\n' | 0x80) { + c & 0x7f + } else { + c + } + } + + let normalized: Vec = bytes + .iter() + .copied() + .map(normalize) + .chain(std::iter::once(normalize(*bytes.last().unwrap()))) + .map_windows(|[a, b]| { + if *a == b'\r' && *b == b'\n' { + None + } else { + Some(*a) + } + }) + .flatten() + .collect(); + + let result = String::from_utf8_lossy(&normalized).to_string(); + + Self(result) + } + + pub fn to_bytes(&self) -> Vec { + let mut out = Vec::with_capacity(self.0.len() + 2); + + for &b in self.0.as_bytes() { + if b == b'\n' { + out.extend_from_slice(b"\r\n"); + } else { + out.push(b); + } + } + + if !self.0.ends_with('\n') { + out.extend_from_slice(b"\r\n"); + } + + out + } +}