2019-05-10 07:47:29 +02:00
|
|
|
//! Send raw TCP commands to the Redis server
|
|
|
|
use std::fmt::Display;
|
|
|
|
|
2019-07-06 02:08:50 +02:00
|
|
|
/// Send a subscribe or unsubscribe to the Redis PubSub channel
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! pubsub_cmd {
|
|
|
|
($cmd:expr, $self:expr, $tl:expr) => {{
|
2019-10-02 06:03:18 +02:00
|
|
|
use std::io::Write;
|
|
|
|
log::info!("Sending {} command to {}", $cmd, $tl);
|
2019-07-06 02:08:50 +02:00
|
|
|
$self
|
|
|
|
.pubsub_connection
|
2019-10-03 06:34:41 +02:00
|
|
|
.write_all(&redis_cmd::pubsub($cmd, $tl, $self.redis_namespace.clone()))
|
2019-07-06 02:08:50 +02:00
|
|
|
.expect("Can send command to Redis");
|
2019-10-02 06:03:18 +02:00
|
|
|
// Because we keep track of the number of clients subscribed to a channel on our end,
|
|
|
|
// we need to manually tell Redis when we have subscribed or unsubscribed
|
|
|
|
let subscription_new_number = match $cmd {
|
|
|
|
"unsubscribe" => "0",
|
|
|
|
"subscribe" => "1",
|
|
|
|
_ => panic!("Given unacceptable PUBSUB command"),
|
|
|
|
};
|
2019-07-06 02:08:50 +02:00
|
|
|
$self
|
|
|
|
.secondary_redis_connection
|
|
|
|
.write_all(&redis_cmd::set(
|
|
|
|
format!("subscribed:timeline:{}", $tl),
|
2019-10-02 06:03:18 +02:00
|
|
|
subscription_new_number,
|
2019-10-03 06:34:41 +02:00
|
|
|
$self.redis_namespace.clone(),
|
2019-07-06 02:08:50 +02:00
|
|
|
))
|
|
|
|
.expect("Can set Redis");
|
2019-10-02 06:03:18 +02:00
|
|
|
|
|
|
|
log::info!("Now subscribed to: {:#?}", $self.msg_queues);
|
2019-07-06 02:08:50 +02:00
|
|
|
}};
|
|
|
|
}
|
2019-05-10 07:47:29 +02:00
|
|
|
/// Send a `SUBSCRIBE` or `UNSUBSCRIBE` command to a specific timeline
|
2019-10-03 06:34:41 +02:00
|
|
|
pub fn pubsub(command: impl Display, timeline: impl Display, ns: Option<String>) -> Vec<u8> {
|
|
|
|
let arg = match ns {
|
2019-10-02 06:03:18 +02:00
|
|
|
Some(namespace) => format!("{}:timeline:{}", namespace, timeline),
|
|
|
|
None => format!("timeline:{}", timeline),
|
|
|
|
};
|
|
|
|
cmd(command, arg)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Send a generic two-item command to Redis
|
|
|
|
pub fn cmd(command: impl Display, arg: impl Display) -> Vec<u8> {
|
|
|
|
let (command, arg) = (command.to_string(), arg.to_string());
|
|
|
|
log::info!("Sent {} command", &command);
|
2019-05-10 07:47:29 +02:00
|
|
|
format!(
|
|
|
|
"*2\r\n${cmd_length}\r\n{cmd}\r\n${arg_length}\r\n{arg}\r\n",
|
|
|
|
cmd_length = command.len(),
|
|
|
|
cmd = command,
|
|
|
|
arg_length = arg.len(),
|
|
|
|
arg = arg
|
|
|
|
)
|
|
|
|
.as_bytes()
|
|
|
|
.to_owned()
|
|
|
|
}
|
|
|
|
|
2019-10-02 06:03:18 +02:00
|
|
|
/// Send a `SET` command (used to manually unsubscribe from Redis)
|
2019-10-03 06:34:41 +02:00
|
|
|
pub fn set(key: impl Display, value: impl Display, ns: Option<String>) -> Vec<u8> {
|
|
|
|
let key = match ns {
|
2019-10-02 06:03:18 +02:00
|
|
|
Some(namespace) => format!("{}:{}", namespace, key),
|
|
|
|
None => key.to_string(),
|
|
|
|
};
|
|
|
|
let value = value.to_string();
|
2019-05-10 07:47:29 +02:00
|
|
|
format!(
|
|
|
|
"*3\r\n$3\r\nSET\r\n${key_length}\r\n{key}\r\n${value_length}\r\n{value}\r\n",
|
|
|
|
key_length = key.len(),
|
|
|
|
key = key,
|
|
|
|
value_length = value.len(),
|
|
|
|
value = value
|
|
|
|
)
|
|
|
|
.as_bytes()
|
|
|
|
.to_owned()
|
|
|
|
}
|