diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 33 | ||||
| -rw-r--r-- | src/macros.rs | 95 | ||||
| -rw-r--r-- | src/resp_commands.rs | 20 |
3 files changed, 130 insertions, 18 deletions
@@ -1,4 +1,9 @@ +use resp_parser::RespType; use std::{env, sync::Arc}; +use std::{ + io::{Read, Write}, + net::{TcpListener, TcpStream}, +}; #[macro_use] pub mod macros; @@ -40,6 +45,25 @@ pub struct Config { pub server: RedisServer, } +fn handshake_process(slave: &RedisServer) -> Result<(), String> { + let master_address = format!("{}:{}", slave.master_host, slave.master_port); + // PING + match TcpStream::connect(master_address) { + Ok(mut stream) => { + if let Err(e) = stream.write_all(&resp_bytes!(array => [resp!(bulk "PING")])) { + return Err(format!("Failed to send: {}", e)); + } else { + Ok(()) + } + } + Err(e) => Err(format!("Master node doesn't exists: {}", e)), + } + + // REPLCONF + + // PSYNC +} + pub type SharedConfig = Arc<Option<Config>>; impl Config { @@ -86,11 +110,7 @@ impl Config { // TODO: Find a better name for this variable let info = args[i + 1].clone(); - let (master_host, master_port) = info - .strip_prefix('"') - .and_then(|x| x.strip_suffix('"')) - .and_then(|x| x.split_once(' ')) - .unwrap_or(("", "")); + let (master_host, master_port) = info.split_once(' ').unwrap(); redis_server.role = "slave".to_string(); @@ -100,6 +120,9 @@ impl Config { redis_server.master_host = master_host.to_string(); redis_server.master_port = master_port.to_string(); + + handshake_process(&redis_server)?; + i += 2; } _ => { diff --git a/src/macros.rs b/src/macros.rs index 96b5e09..9dbad5d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,5 +1,5 @@ #[macro_export] -macro_rules! resp { +macro_rules! resp_bytes { // Null: resp!(null) (null) => { RespType::Null().to_resp_bytes() @@ -28,9 +28,9 @@ macro_rules! resp { RespType::BulkString($s.into()).to_resp_bytes() }; - // Array: resp!(array [resp!("one"), resp!(int 2)]) + // Array: resp!(array => [resp!(bulk "one"), resp!(int 2)]) // FIXME: this doesn't work and errors - (array [$($elem:expr),*]) => { + (array => [$($elem:expr),*]) => { RespType::Array(vec![$($elem),*]).to_resp_bytes() }; @@ -87,3 +87,92 @@ macro_rules! resp { RespType::Pushes(vec![$($elem),*]).to_resp_bytes() }; } + +macro_rules! resp { + // Null: resp!(null) + (null) => { + RespType::Null() + }; + + // Simple String: resp!("PONG") or resp!(simple "PONG") + (simple $s:expr) => { + RespType::SimpleString($s.to_string()) + }; + ($s:expr) => { + RespType::SimpleString($s.to_string()) + }; + + // Simple Error: resp!(error "ERR message") + (error $s:expr) => { + RespType::SimpleError($s.to_string()) + }; + + // Integer: resp!(int 123) + (int $i:expr) => { + RespType::Integer($i) + }; + + // Bulk String: resp!(bulk "hello") or resp!(bulk vec![104, 101, 108, 108, 111]) + (bulk $s:expr) => { + RespType::BulkString($s.into()) + }; + + // Array: resp!(array => [resp!(bulk "one"), resp!(int 2)]) + // FIXME: this doesn't work and errors + (array => [$($elem:expr),*]) => { + RespType::Array(vec![$($elem),*]) + }; + + // Boolean: resp!(bool true) + (bool $b:expr) => { + RespType::Boolean($b) + }; + + // Double: resp!(double 3.14) + (double $d:expr) => { + RespType::Doubles($d) + }; + + // Big Number: resp!(bignumber "123456789") + (bignumber $n:expr) => { + RespType::BigNumbers($n.to_string()) + }; + + // Bulk Error: resp!(bulkerror [resp!("err1"), resp!("err2")]) + (bulkerror [$($elem:expr),*]) => { + RespType::BulkErrors(vec![$($elem),*]) + }; + + // Verbatim String: resp!(verbatim [resp!("txt"), resp!("example")]) + (verbatim [$($elem:expr),*]) => { + RespType::VerbatimStrings(vec![$($elem),*]) + }; + + // Map: resp!(map {resp!("key") => resp!("value")}) + (map {$($key:expr => $value:expr),*}) => { + RespType::Maps({ + let mut map = HashMap::new(); + $(map.insert($key, $value);)* + map + }) + }; + + // Attributes: resp!(attributes [resp!("key"), resp!("value")]) + (attributes [$($elem:expr),*]) => { + RespType::Attributes(vec![$($elem),*]) + }; + + // Set: resp!(set [resp!("one"), resp!("two")]) + (set [$($elem:expr),*]) => { + RespType::Sets({ + let mut set = HashSet::new(); + $(set.insert($elem);)* + set + }) + }; + + // Push: resp!(push [resp!("event"), resp!("data")]) + (push [$($elem:expr),*]) => { + RespType::Pushes(vec![$($elem),*]) + }; +} diff --git a/src/resp_commands.rs b/src/resp_commands.rs index 2c9c09c..554c296 100644 --- a/src/resp_commands.rs +++ b/src/resp_commands.rs @@ -124,8 +124,8 @@ impl RedisCommands { pub fn execute(self, cache: SharedCache, config: SharedConfig) -> Vec<u8> { use RedisCommands as RC; match self { - RC::Ping => resp!("PONG"), - RC::Echo(echo_string) => resp!(echo_string), + RC::Ping => resp_bytes!("PONG"), + RC::Echo(echo_string) => resp_bytes!(echo_string), RC::Get(key) => { let mut cache = cache.lock().unwrap(); @@ -133,12 +133,12 @@ impl RedisCommands { Some(entry) => { if entry.is_expired() { cache.remove(&key); // Clean up expired key - resp!(null) + resp_bytes!(null) } else { - resp!(bulk entry.value) + resp_bytes!(bulk entry.value) } } - None => resp!(null), + None => resp_bytes!(null), } } RC::Set(command) => { @@ -149,10 +149,10 @@ impl RedisCommands { match command.condition { Some(SetCondition::NotExists) if key_exists => { - return resp!(null); // Key exists, NX failed + return resp_bytes!(null); // Key exists, NX failed } Some(SetCondition::Exists) if !key_exists => { - return resp!(null); // Key doesn't exist, XX failed + return resp_bytes!(null); // Key doesn't exist, XX failed } _ => {} // No condition or condition met } @@ -186,12 +186,12 @@ impl RedisCommands { ); if !command.get_old_value { - return resp!("OK"); + return resp_bytes!("OK"); } match get_value { - Some(val) => return resp!(bulk val), - None => return resp!(null), + Some(val) => return resp_bytes!(bulk val), + None => return resp_bytes!(null), } } RC::ConfigGet(s) => { |
