feat(redis): support MONITOR live command log
This commit is contained in:
25 files changed
+439
-7
No files matched your search
@@ -1121,6 +1121,35 @@ pub async fn connect_direct_node(
|
||||
connect_client(client).await
|
||||
}
|
||||
|
||||
pub async fn connect_monitor(
|
||||
config: &ConnectionConfig,
|
||||
host: &str,
|
||||
port: u16,
|
||||
timeout: std::time::Duration,
|
||||
) -> Result<redis::aio::Monitor, String> {
|
||||
let mut last_error = String::new();
|
||||
for info in standalone_connection_infos(config, host, port) {
|
||||
let client = redis::Client::open(info).map_err(|error| error.to_string())?;
|
||||
let connect = async {
|
||||
let mut validation = client.get_multiplexed_async_connection().await?;
|
||||
redis::cmd("MONITOR").query_async::<()>(&mut validation).await?;
|
||||
drop(validation);
|
||||
client.get_async_monitor().await
|
||||
};
|
||||
match tokio::time::timeout(timeout, connect).await {
|
||||
Ok(Ok(monitor)) => return Ok(monitor),
|
||||
Ok(Err(error)) => {
|
||||
last_error = error.to_string();
|
||||
if !is_redis_auth_error(&last_error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(_) => return Err("Redis MONITOR connection timed out".to_string()),
|
||||
}
|
||||
}
|
||||
Err(last_error)
|
||||
}
|
||||
|
||||
pub async fn connect_pubsub(
|
||||
config: &ConnectionConfig,
|
||||
host: &str,
|
||||
@@ -2218,6 +2247,11 @@ where
|
||||
{
|
||||
let argv = parse_command_argv(command_text)?;
|
||||
let command = argv[0].to_ascii_uppercase();
|
||||
if command == "MONITOR" {
|
||||
return Err(
|
||||
"MONITOR requires a dedicated streaming connection; run MONITOR alone in the query editor".to_string()
|
||||
);
|
||||
}
|
||||
let safety = classify_command(&command);
|
||||
if !skip_safety_check && safety == RedisCommandSafety::Blocked {
|
||||
return Err(format!("Redis command is blocked for safety: {command}"));
|
||||
|
||||
@@ -1141,6 +1141,28 @@ pub async fn redis_publish_core(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn redis_create_monitor_core(state: &AppState, connection_id: &str) -> Result<redis::aio::Monitor, String> {
|
||||
let config = state.configs.read().await.get(connection_id).ok_or("Connection config not found")?.clone();
|
||||
if config.db_type != crate::models::connection::DatabaseType::Redis {
|
||||
return Err("Not a Redis connection".to_string());
|
||||
}
|
||||
if config.uses_redis_sentinel() || config.uses_redis_cluster() {
|
||||
return Err(
|
||||
"MONITOR requires a direct Redis node connection; connect to the node you want to monitor".to_string()
|
||||
);
|
||||
}
|
||||
let (host, port) = state.connection_host_port(connection_id, &config).await?;
|
||||
let mut runtime_config = config.clone();
|
||||
state.apply_session_credential(&config, &mut runtime_config, connection_id);
|
||||
redis_driver::connect_monitor(
|
||||
&runtime_config,
|
||||
&host,
|
||||
port,
|
||||
std::time::Duration::from_secs(config.effective_connect_timeout_secs()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn redis_create_pubsub_core(state: &AppState, connection_id: &str) -> Result<redis::aio::PubSub, String> {
|
||||
let configs = state.configs.read().await;
|
||||
let config = configs.get(connection_id).ok_or("Connection config not found")?.clone();
|
||||
|
||||
Reference in new issue
Block a user