diff --git a/src/request/timeline.rs b/src/request/timeline.rs index 39818ec..e6fc9b6 100644 --- a/src/request/timeline.rs +++ b/src/request/timeline.rs @@ -19,25 +19,29 @@ impl Timeline { } pub fn to_redis_raw_timeline(&self, hashtag: Option<&String>) -> Result { - use {Content::*, Reach::*, Stream::*}; + // TODO -- does this need to account for namespaces? + use {Content::*, Reach::*, Stream::*, TimelineErr::*}; + Ok(match self { - Timeline(Public, Federated, All) => "timeline:public".into(), - Timeline(Public, Local, All) => "timeline:public:local".into(), - Timeline(Public, Federated, Media) => "timeline:public:media".into(), - Timeline(Public, Local, Media) => "timeline:public:local:media".into(), - // TODO -- would `.push_str` be faster here? - Timeline(Hashtag(_id), Federated, All) => format!( - "timeline:hashtag:{}", - hashtag.ok_or(TimelineErr::MissingHashtag)? - ), - Timeline(Hashtag(_id), Local, All) => format!( - "timeline:hashtag:{}:local", - hashtag.ok_or(TimelineErr::MissingHashtag)? - ), - Timeline(User(id), Federated, All) => format!("timeline:{}", id), - Timeline(User(id), Federated, Notification) => format!("timeline:{}:notification", id), - Timeline(List(id), Federated, All) => format!("timeline:list:{}", id), - Timeline(Direct(id), Federated, All) => format!("timeline:direct:{}", id), + Timeline(Public, Federated, All) => "timeline:public".to_string(), + Timeline(Public, Local, All) => "timeline:public:local".to_string(), + Timeline(Public, Federated, Media) => "timeline:public:media".to_string(), + Timeline(Public, Local, Media) => "timeline:public:local:media".to_string(), + Timeline(Hashtag(_id), Federated, All) => { + ["timeline:hashtag:", hashtag.ok_or(MissingHashtag)?].concat() + } + Timeline(Hashtag(_id), Local, All) => [ + "timeline:hashtag:", + hashtag.ok_or(MissingHashtag)?, + ":local", + ] + .concat(), + Timeline(User(id), Federated, All) => ["timeline:", &id.to_string()].concat(), + Timeline(User(id), Federated, Notification) => { + ["timeline:", &id.to_string(), ":notification"].concat() + } + Timeline(List(id), Federated, All) => ["timeline:list:", &id.to_string()].concat(), + Timeline(Direct(id), Federated, All) => ["timeline:direct:", &id.to_string()].concat(), Timeline(_one, _two, _three) => Err(TimelineErr::InvalidInput)?, }) } @@ -57,8 +61,7 @@ impl Timeline { [id, "notification"] => Timeline(User(id.parse()?), Federated, Notification), ["list", id] => Timeline(List(id.parse()?), Federated, All), ["direct", id] => Timeline(Direct(id.parse()?), Federated, All), - // Other endpoints don't exist: - [..] => Err(InvalidInput)?, + [..] => Err(InvalidInput)?, // Other endpoints don't exist }) } diff --git a/src/response/redis.rs b/src/response/redis.rs index 3405f62..87db129 100644 --- a/src/response/redis.rs +++ b/src/response/redis.rs @@ -15,12 +15,40 @@ impl RedisCmd { pub fn into_sendable(self, tl: &str) -> (Vec, Vec) { match self { RedisCmd::Subscribe => ( - format!("*2\r\n$9\r\nsubscribe\r\n${}\r\n{}\r\n", tl.len(), tl).into_bytes(), - format!("*3\r\n$3\r\nSET\r\n${}\r\n{}\r\n$1\r\n1\r\n", tl.len(), tl).into_bytes(), + [ + b"*2\r\n$9\r\nsubscribe\r\n$", + tl.len().to_string().as_bytes(), + b"\r\n", + tl.as_bytes(), + b"\r\n", + ] + .concat(), + [ + b"*3\r\n$3\r\nSET\r\n$", + tl.len().to_string().as_bytes(), + b"\r\n", + tl.as_bytes(), + b"\r\n$1\r\n1\r\n", + ] + .concat(), ), RedisCmd::Unsubscribe => ( - format!("*2\r\n$11\r\nunsubscribe\r\n${}\r\n{}\r\n", tl.len(), tl).into_bytes(), - format!("*3\r\n$3\r\nSET\r\n${}\r\n{}\r\n$1\r\n0\r\n", tl.len(), tl).into_bytes(), + [ + b"*2\r\n$11\r\nunsubscribe\r\n$", + tl.len().to_string().as_bytes(), + b"\r\n", + tl.as_bytes(), + b"\r\n", + ] + .concat(), + [ + b"*3\r\n$3\r\nSET\r\n$", + tl.len().to_string().as_bytes(), + b"\r\n", + tl.as_bytes(), + b"\r\n$1\r\n0\r\n", + ] + .concat(), ), } } diff --git a/src/response/redis/connection.rs b/src/response/redis/connection.rs index 58f142a..f4b2dd1 100644 --- a/src/response/redis/connection.rs +++ b/src/response/redis/connection.rs @@ -29,7 +29,8 @@ pub struct RedisConn { impl RedisConn { pub fn new(redis_cfg: &Redis) -> Result { - let addr = format!("{}:{}", *redis_cfg.host, *redis_cfg.port); + let addr = [&*redis_cfg.host, ":", &*redis_cfg.port.to_string()].concat(); + let conn = Self::new_connection(&addr, redis_cfg.password.as_ref())?; conn.set_nonblocking(true) .map_err(|e| RedisConnErr::with_addr(&addr, e))?; @@ -81,7 +82,7 @@ impl RedisConn { use {Async::*, RedisParseOutput::*}; let (res, leftover) = match RedisParseOutput::try_from(input) { Ok(Msg(msg)) => match &self.redis_namespace { - Some(ns) if msg.timeline_txt.starts_with(&format!("{}:timeline:", ns)) => { + Some(ns) if msg.timeline_txt.starts_with(&[ns, ":timeline:"].concat()) => { let trimmed_tl = &msg.timeline_txt[ns.len() + ":timeline:".len()..]; let tl = Timeline::from_redis_text(trimmed_tl, &mut self.tag_id_cache)?; let event = msg.event_txt.try_into()?; @@ -135,8 +136,17 @@ impl RedisConn { } fn auth_connection(conn: &mut TcpStream, addr: &str, pass: &str) -> Result<()> { - conn.write_all(&format!("*2\r\n$4\r\nauth\r\n${}\r\n{}\r\n", pass.len(), pass).as_bytes()) - .map_err(|e| RedisConnErr::with_addr(&addr, e))?; + conn.write_all( + &[ + b"*2\r\n$4\r\nauth\r\n$", + pass.len().to_string().as_bytes(), + b"\r\n", + pass.as_bytes(), + b"\r\n", + ] + .concat(), + ) + .map_err(|e| RedisConnErr::with_addr(&addr, e))?; let mut buffer = vec![0_u8; 5]; conn.read_exact(&mut buffer) .map_err(|e| RedisConnErr::with_addr(&addr, e))?; diff --git a/src/response/redis/msg.rs b/src/response/redis/msg.rs index f1f0370..0a592d5 100644 --- a/src/response/redis/msg.rs +++ b/src/response/redis/msg.rs @@ -82,10 +82,7 @@ fn utf8_to_redis_data<'a>(s: &'a str) -> Result<(RedisData, &'a str), RedisParse ":" => parse_redis_int(s), "$" => parse_redis_bulk_string(s), "*" => parse_redis_array(s), - e => Err(InvalidLineStart(format!( - "Encountered invalid initial character `{}` in line `{}`", - e, s - ))), + e => Err(InvalidLineStart(e.to_string())), } }