aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoromagdy <omar.professional8777@gmail.com>2025-07-23 02:42:31 +0300
committeromagdy <omar.professional8777@gmail.com>2025-07-23 02:42:31 +0300
commit21a90f12690729f3f4aaca64d413e9e5d8dc0bd4 (patch)
treec68d7c6c56e3d4b6db95d4226f8dfb664b3c0dc2 /src
parentd4dbbda97b42bad8a41297ba1c3a693f1fe66902 (diff)
downloadredis-rust-21a90f12690729f3f4aaca64d413e9e5d8dc0bd4.tar.xz
redis-rust-21a90f12690729f3f4aaca64d413e9e5d8dc0bd4.zip
feat: Added first step in handshake process between replicas(slaves) and master nodes
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs33
-rw-r--r--src/macros.rs95
-rw-r--r--src/resp_commands.rs20
3 files changed, 130 insertions, 18 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 8a88674..bb91b2e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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) => {