1use std::collections::HashMap;
2
3use crate::{
4 prepare_command,
5 resp::{
6 cmd, ArgsOrCollection, CommandArg, CommandArgs, FromKeyValueValueArray, FromValue,
7 HashMapExt, IntoArgs, KeyValueArgOrCollection, Value,
8 },
9 PreparedCommand, Result,
10};
11
12pub trait SentinelCommands {
16 #[must_use]
21 fn sentinel_config_get<N, RN, RV, R>(&mut self, name: N) -> PreparedCommand<Self, R>
22 where
23 Self: Sized,
24 N: Into<CommandArg>,
25 RN: FromValue,
26 RV: FromValue,
27 R: FromKeyValueValueArray<RN, RV>,
28 {
29 prepare_command(self, cmd("SENTINEL").arg("CONFIG").arg("GET").arg(name))
30 }
31
32 #[must_use]
34 fn sentinel_config_set<N, V>(&mut self, name: N, value: V) -> PreparedCommand<Self, ()>
35 where
36 Self: Sized,
37 N: Into<CommandArg>,
38 V: Into<CommandArg>,
39 {
40 prepare_command(
41 self,
42 cmd("SENTINEL")
43 .arg("CONFIG")
44 .arg("SET")
45 .arg(name)
46 .arg(value),
47 )
48 }
49
50 #[must_use]
55 fn sentinel_ckquorum<N>(&mut self, master_name: N) -> PreparedCommand<Self, ()>
56 where
57 Self: Sized,
58 N: Into<CommandArg>,
59 {
60 prepare_command(self, cmd("SENTINEL").arg("CKQUORUM").arg(master_name))
61 }
62
63 #[must_use]
68 fn sentinel_failover<N>(&mut self, master_name: N) -> PreparedCommand<Self, ()>
69 where
70 Self: Sized,
71 N: Into<CommandArg>,
72 {
73 prepare_command(self, cmd("SENTINEL").arg("FAILOVER").arg(master_name))
74 }
75
76 #[must_use]
85 fn sentinel_flushconfig(&mut self) -> PreparedCommand<Self, ()>
86 where
87 Self: Sized,
88 {
89 prepare_command(self, cmd("SENTINEL").arg("FLUSHCONFIG"))
90 }
91
92 #[must_use]
103 fn sentinel_get_master_addr_by_name<N>(
104 &mut self,
105 master_name: N,
106 ) -> PreparedCommand<Self, Option<(String, u16)>>
107 where
108 Self: Sized,
109 N: Into<CommandArg>,
110 {
111 prepare_command(
112 self,
113 cmd("SENTINEL")
114 .arg("GET-MASTER-ADDR-BY-NAME")
115 .arg(master_name),
116 )
117 }
118
119 #[must_use]
121 fn sentinel_info_cache<N, NN, R>(&mut self, master_names: NN) -> PreparedCommand<Self, R>
122 where
123 Self: Sized,
124 N: Into<CommandArg>,
125 NN: ArgsOrCollection<N>,
126 R: FromKeyValueValueArray<String, Vec<(u64, String)>>,
127 {
128 prepare_command(self, cmd("SENTINEL").arg("INFO-CACHE").arg(master_names))
129 }
130
131 #[must_use]
133 fn sentinel_master<N>(&mut self, master_name: N) -> PreparedCommand<Self, SentinelMasterInfo>
134 where
135 Self: Sized,
136 N: Into<CommandArg>,
137 {
138 prepare_command(self, cmd("SENTINEL").arg("MASTER").arg(master_name))
139 }
140
141 #[must_use]
143 fn sentinel_masters(&mut self) -> PreparedCommand<Self, Vec<SentinelMasterInfo>>
144 where
145 Self: Sized,
146 {
147 prepare_command(self, cmd("SENTINEL").arg("MASTERS"))
148 }
149
150 #[must_use]
157 fn sentinel_monitor<N, I>(
158 &mut self,
159 name: N,
160 ip: I,
161 port: u16,
162 quorum: usize,
163 ) -> PreparedCommand<Self, ()>
164 where
165 Self: Sized,
166 N: Into<CommandArg>,
167 I: Into<CommandArg>,
168 {
169 prepare_command(
170 self,
171 cmd("SENTINEL")
172 .arg("MONITOR")
173 .arg(name)
174 .arg(ip)
175 .arg(port)
176 .arg(quorum),
177 )
178 }
179
180 #[must_use]
186 fn sentinel_remove<N>(&mut self, name: N) -> PreparedCommand<Self, ()>
187 where
188 Self: Sized,
189 N: Into<CommandArg>,
190 {
191 prepare_command(self, cmd("SENTINEL").arg("REMOVE").arg(name))
192 }
193
194 #[must_use]
201 fn sentinel_set<N, O, V, C>(&mut self, name: N, configs: C) -> PreparedCommand<Self, ()>
202 where
203 Self: Sized,
204 N: Into<CommandArg>,
205 O: Into<CommandArg>,
206 V: Into<CommandArg>,
207 C: KeyValueArgOrCollection<O, V>,
208 {
209 prepare_command(self, cmd("SENTINEL").arg("SET").arg(name).arg(configs))
210 }
211
212 #[must_use]
214 fn sentinel_myid(&mut self) -> PreparedCommand<Self, String>
215 where
216 Self: Sized,
217 {
218 prepare_command(self, cmd("SENTINEL").arg("MYID"))
219 }
220
221 #[must_use]
223 fn sentinel_pending_scripts(&mut self) -> PreparedCommand<Self, Vec<Value>>
224 where
225 Self: Sized,
226 {
227 prepare_command(self, cmd("SENTINEL").arg("PENDING-SCRIPTS"))
228 }
229
230 #[must_use]
232 fn sentinel_replicas<N>(
233 &mut self,
234 master_name: N,
235 ) -> PreparedCommand<Self, Vec<SentinelReplicaInfo>>
236 where
237 Self: Sized,
238 N: Into<CommandArg>,
239 {
240 prepare_command(self, cmd("SENTINEL").arg("REPLICAS").arg(master_name))
241 }
242
243 #[must_use]
252 fn sentinel_reset<P>(&mut self, pattern: P) -> PreparedCommand<Self, usize>
253 where
254 Self: Sized,
255 P: Into<CommandArg>,
256 {
257 prepare_command(self, cmd("SENTINEL").arg("RESET").arg(pattern))
258 }
259
260 #[must_use]
262 fn sentinel_sentinels<N>(&mut self, master_name: N) -> PreparedCommand<Self, Vec<SentinelInfo>>
263 where
264 Self: Sized,
265 N: Into<CommandArg>,
266 {
267 prepare_command(self, cmd("SENTINEL").arg("SENTINELS").arg(master_name))
268 }
269
270 #[must_use]
272 fn sentinel_simulate_failure(
273 &mut self,
274 mode: SentinelSimulateFailureMode,
275 ) -> PreparedCommand<Self, ()>
276 where
277 Self: Sized,
278 {
279 prepare_command(self, cmd("SENTINEL").arg("SIMULATE-FAILURE").arg(mode))
280 }
281}
282
283#[derive(Debug)]
284pub struct SentinelMasterInfo {
285 pub name: String,
286 pub ip: String,
287 pub port: u16,
288 pub runid: String,
289 pub flags: String,
290 pub link_pending_commands: usize,
291 pub link_refcount: usize,
292 pub last_ping_sent: usize,
293 pub last_ok_ping_reply: usize,
294 pub last_ping_reply: usize,
295 pub down_after_milliseconds: u64,
296 pub info_refresh: u64,
297 pub role_reported: String,
298 pub role_reported_time: u64,
299 pub config_epoch: usize,
300 pub num_slaves: usize,
301 pub num_other_sentinels: usize,
302 pub quorum: usize,
303 pub failover_timeout: u64,
304 pub parallel_syncs: usize,
305}
306
307impl FromValue for SentinelMasterInfo {
308 fn from_value(value: Value) -> Result<Self> {
309 let mut values: HashMap<String, Value> = value.into()?;
310
311 Ok(Self {
312 name: values.remove_or_default("name").into()?,
313 ip: values.remove_or_default("ip").into()?,
314 port: values.remove_or_default("port").into()?,
315 runid: values.remove_or_default("runid").into()?,
316 flags: values.remove_or_default("flags").into()?,
317 link_pending_commands: values.remove_or_default("link-pending-commands").into()?,
318 link_refcount: values.remove_or_default("link-refcount").into()?,
319 last_ping_sent: values.remove_or_default("last-ping-sent").into()?,
320 last_ok_ping_reply: values.remove_or_default("last-ok-ping-reply").into()?,
321 last_ping_reply: values.remove_or_default("last-ping-reply").into()?,
322 down_after_milliseconds: values.remove_or_default("down-after-milliseconds").into()?,
323 info_refresh: values.remove_or_default("info-refresh").into()?,
324 role_reported: values.remove_or_default("role-reported").into()?,
325 role_reported_time: values.remove_or_default("role-reported-time").into()?,
326 config_epoch: values.remove_or_default("config-epoch").into()?,
327 num_slaves: values.remove_or_default("num-slaves").into()?,
328 num_other_sentinels: values.remove_or_default("num-other-sentinels").into()?,
329 quorum: values.remove_or_default("quorum").into()?,
330 failover_timeout: values.remove_or_default("failover-timeout").into()?,
331 parallel_syncs: values.remove_or_default("parallel-syncs").into()?,
332 })
333 }
334}
335
336#[derive(Debug)]
337pub struct SentinelReplicaInfo {
338 pub name: String,
339 pub ip: String,
340 pub port: u16,
341 pub runid: String,
342 pub flags: String,
343 pub link_pending_commands: usize,
344 pub link_refcount: usize,
345 pub last_ping_sent: usize,
346 pub last_ok_ping_reply: usize,
347 pub last_ping_reply: usize,
348 pub down_after_milliseconds: u64,
349 pub info_refresh: u64,
350 pub role_reported: String,
351 pub role_reported_time: u64,
352 pub master_link_down_time: u64,
353 pub master_link_status: String,
354 pub master_host: String,
355 pub master_port: u16,
356 pub slave_priority: u64,
357 pub slave_replica_offset: u64,
358 pub replica_announed: usize,
359}
360
361impl FromValue for SentinelReplicaInfo {
362 fn from_value(value: Value) -> Result<Self> {
363 let mut values: HashMap<String, Value> = value.into()?;
364
365 Ok(Self {
366 name: values.remove_or_default("name").into()?,
367 ip: values.remove_or_default("ip").into()?,
368 port: values.remove_or_default("port").into()?,
369 runid: values.remove_or_default("runid").into()?,
370 flags: values.remove_or_default("flags").into()?,
371 link_pending_commands: values.remove_or_default("link-pending-commands").into()?,
372 link_refcount: values.remove_or_default("link-refcount").into()?,
373 last_ping_sent: values.remove_or_default("last-ping-sent").into()?,
374 last_ok_ping_reply: values.remove_or_default("last-ok-ping-reply").into()?,
375 last_ping_reply: values.remove_or_default("last-ping-reply").into()?,
376 down_after_milliseconds: values.remove_or_default("down-after-milliseconds").into()?,
377 info_refresh: values.remove_or_default("info-refresh").into()?,
378 role_reported: values.remove_or_default("role-reported").into()?,
379 role_reported_time: values.remove_or_default("role-reported-time").into()?,
380 master_link_down_time: values.remove_or_default("master-link-down-time").into()?,
381 master_link_status: values.remove_or_default("master-link-status").into()?,
382 master_host: values.remove_or_default("master-host").into()?,
383 master_port: values.remove_or_default("master-port").into()?,
384 slave_priority: values.remove_or_default("slave-priority").into()?,
385 slave_replica_offset: values.remove_or_default("slave-replica-offset").into()?,
386 replica_announed: values.remove_or_default("replica-announed").into()?,
387 })
388 }
389}
390
391pub struct SentinelInfo {
392 pub name: String,
393 pub ip: String,
394 pub port: u16,
395 pub runid: String,
396 pub flags: String,
397 pub link_pending_commands: usize,
398 pub link_refcount: usize,
399 pub last_ping_sent: usize,
400 pub last_ok_ping_reply: usize,
401 pub last_ping_reply: usize,
402 pub down_after_milliseconds: u64,
403 pub last_hello_message: u64,
404 pub voted_leader: String,
405 pub voted_leader_epoch: usize,
406}
407
408impl FromValue for SentinelInfo {
409 fn from_value(value: Value) -> Result<Self> {
410 let mut values: HashMap<String, Value> = value.into()?;
411
412 Ok(Self {
413 name: values.remove_or_default("name").into()?,
414 ip: values.remove_or_default("ip").into()?,
415 port: values.remove_or_default("port").into()?,
416 runid: values.remove_or_default("runid").into()?,
417 flags: values.remove_or_default("flags").into()?,
418 link_pending_commands: values.remove_or_default("link-pending-commands").into()?,
419 link_refcount: values.remove_or_default("link-refcount").into()?,
420 last_ping_sent: values.remove_or_default("last-ping-sent").into()?,
421 last_ok_ping_reply: values.remove_or_default("last-ok-ping-reply").into()?,
422 last_ping_reply: values.remove_or_default("last-ping-reply").into()?,
423 down_after_milliseconds: values.remove_or_default("down-after-milliseconds").into()?,
424 last_hello_message: values.remove_or_default("last-hello-message").into()?,
425 voted_leader: values.remove_or_default("voted-leader").into()?,
426 voted_leader_epoch: values.remove_or_default("voted-leader-epoch").into()?,
427 })
428 }
429}
430
431pub enum SentinelSimulateFailureMode {
434 CrashAfterElection,
435 CrashAfterPromotion,
436}
437
438impl IntoArgs for SentinelSimulateFailureMode {
439 fn into_args(self, args: CommandArgs) -> CommandArgs {
440 args.arg(match self {
441 SentinelSimulateFailureMode::CrashAfterElection => "CRASH-AFTER-ELECTION",
442 SentinelSimulateFailureMode::CrashAfterPromotion => "CRASH-AFTER-PROMOTION",
443 })
444 }
445}