🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2021-01-26 23:52:55.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2021-01-26 23:52:55.0 +00:00:00
commit
6d638389fdd519ac65bef8bc93ff4718b6277aae [patch]
tree
f6ef48de29e6ea84160508ce62f5ea1e765eb1bf
parent
c3eb52e5dd4980c6cba7abf05761c5bcb4d3fcb1
download
6d638389fdd519ac65bef8bc93ff4718b6277aae.tar.gz

Add a simple PRIVMSG test



Diff

 titanirc-codec/src/lib.rs        |  3 +++
 titanirc-codec/src/wire.rs       | 23 +++++++++++------------
 titanirc-server/src/main.rs      |  3 +++
 titanirc-server/src/server.rs    |  2 +-
 titanirc-server/src/session.rs   |  2 +-
 titanirc-types/src/lib.rs        | 31 +++++++++++++++++++++++++++----
 titanirc-types/src/primitives.rs | 20 +++++++-------------
 7 files changed, 53 insertions(+), 31 deletions(-)

diff --git a/titanirc-codec/src/lib.rs b/titanirc-codec/src/lib.rs
index 0ea1a5c..bb3d677 100644
--- a/titanirc-codec/src/lib.rs
+++ b/titanirc-codec/src/lib.rs
@@ -1,3 +1,6 @@
#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

mod wire;

pub use crate::wire::Decoder;
diff --git a/titanirc-codec/src/wire.rs b/titanirc-codec/src/wire.rs
index ea36387..eb9548e 100644
--- a/titanirc-codec/src/wire.rs
+++ b/titanirc-codec/src/wire.rs
@@ -11,19 +11,18 @@ impl FrameDecoder for Decoder {
    type Error = std::io::Error;

    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
        let length = match find_crlf(src) {
            Some(len) => len,
            None => {
                if src.len() > MAX_LENGTH {
                    return Err(std::io::Error::new(
                        std::io::ErrorKind::InvalidData,
                        format!("Frame of length {} is too large.", src.len()),
                    ));
                }

                // tell Framed we need more bytes
                return Ok(None);
        let length = if let Some(len) = find_crlf(src) {
            len
        } else {
            if src.len() > MAX_LENGTH {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::InvalidData,
                    format!("Frame of length {} is too large.", src.len()),
                ));
            }

            // tell Framed we need more bytes
            return Ok(None);
        };

        let bytes = src.copy_to_bytes(length + 1);
diff --git a/titanirc-server/src/main.rs b/titanirc-server/src/main.rs
index 05d9419..95f8781 100644
--- a/titanirc-server/src/main.rs
+++ b/titanirc-server/src/main.rs
@@ -1,3 +1,6 @@
#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

mod error;
mod server;
mod session;
diff --git a/titanirc-server/src/server.rs b/titanirc-server/src/server.rs
index dda6d22..9740800 100644
--- a/titanirc-server/src/server.rs
+++ b/titanirc-server/src/server.rs
@@ -23,7 +23,7 @@ impl Handler<Connection> for Server {
        println!("Accepted connection from {}", remote);

        Session::create(move |ctx| {
            let (read, write) = tokio::io::split(stream);
            let (read, _write) = tokio::io::split(stream);
            Session::add_stream(FramedRead::new(read, titanirc_codec::Decoder), ctx);
            Session {}
        });
diff --git a/titanirc-server/src/session.rs b/titanirc-server/src/session.rs
index c74bd3a..8482c46 100644
--- a/titanirc-server/src/session.rs
+++ b/titanirc-server/src/session.rs
@@ -9,7 +9,7 @@ impl Actor for Session {

impl StreamHandler<Result<Command, std::io::Error>> for Session {
    /// This is main event loop for client requests
    fn handle(&mut self, cmd: Result<Command, std::io::Error>, ctx: &mut Self::Context) {
    fn handle(&mut self, cmd: Result<Command, std::io::Error>, _ctx: &mut Self::Context) {
        match cmd {
            Ok(cmd) => println!("cmd: {:?}", cmd),
            Err(e) => eprintln!("error decoding: {}", e),
diff --git a/titanirc-types/src/lib.rs b/titanirc-types/src/lib.rs
index e439c45..ec6c621 100644
--- a/titanirc-types/src/lib.rs
+++ b/titanirc-types/src/lib.rs
@@ -1,3 +1,6 @@
#![deny(clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

mod primitives;

pub use crate::primitives::*;
@@ -16,14 +19,12 @@ macro_rules! define_commands {
                $([<$name:camel>]([<$name:camel Command>])),*
            }

            $(const [<$name _BYTES>]: &[u8] = stringify!($name).as_bytes();)*

            impl Command {
                pub fn parse(input: &[u8]) -> Result<Option<Self>, nom::Err<nom::error::Error<&[u8]>>> {
                    let (rest, kind) = nom::bytes::complete::take_till(|c| c == b' ')(input)?;

                    $(const [<$name _BYTES>]: &[u8] = stringify!($name).as_bytes();)*

                    eprintln!("kind: {:?}", std::str::from_utf8(kind));

                    match kind {
                        $([<$name _BYTES>] => Ok(Some(Self::[<$name:camel>]([<$name:camel Command>]::parse(rest)?)))),*,
                        _ => Ok(None)
@@ -38,6 +39,7 @@ macro_rules! define_commands {
                }

                impl [<$name:camel Command>] {
                    #[allow(unused_variables)]
                    pub fn parse(rest: &[u8]) -> Result<Self, nom::Err<nom::error::Error<&[u8]>>> {
                        $(
                            $(
@@ -72,3 +74,24 @@ define_commands! {

    PRIVMSG(Receiver, Message),
}

#[cfg(test)]
mod tests {
    use super::Command;

    #[test]
    fn parse_empty() {
        assert!(matches!(Command::parse(b""), Ok(None)));
    }

    #[test]
    fn parse_privmsg() {
        assert!(matches!(
            Command::parse(b"PRIVMSG foo :baz"),
            Ok(Some(Command::Privmsg(super::PrivmsgCommand {
                receiver: super::Receiver::User(super::Nick(nick)),
                message: super::Message(msg),
            }))) if nick == "foo" && msg == ":baz"
        ))
    }
}
diff --git a/titanirc-types/src/primitives.rs b/titanirc-types/src/primitives.rs
index 3ba32d5..ed3dcb9 100644
--- a/titanirc-types/src/primitives.rs
+++ b/titanirc-types/src/primitives.rs
@@ -23,33 +23,27 @@ macro_rules! standard_string_parser {
}

#[derive(Debug)]
pub struct Username(String);

pub struct Username(pub(crate) String);
standard_string_parser!(Username);

#[derive(Debug)]
pub struct HostName(String);

pub struct HostName(pub(crate) String);
standard_string_parser!(HostName);

#[derive(Debug)]
pub struct ServerName(String);

pub struct ServerName(pub(crate) String);
standard_string_parser!(ServerName);

#[derive(Debug)]
pub struct RealName(String);

pub struct RealName(pub(crate) String);
standard_string_parser!(RealName);

#[derive(Debug)]
pub struct Nick(String);

pub struct Nick(pub(crate) String);
standard_string_parser!(Nick);

#[derive(Debug)]
pub struct Channel(String);

pub struct Channel(pub(crate) String);
standard_string_parser!(Channel);

#[derive(Debug)]
@@ -73,7 +67,7 @@ impl PrimitiveParser for Receiver {
}

#[derive(Debug)]
pub struct Message(String);
pub struct Message(pub(crate) String);

impl PrimitiveParser for Message {
    fn parse(bytes: &[u8]) -> IResult<&[u8], Self> {