use crate::{
ClientError, Error, Result,
client::{PreparedCommand, prepare_command},
resp::{CommandArgsMut, Response, cmd, serialize_flag},
};
use serde::{
Deserialize, Deserializer, Serialize,
de::{self, SeqAccess, Visitor},
};
use smallvec::SmallVec;
use std::{collections::HashMap, fmt, str::FromStr};
pub trait ServerCommands<'a>: Sized {
fn acl_cat<R: Response>(self, options: AclCatOptions) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("ACL").arg("CAT").arg(options))
}
fn acl_deluser(self, usernames: impl Serialize) -> PreparedCommand<'a, Self, usize> {
prepare_command(
self,
cmd("ACL").arg("DELUSER").arg(usernames).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AllSucceeded,
1,
),
)
}
fn acl_dryrun<R: Response>(
self,
username: impl Serialize,
command: impl Serialize,
options: AclDryRunOptions,
) -> PreparedCommand<'a, Self, R> {
prepare_command(
self,
cmd("ACL")
.arg("DRYRUN")
.arg(username)
.arg(command)
.arg(options),
)
}
fn acl_genpass<R: Response>(self, options: AclGenPassOptions) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("ACL").arg("GENPASS").arg(options))
}
fn acl_getuser<R: Response>(self, username: impl Serialize) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("ACL").arg("GETUSER").arg(username))
}
fn acl_help<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(self, cmd("ACL").arg("HELP"))
}
fn acl_list<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(self, cmd("ACL").arg("LIST"))
}
fn acl_load(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("ACL").arg("LOAD"))
}
fn acl_log<R: Response>(self, options: AclLogOptions) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("ACL").arg("LOG").arg(options))
}
fn acl_save(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("ACL").arg("SAVE").cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AllSucceeded,
1,
),
)
}
fn acl_setuser(
self,
username: impl Serialize,
rules: impl Serialize,
) -> PreparedCommand<'a, Self, ()> {
prepare_command(
self,
cmd("ACL")
.arg("SETUSER")
.arg(username)
.arg(rules)
.cluster_info(RequestPolicy::AllNodes, ResponsePolicy::AllSucceeded, 1),
)
}
fn acl_users<R: Response>(self) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("ACL").arg("USERS"))
}
fn acl_whoami<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(self, cmd("ACL").arg("WHOAMI"))
}
fn bgrewriteaof<R: Response>(self) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("BGREWRITEAOF"))
}
fn bgsave<R: Response>(self, options: BgsaveOptions) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("BGSAVE").arg(options))
}
fn command(self) -> PreparedCommand<'a, Self, Vec<CommandInfo>>
where
Self: Sized,
{
prepare_command(self, cmd("COMMAND"))
}
fn command_count(self) -> PreparedCommand<'a, Self, usize>
where
Self: Sized,
{
prepare_command(self, cmd("COMMAND").arg("COUNT"))
}
fn command_docs<R: Response>(
self,
command_names: impl Serialize,
) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("COMMAND").arg("DOCS").arg(command_names))
}
fn command_getkeys<R: Response>(self, args: impl Serialize) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("COMMAND").arg("GETKEYS").arg(args))
}
fn command_getkeysandflags<R: Response>(
self,
args: impl Serialize,
) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("COMMAND").arg("GETKEYSANDFLAGS").arg(args))
}
fn command_help<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(self, cmd("COMMAND").arg("HELP"))
}
fn command_info(
self,
command_names: impl Serialize,
) -> PreparedCommand<'a, Self, Vec<CommandInfo>> {
prepare_command(self, cmd("COMMAND").arg("INFO").arg(command_names))
}
fn command_list<R: Response>(
self,
options: CommandListOptions,
) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("COMMAND").arg("LIST").arg(options))
}
#[must_use]
fn config_get<R: Response>(self, params: impl Serialize) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("CONFIG").arg("GET").arg(params))
}
#[must_use]
fn config_help(self) -> PreparedCommand<'a, Self, Vec<String>>
where
Self: Sized,
{
prepare_command(self, cmd("CONFIG").arg("HELP"))
}
#[must_use]
fn config_resetstat(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("CONFIG").arg("RESETSTAT").cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn config_rewrite(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("CONFIG").arg("REWRITE"))
}
#[must_use]
fn config_set(self, configs: impl Serialize) -> PreparedCommand<'a, Self, ()> {
prepare_command(
self,
cmd("CONFIG").arg("SET").arg(configs).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn dbsize(self) -> PreparedCommand<'a, Self, usize>
where
Self: Sized,
{
prepare_command(
self,
cmd("DBSIZE").cluster_info(RequestPolicy::AllShards, ResponsePolicy::AggSum, 1),
)
}
#[must_use]
fn failover(self, options: FailOverOptions) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("FAILOVER").arg(options))
}
#[must_use]
fn flushdb(
self,
flushing_mode: impl Into<Option<FlushingMode>>,
) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("FLUSHDB").arg(flushing_mode.into()).cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn flushall(
self,
flushing_mode: impl Into<Option<FlushingMode>>,
) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("FLUSHALL").arg(flushing_mode.into()).cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn info<R: Response>(self, sections: impl Serialize) -> PreparedCommand<'a, Self, R> {
prepare_command(
self,
cmd("INFO").arg(sections).cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn lastsave(self) -> PreparedCommand<'a, Self, u64>
where
Self: Sized,
{
prepare_command(self, cmd("LASTSAVE"))
}
#[must_use]
fn latency_doctor<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(
self,
cmd("LATENCY").arg("DOCTOR").cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn latency_graph<R: Response>(self, event: LatencyHistoryEvent) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(
self,
cmd("LATENCY").arg("GRAPH").arg(event).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::Special,
1,
),
)
}
fn latency_help<R: Response>(self) -> PreparedCommand<'a, Self, R>
where
Self: Sized,
{
prepare_command(self, cmd("LATENCY").arg("HELP"))
}
#[must_use]
fn latency_histogram<R: Response>(
self,
commands: impl Serialize,
) -> PreparedCommand<'a, Self, R> {
prepare_command(
self,
cmd("LATENCY").arg("HISTOGRAM").arg(commands).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn latency_history<R: Response>(
self,
event: LatencyHistoryEvent,
) -> PreparedCommand<'a, Self, R> {
prepare_command(
self,
cmd("LATENCY").arg("HISTORY").arg(event).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn latency_latest<R: Response>(self) -> PreparedCommand<'a, Self, R> {
prepare_command(
self,
cmd("LATENCY").arg("LATEST").cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn latency_reset(self, events: impl Serialize) -> PreparedCommand<'a, Self, usize> {
prepare_command(
self,
cmd("LATENCY").arg("RESET").arg(events).cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AggSum,
1,
),
)
}
#[must_use]
fn lolwut(self, options: LolWutOptions) -> PreparedCommand<'a, Self, String>
where
Self: Sized,
{
prepare_command(self, cmd("LOLWUT").arg(options))
}
#[must_use]
fn memory_doctor(self) -> PreparedCommand<'a, Self, String>
where
Self: Sized,
{
prepare_command(
self,
cmd("MEMORY").arg("DOCTOR").cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn memory_help(self) -> PreparedCommand<'a, Self, Vec<String>>
where
Self: Sized,
{
prepare_command(self, cmd("MEMORY").arg("HELP"))
}
#[must_use]
fn memory_malloc_stats(self) -> PreparedCommand<'a, Self, String>
where
Self: Sized,
{
prepare_command(
self,
cmd("MEMORY").arg("MALLOC-STATS").cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn memory_purge(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("MEMORY").arg("PURGE").cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn memory_stats(self) -> PreparedCommand<'a, Self, MemoryStats>
where
Self: Sized,
{
prepare_command(
self,
cmd("MEMORY").arg("STATS").cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::Special,
1,
),
)
}
#[must_use]
fn memory_usage(
self,
key: impl Serialize,
options: MemoryUsageOptions,
) -> PreparedCommand<'a, Self, Option<usize>> {
prepare_command(self, cmd("MEMORY").arg("USAGE").key(key).arg(options))
}
#[must_use]
fn module_list<R: Response>(self) -> PreparedCommand<'a, Self, R> {
prepare_command(self, cmd("MODULE").arg("LIST"))
}
#[must_use]
fn module_help(self) -> PreparedCommand<'a, Self, Vec<String>>
where
Self: Sized,
{
prepare_command(self, cmd("MODULE").arg("HELP"))
}
#[must_use]
fn replicaof(self, options: ReplicaOfOptions) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("REPLICAOF").arg(options))
}
#[must_use]
fn role(self) -> PreparedCommand<'a, Self, RoleResult>
where
Self: Sized,
{
prepare_command(self, cmd("ROLE"))
}
#[must_use]
fn save(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("SAVE"))
}
#[must_use]
fn shutdown(self, options: ShutdownOptions) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("SHUTDOWN").arg(options))
}
#[must_use]
fn slowlog_get(self, options: SlowLogGetOptions) -> PreparedCommand<'a, Self, Vec<SlowLogEntry>>
where
Self: Sized,
{
prepare_command(
self,
cmd("SLOWLOG")
.arg("GET")
.arg(options)
.cluster_info(RequestPolicy::AllNodes, None, 1),
)
}
#[must_use]
fn slowlog_help(self) -> PreparedCommand<'a, Self, Vec<String>>
where
Self: Sized,
{
prepare_command(self, cmd("SLOWLOG").arg("HELP"))
}
#[must_use]
fn slowlog_len(self) -> PreparedCommand<'a, Self, usize>
where
Self: Sized,
{
prepare_command(
self,
cmd("SLOWLOG").arg("LEN").cluster_info(
RequestPolicy::AllShards,
ResponsePolicy::AggSum,
1,
),
)
}
#[must_use]
fn slowlog_reset(self) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(
self,
cmd("SLOWLOG").arg("RESET").cluster_info(
RequestPolicy::AllNodes,
ResponsePolicy::AllSucceeded,
1,
),
)
}
#[must_use]
fn swapdb(self, index1: usize, index2: usize) -> PreparedCommand<'a, Self, ()>
where
Self: Sized,
{
prepare_command(self, cmd("SWAPDB").arg(index1).arg(index2))
}
#[must_use]
fn time(self) -> PreparedCommand<'a, Self, (u32, u32)>
where
Self: Sized,
{
prepare_command(self, cmd("TIME"))
}
}
#[derive(Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub enum FlushingMode {
Async,
Sync,
}
#[derive(Default, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub struct AclCatOptions<'a>(#[serde(skip_serializing_if = "Option::is_none")] Option<&'a str>);
impl<'a> AclCatOptions<'a> {
#[must_use]
pub fn category_name(category_name: &'a str) -> Self {
Self(Some(category_name))
}
}
#[derive(Default, Serialize)]
pub struct AclDryRunOptions(CommandArgsMut);
impl AclDryRunOptions {
#[must_use]
pub fn arg(self, args: impl Serialize) -> Self {
Self(self.0.arg(args))
}
}
#[derive(Default, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub struct AclGenPassOptions(#[serde(skip_serializing_if = "Option::is_none")] Option<u32>);
impl AclGenPassOptions {
#[must_use]
pub fn bits(bits: u32) -> Self {
Self(Some(bits))
}
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct AclLogOptions {
#[serde(rename = "", skip_serializing_if = "Option::is_none")]
pub count: Option<u32>,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
pub reset: bool,
}
impl AclLogOptions {
#[must_use]
pub fn count(count: u32) -> Self {
Self {
count: Some(count),
reset: false,
}
}
#[must_use]
pub fn reset() -> Self {
Self {
count: None,
reset: true,
}
}
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct BgsaveOptions {
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
schedule: bool,
}
impl BgsaveOptions {
#[must_use]
pub fn schedule(mut self) -> Self {
self.schedule = true;
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CommandInfo {
pub name: String,
pub arity: isize,
pub flags: Vec<String>,
pub first_key: usize,
pub last_key: isize,
pub step: usize,
pub acl_categories: Vec<String>,
#[serde(default)]
pub command_tips: Vec<CommandTip>,
#[serde(default)]
pub key_specifications: Vec<KeySpecification>,
#[serde(default)]
pub sub_commands: Vec<CommandInfo>,
}
#[derive(Debug, Clone)]
pub enum CommandTip {
NonDeterministricOutput,
NonDeterministricOutputOrder,
RequestPolicy(RequestPolicy),
ResponsePolicy(ResponsePolicy),
}
impl<'de> Deserialize<'de> for CommandTip {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let tip = <&str>::deserialize(deserializer)?;
match tip {
"nondeterministic_output" => Ok(CommandTip::NonDeterministricOutput),
"nondeterministic_output_order" => Ok(CommandTip::NonDeterministricOutputOrder),
_ => {
let mut parts = tip.split(':');
match (parts.next(), parts.next(), parts.next()) {
(Some("request_policy"), Some(policy), None) => {
match RequestPolicy::from_str(policy) {
Ok(request_policy) => Ok(CommandTip::RequestPolicy(request_policy)),
Err(_) => Err(de::Error::invalid_value(
de::Unexpected::Str(policy),
&"a valid RequestPolicy value",
)),
}
}
(Some("response_policy"), Some(policy), None) => {
match ResponsePolicy::from_str(policy) {
Ok(response_policy) => Ok(CommandTip::ResponsePolicy(response_policy)),
Err(_) => Err(de::Error::invalid_value(
de::Unexpected::Str(policy),
&"a valid ResponsePolicy value",
)),
}
}
_ => Err(de::Error::invalid_value(
de::Unexpected::Str(tip),
&"a valid CommandTip value",
)),
}
}
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub enum RequestPolicy {
AllNodes,
AllShards,
MultiShard,
Special,
}
impl FromStr for RequestPolicy {
type Err = Error;
fn from_str(str: &str) -> Result<Self> {
match str {
"all_nodes" => Ok(RequestPolicy::AllNodes),
"all_shards" => Ok(RequestPolicy::AllShards),
"multi_shard" => Ok(RequestPolicy::MultiShard),
"special" => Ok(RequestPolicy::Special),
_ => Err(Error::Client(ClientError::CannotParseRequestPolicy)),
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub enum ResponsePolicy {
OneSucceeded,
AllSucceeded,
AggLogicalAnd,
AggLogicalOr,
AggMin,
AggMax,
AggSum,
Special,
}
impl FromStr for ResponsePolicy {
type Err = Error;
fn from_str(str: &str) -> Result<Self> {
match str {
"one_succeeded" => Ok(ResponsePolicy::OneSucceeded),
"all_succeeded" => Ok(ResponsePolicy::AllSucceeded),
"agg_logical_and" => Ok(ResponsePolicy::AggLogicalAnd),
"agg_logical_or" => Ok(ResponsePolicy::AggLogicalOr),
"agg_min" => Ok(ResponsePolicy::AggMin),
"agg_max" => Ok(ResponsePolicy::AggMax),
"agg_sum" => Ok(ResponsePolicy::AggSum),
"special" => Ok(ResponsePolicy::Special),
_ => Err(Error::Client(ClientError::CannotParseResponsePolicy)),
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct KeySpecification {
pub begin_search: BeginSearch,
pub find_keys: FindKeys,
pub flags: Vec<String>,
#[serde(default)]
pub notes: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", content = "spec")]
#[serde(rename_all = "lowercase")]
pub enum BeginSearch {
#[serde(deserialize_with = "deserialize_begin_search_idx")]
Index(usize),
Keyword {
keyword: String,
#[serde(rename = "startfrom")]
start_from: isize,
},
#[serde(deserialize_with = "deserialize_begin_search_unknown")]
Unknown,
}
fn deserialize_begin_search_idx<'de, D>(deserializer: D) -> std::result::Result<usize, D::Error>
where
D: Deserializer<'de>,
{
let map = HashMap::<String, usize>::deserialize(deserializer)?;
let index = map
.get("index")
.ok_or_else(|| de::Error::custom("Cannot parse BeginSearch index"))?;
Ok(*index)
}
fn deserialize_begin_search_unknown<'de, D>(deserializer: D) -> std::result::Result<(), D::Error>
where
D: Deserializer<'de>,
{
let map = HashMap::<String, ()>::deserialize(deserializer)?;
assert!(map.is_empty());
Ok(())
}
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type", content = "spec")]
#[serde(rename_all = "lowercase")]
pub enum FindKeys {
Range {
#[serde(rename = "lastkey")]
last_key: isize,
#[serde(rename = "keystep")]
key_step: usize,
limit: usize,
},
KeyNum {
#[serde(rename = "keynumidx")]
key_num_idx: usize,
#[serde(rename = "firstkey")]
first_key: usize,
#[serde(rename = "keystep")]
key_step: usize,
},
Unknown {},
}
#[derive(Debug, Default, Deserialize)]
pub struct CommandDoc {
pub summary: String,
pub since: String,
pub group: String,
pub complexity: String,
#[serde(default)]
pub doc_flags: Vec<CommandDocFlag>,
#[serde(default)]
pub deprecated_since: String,
#[serde(default)]
pub replaced_by: String,
#[serde(default)]
pub history: Vec<HistoricalNote>,
pub arguments: Vec<CommandArgument>,
}
#[derive(Debug, Deserialize)]
pub enum CommandDocFlag {
Deprecated,
SystemCommand,
}
#[derive(Debug, Deserialize)]
pub struct HistoricalNote {
pub version: String,
pub description: String,
}
#[derive(Debug, Deserialize)]
pub struct CommandArgument {
pub name: String,
#[serde(default)]
pub display_text: String,
#[serde(rename = "type")]
pub type_: CommandArgumentType,
#[serde(default)]
pub key_spec_index: usize,
#[serde(default)]
pub token: String,
#[serde(default)]
pub summary: String,
#[serde(default)]
pub since: String,
#[serde(default)]
pub deprecated_since: String,
#[serde(default)]
pub flags: Vec<ArgumentFlag>,
#[serde(default)]
pub value: Vec<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum CommandArgumentType {
String,
Integer,
Double,
Key,
Pattern,
UnixTime,
PureToken,
Oneof,
Block,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ArgumentFlag {
Optional,
Multiple,
MultipleToken,
}
#[derive(Serialize)]
#[serde(rename_all = "UPPERCASE")]
enum FilterBy<'a> {
Module(&'a str),
AclCat(&'a str),
Pattern(&'a str),
}
#[derive(Default, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub struct CommandListOptions<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
filterby: Option<FilterBy<'a>>,
}
impl<'a> CommandListOptions<'a> {
#[must_use]
pub fn filter_by_module_name(mut self, module_name: &'a str) -> Self {
self.filterby = Some(FilterBy::Module(module_name));
self
}
#[must_use]
pub fn filter_by_acl_category(mut self, acl_category: &'a str) -> Self {
self.filterby = Some(FilterBy::AclCat(acl_category));
self
}
#[must_use]
pub fn filter_by_pattern(mut self, pattern: &'a str) -> Self {
self.filterby = Some(FilterBy::Pattern(pattern));
self
}
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct FailOverOptions<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
to: Option<(&'a str, u16)>,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
force: bool,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
abort: bool,
#[serde(skip_serializing_if = "Option::is_none")]
timeout: Option<u64>,
}
impl<'a> FailOverOptions<'a> {
#[must_use]
pub fn to(mut self, host: &'a str, port: u16) -> Self {
self.to = Some((host, port));
self
}
#[must_use]
pub fn force(mut self) -> Self {
self.force = true;
self
}
#[must_use]
pub fn abort(mut self) -> Self {
self.abort = true;
self
}
#[must_use]
pub fn timeout(mut self, milliseconds: u64) -> Self {
self.timeout = Some(milliseconds);
self
}
}
#[derive(Serialize)]
#[serde(rename_all = "lowercase")]
pub enum InfoSection {
Server,
Clients,
Memory,
Persistence,
Stats,
Replication,
Cpu,
Commandstats,
Latencystats,
Cluster,
Keyspace,
Modules,
Errorstats,
All,
Default,
Everything,
}
#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum LatencyHistoryEvent {
ActiveDefragCycle,
AofFsyncAlways,
AofStat,
AofRewriteDiffWrite,
AofRename,
AofWrite,
AofWriteActiveChild,
AofWriteAlone,
AofWritePendingFsync,
Command,
ExpireCycle,
EvictionCycle,
EvictionDel,
FastCommand,
Fork,
RdbUnlinkTempFile,
}
#[derive(Default, Deserialize)]
pub struct CommandHistogram {
pub calls: usize,
pub histogram_usec: HashMap<u32, u32>,
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct LolWutOptions {
#[serde(skip_serializing_if = "Option::is_none")]
version: Option<u32>,
#[serde(rename = "", skip_serializing_if = "SmallVec::is_empty")]
optional_arguments: SmallVec<[u32; 5]>,
}
impl LolWutOptions {
#[must_use]
pub fn version(mut self, version: u32) -> Self {
self.version = Some(version);
self
}
#[must_use]
pub fn optional_arg(mut self, arg: u32) -> Self {
self.optional_arguments.push(arg);
self
}
}
#[derive(Debug, Deserialize)]
pub struct MemoryStats {
#[serde(rename = "peak.allocated")]
pub peak_allocated: usize,
#[serde(rename = "total.allocated")]
pub total_allocated: usize,
#[serde(rename = "startup.allocated")]
#[serde(default)]
pub startup_allocated: usize,
#[serde(rename = "replication.backlog")]
#[serde(default)]
pub replication_backlog: usize,
#[serde(rename = "clients.slaves")]
#[serde(default)]
pub clients_slaves: usize,
#[serde(rename = "clients.normal")]
#[serde(default)]
pub clients_normal: usize,
#[serde(rename = "cluster.links")]
#[serde(default)]
pub cluster_links: usize,
#[serde(rename = "aof.buffer")]
#[serde(default)]
pub aof_buffer: usize,
#[serde(rename = "lua.caches")]
#[serde(default)]
pub lua_caches: usize,
#[serde(rename = "functions.caches")]
#[serde(default)]
pub functions_caches: usize,
#[serde(rename = "overhead.total")]
#[serde(default)]
pub overhead_total: usize,
#[serde(rename = "keys.count")]
#[serde(default)]
pub keys_count: usize,
#[serde(rename = "keys.bytes-per-key")]
#[serde(default)]
pub keys_bytes_per_key: usize,
#[serde(rename = "dataset.bytes")]
#[serde(default)]
pub dataset_bytes: usize,
#[serde(rename = "dataset.percentage")]
#[serde(default)]
pub dataset_percentage: f64,
#[serde(rename = "peak.percentage")]
#[serde(default)]
pub peak_percentage: f64,
#[serde(rename = "allocator.allocated")]
#[serde(default)]
pub allocator_allocated: usize,
#[serde(rename = "allocator.active")]
#[serde(default)]
pub allocator_active: usize,
#[serde(rename = "allocator.resident")]
#[serde(default)]
pub allocator_resident: usize,
#[serde(rename = "allocator-fragmentation.ratio")]
#[serde(default)]
pub allocator_fragmentation_ratio: f64,
#[serde(rename = "allocator-fragmentation.bytes")]
#[serde(default)]
pub allocator_fragmentation_bytes: isize,
#[serde(rename = "allocator-rss.ratio")]
#[serde(default)]
pub allocator_rss_ratio: f64,
#[serde(rename = "allocator-rss.bytes")]
#[serde(default)]
pub allocator_rss_bytes: isize,
#[serde(rename = "rss-overhead.ratio")]
#[serde(default)]
pub rss_overhead_ratio: f64,
#[serde(rename = "rss-overhead.bytes")]
#[serde(default)]
pub rss_overhead_bytes: isize,
#[serde(rename = "fragmentation")]
#[serde(default)]
pub fragmentation: f64,
#[serde(rename = "fragmentation.bytes")]
#[serde(default)]
pub fragmentation_bytes: isize,
}
#[derive(Debug, Deserialize)]
pub struct DatabaseOverhead {
pub overhead_hashtable_main: usize,
pub overhead_hashtable_expires: usize,
pub overhead_hashtable_slot_to_keys: usize,
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct MemoryUsageOptions {
#[serde(skip_serializing_if = "Option::is_none")]
samples: Option<u32>,
}
impl MemoryUsageOptions {
#[must_use]
pub fn samples(mut self, count: u32) -> Self {
self.samples = Some(count);
self
}
}
#[derive(Deserialize)]
pub struct ModuleInfo {
pub name: String,
#[serde(default)]
pub version: u64,
}
#[derive(Serialize)]
#[serde(untagged)]
pub enum ReplicaOfOptions<'a> {
Master((&'a str, u16)),
NoOne(&'static str, &'static str),
}
impl<'a> ReplicaOfOptions<'a> {
#[must_use]
pub fn no_one() -> Self {
Self::NoOne("NO", "ONE")
}
#[must_use]
pub fn master(host: &'a str, port: u16) -> Self {
Self::Master((host, port))
}
}
#[derive(Debug)]
pub enum RoleResult {
Master {
master_replication_offset: usize,
replica_infos: Vec<ReplicaInfo>,
},
Replica {
master_ip: String,
master_port: u16,
state: ReplicationState,
amount_data_received: isize,
},
Sentinel {
master_names: Vec<String>,
},
}
impl<'de> Deserialize<'de> for RoleResult {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct RoleResultVisitor;
impl<'de> Visitor<'de> for RoleResultVisitor {
type Value = RoleResult;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("RoleResult")
}
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let Some(role): Option<&str> = seq.next_element()? else {
return Err(de::Error::invalid_length(0, &"more elements in sequence"));
};
match role {
"master" => {
let Some(master_replication_offset): Option<usize> = seq.next_element()?
else {
return Err(de::Error::invalid_length(1, &"more elements in sequence"));
};
let Some(replica_infos): Option<Vec<ReplicaInfo>> = seq.next_element()?
else {
return Err(de::Error::invalid_length(2, &"more elements in sequence"));
};
Ok(RoleResult::Master {
master_replication_offset,
replica_infos,
})
}
"slave" => {
let Some(master_ip): Option<String> = seq.next_element()? else {
return Err(de::Error::invalid_length(1, &"more elements in sequence"));
};
let Some(master_port): Option<u16> = seq.next_element()? else {
return Err(de::Error::invalid_length(2, &"more elements in sequence"));
};
let Some(state): Option<ReplicationState> = seq.next_element()? else {
return Err(de::Error::invalid_length(3, &"more elements in sequence"));
};
let Some(amount_data_received): Option<isize> = seq.next_element()? else {
return Err(de::Error::invalid_length(4, &"more elements in sequence"));
};
Ok(RoleResult::Replica {
master_ip,
master_port,
state,
amount_data_received,
})
}
"sentinel" => {
let Some(master_names): Option<Vec<String>> = seq.next_element()? else {
return Err(de::Error::invalid_length(1, &"more elements in sequence"));
};
Ok(RoleResult::Sentinel { master_names })
}
_ => Err(de::Error::invalid_value(
de::Unexpected::Str(role),
&"expected `master`, `slave` or `sentinel`",
)),
}
}
}
deserializer.deserialize_seq(RoleResultVisitor)
}
}
#[derive(Debug, Deserialize)]
pub struct ReplicaInfo {
pub ip: String,
pub port: u16,
pub last_ack_offset: usize,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum ReplicationState {
Handshake,
None,
Connect,
Connecting,
Sync,
Connected,
Unknown,
}
#[derive(Default, Serialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
pub struct ShutdownOptions {
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
save: bool,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
nosave: bool,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
now: bool,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
force: bool,
#[serde(
skip_serializing_if = "std::ops::Not::not",
serialize_with = "serialize_flag"
)]
abort: bool,
}
impl ShutdownOptions {
#[must_use]
pub fn save(mut self, save: bool) -> Self {
self.save = save;
self.nosave = !save;
self
}
#[must_use]
pub fn now(mut self) -> Self {
self.now = true;
self
}
#[must_use]
pub fn force(mut self) -> Self {
self.force = true;
self
}
#[must_use]
pub fn abort(mut self) -> Self {
self.abort = true;
self
}
}
#[derive(Default, Serialize)]
pub struct SlowLogGetOptions(#[serde(skip_serializing_if = "Option::is_none")] Option<u32>);
impl SlowLogGetOptions {
#[must_use]
pub fn count(count: u32) -> Self {
Self(Some(count))
}
}
#[derive(Deserialize)]
pub struct SlowLogEntry {
pub id: i64,
pub unix_timestamp: u32,
pub execution_time_micros: u64,
pub command: Vec<String>,
pub client_address: String,
pub client_name: String,
}