use std::sync::atomic::{AtomicU64, Ordering};
pub fn key(prefix: &str) -> String {
static COUNTER: AtomicU64 = AtomicU64::new(0);
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
let t = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
format!("{prefix}:{t}:{n}")
}
pub fn tkey(tag: &str, name: &str) -> String {
static COUNTER: AtomicU64 = AtomicU64::new(0);
let n = COUNTER.fetch_add(1, Ordering::Relaxed);
let t = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
format!("{{{tag}}}:{name}:{t}:{n}")
}
fn parse_version(s: &str) -> Option<(u32, u32, u32)> {
let mut it = s.trim().split('.');
let major = it.next()?.parse().ok()?;
let minor = it.next().unwrap_or("0").parse().unwrap_or(0);
let patch = it
.next()
.unwrap_or("0")
.chars()
.take_while(|c| c.is_ascii_digit())
.collect::<String>()
.parse()
.unwrap_or(0);
Some((major, minor, patch))
}
fn collect_value_text(v: &glide::Value, out: &mut String) {
use glide::Value;
match v {
Value::BulkString(b) => {
out.push_str(&String::from_utf8_lossy(b));
out.push('\n');
}
Value::SimpleString(s) => {
out.push_str(s);
out.push('\n');
}
Value::VerbatimString { text, .. } => {
out.push_str(text);
out.push('\n');
}
Value::Array(items) | Value::Set(items) => {
for it in items {
collect_value_text(it, out);
}
}
Value::Map(pairs) => {
for (k, val) in pairs {
collect_value_text(k, out);
collect_value_text(val, out);
}
}
_ => {}
}
}
pub async fn server_version<C>(c: &C) -> Option<(u32, u32, u32)>
where
C: glide::CustomCommand + Sync,
{
let reply = c.custom_command(&["INFO", "server"]).await.ok()?;
let mut text = String::new();
collect_value_text(&reply, &mut text);
for key in ["valkey_version:", "redis_version:"] {
for line in text.lines() {
if let Some(v) = line.trim().strip_prefix(key) {
return parse_version(v);
}
}
}
None
}
pub async fn command_exists<C>(c: &C, name: &str) -> bool
where
C: glide::CustomCommand + Sync,
{
match c.custom_command(&["COMMAND", "INFO", name]).await {
Ok(v) => command_info_present(&v),
Err(_) => false,
}
}
fn command_info_present(v: &glide::Value) -> bool {
use glide::Value;
match v {
Value::Array(items) => items
.iter()
.any(|it| matches!(it, Value::Array(inner) if !inner.is_empty())),
Value::Map(pairs) => pairs.iter().any(|(_, val)| command_info_present(val)),
_ => false,
}
}
pub async fn version_below<C>(c: &C, min: (u32, u32, u32)) -> bool
where
C: glide::CustomCommand + Sync,
{
match server_version(c).await {
Some(v) => v < min,
None => false,
}
}