forked from lavina/lavina
Compare commits
2 Commits
887fd95194
...
16844f5b85
Author | SHA1 | Date |
---|---|---|
Nikita Vilunov | 16844f5b85 | |
Nikita Vilunov | 1373767d7f |
|
@ -7,6 +7,7 @@ use nonempty::nonempty;
|
||||||
use nonempty::NonEmpty;
|
use nonempty::NonEmpty;
|
||||||
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
|
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
||||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
@ -96,7 +97,7 @@ async fn handle_registration<'a>(
|
||||||
let mut pass: Option<Str> = None;
|
let mut pass: Option<Str> = None;
|
||||||
|
|
||||||
let user = loop {
|
let user = loop {
|
||||||
let res = reader.read_until(b'\n', &mut buffer).await;
|
let res = read_irc_message(reader, &mut buffer).await;
|
||||||
let res = match res {
|
let res = match res {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
|
@ -252,7 +253,7 @@ async fn handle_registered_socket<'a>(
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
biased;
|
biased;
|
||||||
len = reader.read_until(b'\n', &mut buffer) => {
|
len = read_irc_message(reader, &mut buffer) => {
|
||||||
let len = len?;
|
let len = len?;
|
||||||
let len = if len == 0 {
|
let len = if len == 0 {
|
||||||
log::info!("EOF, Terminating socket");
|
log::info!("EOF, Terminating socket");
|
||||||
|
@ -291,6 +292,21 @@ async fn handle_registered_socket<'a>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn read_irc_message(reader: &mut BufReader<ReadHalf<'_>>, buf: &mut Vec<u8>) -> Result<usize> {
|
||||||
|
let mut size = 0;
|
||||||
|
'outer: loop {
|
||||||
|
let res = reader.read_until(b'\r', buf).await?;
|
||||||
|
size += res;
|
||||||
|
let next = reader.read_u8().await?;
|
||||||
|
buf.push(next);
|
||||||
|
size += 1;
|
||||||
|
if next != b'\n' {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
return Ok(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_update(
|
async fn handle_update(
|
||||||
config: &ServerConfig,
|
config: &ServerConfig,
|
||||||
user: &RegisteredUser,
|
user: &RegisteredUser,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use nom::combinator::opt;
|
use nom::combinator::{all_consuming, opt};
|
||||||
|
|
||||||
/// Client-to-server command.
|
/// Client-to-server command.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -60,8 +60,8 @@ pub enum ClientMessage {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
|
pub fn client_message(input: &str) -> Result<ClientMessage, anyhow::Error> {
|
||||||
alt((
|
let (_, m) = all_consuming(alt((
|
||||||
client_message_capability,
|
client_message_capability,
|
||||||
client_message_ping,
|
client_message_ping,
|
||||||
client_message_pong,
|
client_message_pong,
|
||||||
|
@ -75,7 +75,8 @@ pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
client_message_part,
|
client_message_part,
|
||||||
client_message_privmsg,
|
client_message_privmsg,
|
||||||
client_message_quit,
|
client_message_quit,
|
||||||
))(input)
|
)))(input)?;
|
||||||
|
Ok(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_message_capability(input: &str) -> IResult<&str, ClientMessage> {
|
fn client_message_capability(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
|
@ -89,24 +90,14 @@ fn client_message_ping(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
let (input, _) = tag("PING ")(input)?;
|
let (input, _) = tag("PING ")(input)?;
|
||||||
let (input, token) = token(input)?;
|
let (input, token) = token(input)?;
|
||||||
|
|
||||||
Ok((
|
Ok((input, ClientMessage::Ping { token: token.into() }))
|
||||||
input,
|
|
||||||
ClientMessage::Ping {
|
|
||||||
token: token.into(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_message_pong(input: &str) -> IResult<&str, ClientMessage> {
|
fn client_message_pong(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
let (input, _) = tag("PONG ")(input)?;
|
let (input, _) = tag("PONG ")(input)?;
|
||||||
let (input, token) = token(input)?;
|
let (input, token) = token(input)?;
|
||||||
|
|
||||||
Ok((
|
Ok((input, ClientMessage::Pong { token: token.into() }))
|
||||||
input,
|
|
||||||
ClientMessage::Pong {
|
|
||||||
token: token.into(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_message_nick(input: &str) -> IResult<&str, ClientMessage> {
|
fn client_message_nick(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
|
@ -225,12 +216,7 @@ fn client_message_quit(input: &str) -> IResult<&str, ClientMessage> {
|
||||||
let (input, _) = tag("QUIT :")(input)?;
|
let (input, _) = tag("QUIT :")(input)?;
|
||||||
let (input, reason) = token(input)?;
|
let (input, reason) = token(input)?;
|
||||||
|
|
||||||
Ok((
|
Ok((input, ClientMessage::Quit { reason: reason.into() }))
|
||||||
input,
|
|
||||||
ClientMessage::Quit {
|
|
||||||
reason: reason.into(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -292,9 +278,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_message_ping() {
|
fn test_client_message_ping() {
|
||||||
let input = "PING 1337";
|
let input = "PING 1337";
|
||||||
let expected = ClientMessage::Ping {
|
let expected = ClientMessage::Ping { token: "1337".into() };
|
||||||
token: "1337".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = client_message(input);
|
let result = client_message(input);
|
||||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||||
|
@ -302,9 +286,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_message_pong() {
|
fn test_client_message_pong() {
|
||||||
let input = "PONG 1337";
|
let input = "PONG 1337";
|
||||||
let expected = ClientMessage::Pong {
|
let expected = ClientMessage::Pong { token: "1337".into() };
|
||||||
token: "1337".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = client_message(input);
|
let result = client_message(input);
|
||||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||||
|
|
|
@ -104,7 +104,7 @@ mod test {
|
||||||
use assert_matches::*;
|
use assert_matches::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::testkit::*;
|
use crate::{testkit::*, client::client_message};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chan_global() {
|
fn test_chan_global() {
|
||||||
|
@ -153,4 +153,10 @@ mod test {
|
||||||
|
|
||||||
assert_eq!(bytes.as_slice(), input.as_bytes());
|
assert_eq!(bytes.as_slice(), input.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_aa() {
|
||||||
|
dbg!(client_message("PING asd"));
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use quick_xml::events::Event;
|
use quick_xml::events::Event;
|
||||||
use quick_xml::name::ResolveResult;
|
use quick_xml::name::ResolveResult;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
|
||||||
use crate::xml::*;
|
use crate::xml::*;
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
pub const XMLNS: &'static str = "http://jabber.org/protocol/muc";
|
pub const XMLNS: &'static str = "http://jabber.org/protocol/muc";
|
||||||
|
|
||||||
|
@ -20,8 +22,8 @@ impl FromXml for History {
|
||||||
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||||
let mut history = History::default();
|
let mut history = History::default();
|
||||||
let (bytes, end) = match event {
|
let (bytes, end) = match event {
|
||||||
Event::Start(bytes) => (bytes, false),
|
Event::Start(bytes) if bytes.name().0 == Self::NAME.as_bytes() => (bytes, false),
|
||||||
Event::Empty(bytes) => (bytes, true),
|
Event::Empty(bytes) if bytes.name().0 == Self::NAME.as_bytes() => (bytes, true),
|
||||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||||
};
|
};
|
||||||
for attr in bytes.attributes() {
|
for attr in bytes.attributes() {
|
||||||
|
@ -72,14 +74,16 @@ impl FromXml for Password {
|
||||||
|
|
||||||
fn parse() -> Self::P {
|
fn parse() -> Self::P {
|
||||||
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||||
let Event::Start(bytes) = event else {
|
let bytes = match event {
|
||||||
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
Event::Start(bytes) if bytes.name().0 == Self::NAME.as_bytes() => bytes,
|
||||||
|
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||||
};
|
};
|
||||||
let (namespace, event) = yield;
|
let (namespace, event) = yield;
|
||||||
let Event::Text(bytes) = event else {
|
let Event::Text(bytes) = event else {
|
||||||
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||||
};
|
};
|
||||||
let s = std::str::from_utf8(bytes)?.to_string();
|
let s = std::str::from_utf8(bytes)?.to_string();
|
||||||
|
let (namespace, event) = yield;
|
||||||
let Event::End(bytes) = event else {
|
let Event::End(bytes) = event else {
|
||||||
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
return Err(anyhow!("Unexpected XML event: {event:?}"));
|
||||||
};
|
};
|
||||||
|
@ -106,7 +110,7 @@ impl FromXml for X {
|
||||||
fn parse() -> Self::P {
|
fn parse() -> Self::P {
|
||||||
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
|
||||||
let mut res = X::default();
|
let mut res = X::default();
|
||||||
let (bytes, end) = match event {
|
let (_, end) = match event {
|
||||||
Event::Start(bytes) => (bytes, false),
|
Event::Start(bytes) => (bytes, false),
|
||||||
Event::Empty(bytes) => (bytes, true),
|
Event::Empty(bytes) => (bytes, true),
|
||||||
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
|
||||||
|
@ -138,3 +142,90 @@ impl FromXml for X {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_success_empty() {
|
||||||
|
let input = "<history/>";
|
||||||
|
let res: History = parse(input).unwrap();
|
||||||
|
let expected = History {
|
||||||
|
maxchars: None,
|
||||||
|
maxstanzas: None,
|
||||||
|
seconds: None,
|
||||||
|
};
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_success_empty_attrs() {
|
||||||
|
let input = r#"<history maxchars="1" maxstanzas="2" seconds="4"/>"#;
|
||||||
|
let res: History = parse(input).unwrap();
|
||||||
|
let expected = History {
|
||||||
|
maxchars: Some(1),
|
||||||
|
maxstanzas: Some(2),
|
||||||
|
seconds: Some(4),
|
||||||
|
};
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_success_start_end() {
|
||||||
|
let input = r#"<history></history>"#;
|
||||||
|
let res: History = parse(input).unwrap();
|
||||||
|
let expected = History {
|
||||||
|
maxchars: None,
|
||||||
|
maxstanzas: None,
|
||||||
|
seconds: None,
|
||||||
|
};
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_incorrect_empty() {
|
||||||
|
let input = r#"<iq/>"#;
|
||||||
|
parse::<History>(input).err().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_password_success() {
|
||||||
|
let input = "<password>olala</password>";
|
||||||
|
let res: Password = parse(input).unwrap();
|
||||||
|
let expected = Password("olala".into());
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_password_incorrect() {
|
||||||
|
let input = r#"<iq>asdsd</iq>"#;
|
||||||
|
parse::<Password>(input).err().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_x_success_empty() {
|
||||||
|
let input = "<x/>";
|
||||||
|
let res: X = parse(input).unwrap();
|
||||||
|
let expected = X {
|
||||||
|
history: None,
|
||||||
|
password: None,
|
||||||
|
};
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_x_success_full() {
|
||||||
|
let input = r#"<x><password>ololo</password><history maxchars="1"/></x>"#;
|
||||||
|
let res: X = parse(input).unwrap();
|
||||||
|
let expected = X {
|
||||||
|
history: Some(History {
|
||||||
|
maxchars: Some(1),
|
||||||
|
maxstanzas: None,
|
||||||
|
seconds: None,
|
||||||
|
}),
|
||||||
|
password: Some(Password("ololo".into())),
|
||||||
|
};
|
||||||
|
assert_eq!(res, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl Parser for IgnoreParser {
|
||||||
|
|
||||||
fn consume<'a>(
|
fn consume<'a>(
|
||||||
self: Self,
|
self: Self,
|
||||||
namespace: ResolveResult,
|
_: ResolveResult,
|
||||||
event: &Event<'a>,
|
event: &Event<'a>,
|
||||||
) -> Continuation<Self, Self::Output> {
|
) -> Continuation<Self, Self::Output> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
|
@ -58,5 +58,5 @@ impl FromXml for Ignore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToXml for () {
|
impl ToXml for () {
|
||||||
fn serialize(&self, events: &mut Vec<Event<'static>>) {}
|
fn serialize(&self, _: &mut Vec<Event<'static>>) {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue