1use crate::{
2 prepare_command,
3 resp::{
4 cmd, CommandArg, CommandArgs, FromValue, IntoArgs, SingleArgOrCollection, Value,
5 },
6 Error, PreparedCommand, Result,
7};
8use std::collections::HashMap;
9
10pub trait ConnectionCommands {
15 #[must_use]
23 fn auth<U, P>(&mut self, username: Option<U>, password: P) -> PreparedCommand<Self, ()>
24 where
25 Self: Sized,
26 U: Into<CommandArg>,
27 P: Into<CommandArg>,
28 {
29 prepare_command(self, cmd("AUTH").arg(username).arg(password))
30 }
31
32 #[must_use]
38 fn client_caching(&mut self, mode: ClientCachingMode) -> PreparedCommand<Self, Option<()>>
39 where
40 Self: Sized,
41 {
42 prepare_command(self, cmd("CLIENT").arg("CACHING").arg(mode))
43 }
44
45 #[must_use]
53 fn client_getname<CN>(&mut self) -> PreparedCommand<Self, Option<CN>>
54 where
55 Self: Sized,
56 CN: FromValue,
57 {
58 prepare_command(self, cmd("CLIENT").arg("GETNAME"))
59 }
60
61 #[must_use]
71 fn client_getredir(&mut self) -> PreparedCommand<Self, i64>
72 where
73 Self: Sized,
74 {
75 prepare_command(self, cmd("CLIENT").arg("GETREDIR"))
76 }
77
78 #[must_use]
86 fn client_id(&mut self) -> PreparedCommand<Self, i64>
87 where
88 Self: Sized,
89 {
90 prepare_command(self, cmd("CLIENT").arg("ID"))
91 }
92
93 #[must_use]
102 fn client_info(&mut self) -> PreparedCommand<Self, ClientInfo>
103 where
104 Self: Sized,
105 {
106 prepare_command(self, cmd("CLIENT").arg("INFO"))
107 }
108
109 #[must_use]
117 fn client_kill(&mut self, options: ClientKillOptions) -> PreparedCommand<Self, usize>
118 where
119 Self: Sized,
120 {
121 prepare_command(self, cmd("CLIENT").arg("KILL").arg(options))
122 }
123
124 #[must_use]
132 fn client_list(&mut self, options: ClientListOptions) -> PreparedCommand<Self, ClientListResult>
133 where
134 Self: Sized,
135 {
136 prepare_command(self, cmd("CLIENT").arg("LIST").arg(options))
137 }
138
139 #[must_use]
144 fn client_no_evict(&mut self, no_evict: bool) -> PreparedCommand<Self, ()>
145 where
146 Self: Sized,
147 {
148 prepare_command(
149 self,
150 cmd("CLIENT")
151 .arg("NO-EVICT")
152 .arg(if no_evict { "ON" } else { "OFF" }),
153 )
154 }
155
156 #[must_use]
162 fn client_pause(&mut self, timeout: u64, mode: ClientPauseMode) -> PreparedCommand<Self, ()>
163 where
164 Self: Sized,
165 {
166 prepare_command(self, cmd("CLIENT").arg("PAUSE").arg(timeout).arg(mode))
167 }
168
169 #[must_use]
174 fn client_reply(&mut self, mode: ClientReplyMode) -> PreparedCommand<Self, ()>
175 where
176 Self: Sized,
177 {
178 prepare_command(self, cmd("CLIENT").arg("REPLY").arg(mode))
179 }
180
181 #[must_use]
186 fn client_setname<CN>(&mut self, connection_name: CN) -> PreparedCommand<Self, ()>
187 where
188 Self: Sized,
189 CN: Into<CommandArg>,
190 {
191 prepare_command(self, cmd("CLIENT").arg("SETNAME").arg(connection_name))
192 }
193
194 #[must_use]
200 fn client_tracking(
201 &mut self,
202 status: ClientTrackingStatus,
203 options: ClientTrackingOptions,
204 ) -> PreparedCommand<Self, ()>
205 where
206 Self: Sized,
207 {
208 prepare_command(self, cmd("CLIENT").arg("TRACKING").arg(status).arg(options))
209 }
210
211 #[must_use]
217 fn client_trackinginfo(&mut self) -> PreparedCommand<Self, ClientTrackingInfo>
218 where
219 Self: Sized,
220 {
221 prepare_command(self, cmd("CLIENT").arg("TRACKINGINFO"))
222 }
223
224 #[must_use]
235 fn client_unblock(
236 &mut self,
237 client_id: i64,
238 mode: ClientUnblockMode,
239 ) -> PreparedCommand<Self, bool>
240 where
241 Self: Sized,
242 {
243 prepare_command(self, cmd("CLIENT").arg("UNBLOCK").arg(client_id).arg(mode))
244 }
245
246 #[must_use]
252 fn client_unpause(&mut self) -> PreparedCommand<Self, bool>
253 where
254 Self: Sized,
255 {
256 prepare_command(self, cmd("CLIENT").arg("UNPAUSE"))
257 }
258
259 #[must_use]
264 fn echo<M, R>(&mut self, message: M) -> PreparedCommand<Self, R>
265 where
266 Self: Sized,
267 M: Into<CommandArg>,
268 R: FromValue,
269 {
270 prepare_command(self, cmd("ECHO").arg(message))
271 }
272
273 #[must_use]
280 fn hello(&mut self, options: HelloOptions) -> PreparedCommand<Self, HelloResult>
281 where
282 Self: Sized,
283 {
284 prepare_command(self, cmd("HELLO").arg(options))
285 }
286
287 #[must_use]
292 fn ping<R>(&mut self, options: PingOptions) -> PreparedCommand<Self, R>
293 where
294 Self: Sized,
295 R: FromValue,
296 {
297 prepare_command(self, cmd("PING").arg(options))
298 }
299
300 #[must_use]
305 fn quit(&mut self) -> PreparedCommand<Self, ()>
306 where
307 Self: Sized,
308 {
309 prepare_command(self, cmd("QUIT"))
310 }
311
312 #[must_use]
318 fn reset(&mut self) -> PreparedCommand<Self, ()>
319 where
320 Self: Sized,
321 {
322 prepare_command(self, cmd("RESET"))
323 }
324
325 #[must_use]
330 fn select(&mut self, index: usize) -> PreparedCommand<Self, ()>
331 where
332 Self: Sized,
333 {
334 prepare_command(self, cmd("SELECT").arg(index))
335 }
336}
337
338pub enum ClientCachingMode {
340 Yes,
341 No,
342}
343
344impl IntoArgs for ClientCachingMode {
345 fn into_args(self, args: CommandArgs) -> CommandArgs {
346 args.arg(match self {
347 ClientCachingMode::Yes => CommandArg::Str("YES"),
348 ClientCachingMode::No => CommandArg::Str("NO"),
349 })
350 }
351}
352
353#[derive(Debug)]
356pub struct ClientInfo {
357 pub id: i64,
359
360 pub addr: String,
362
363 pub laddr: String,
365
366 pub fd: u32,
368
369 pub name: String,
371
372 pub age: u32,
374
375 pub idle: u32,
377
378 pub flags: String,
380
381 pub db: usize,
383
384 pub sub: usize,
386
387 pub psub: usize,
389
390 pub ssub: usize,
392
393 pub multi: usize,
395
396 pub qbuf: usize,
398
399 pub qbuf_free: usize,
401
402 pub argv_mem: usize,
404
405 pub multi_mem: usize,
407
408 pub obl: usize,
410
411 pub oll: usize,
413
414 pub omem: usize,
416
417 pub tot_mem: usize,
419
420 pub events: String,
422
423 pub cmd: String,
425
426 pub user: String,
428
429 pub redir: i64,
431
432 pub resp: i32,
434
435 pub additional_arguments: HashMap<String, String>,
437}
438
439impl ClientInfo {
440 pub fn from_line(line: &str) -> Result<ClientInfo> {
441 let mut values: HashMap<String, String> = line
443 .trim_end()
444 .split(' ')
445 .map(|kvp| {
446 let mut iter = kvp.split('=');
447 match (iter.next(), iter.next()) {
448 (Some(key), None) => (key.to_owned(), "".to_owned()),
449 (Some(key), Some(value)) => (key.to_owned(), value.to_owned()),
450 _ => ("".to_owned(), "".to_owned()),
451 }
452 })
453 .collect();
454
455 Ok(ClientInfo {
456 id: values
457 .remove("id")
458 .map(|id| id.parse::<i64>().unwrap_or_default())
459 .unwrap_or_default(),
460 addr: values.remove("addr").unwrap_or_default(),
461 laddr: values.remove("laddr").unwrap_or_default(),
462 fd: values
463 .remove("fd")
464 .map(|id| id.parse::<u32>().unwrap_or_default())
465 .unwrap_or_default(),
466 name: values.remove("name").unwrap_or_default(),
467 age: values
468 .remove("age")
469 .map(|id| id.parse::<u32>().unwrap_or_default())
470 .unwrap_or_default(),
471 idle: values
472 .remove("idle")
473 .map(|id| id.parse::<u32>().unwrap_or_default())
474 .unwrap_or_default(),
475 flags: values.remove("flags").unwrap_or_default(),
476 db: values
477 .remove("db")
478 .map(|id| id.parse::<usize>().unwrap_or_default())
479 .unwrap_or_default(),
480 sub: values
481 .remove("sub")
482 .map(|id| id.parse::<usize>().unwrap_or_default())
483 .unwrap_or_default(),
484 psub: values
485 .remove("psub")
486 .map(|id| id.parse::<usize>().unwrap_or_default())
487 .unwrap_or_default(),
488 ssub: values
489 .remove("ssub")
490 .map(|id| id.parse::<usize>().unwrap_or_default())
491 .unwrap_or_default(),
492 multi: values
493 .remove("multi")
494 .map(|id| id.parse::<usize>().unwrap_or_default())
495 .unwrap_or_default(),
496 qbuf: values
497 .remove("qbuf")
498 .map(|id| id.parse::<usize>().unwrap_or_default())
499 .unwrap_or_default(),
500 qbuf_free: values
501 .remove("qbuf-free")
502 .map(|id| id.parse::<usize>().unwrap_or_default())
503 .unwrap_or_default(),
504 argv_mem: values
505 .remove("argv-mem")
506 .map(|id| id.parse::<usize>().unwrap_or_default())
507 .unwrap_or_default(),
508 multi_mem: values
509 .remove("multi-mem")
510 .map(|id| id.parse::<usize>().unwrap_or_default())
511 .unwrap_or_default(),
512 obl: values
513 .remove("obl")
514 .map(|id| id.parse::<usize>().unwrap_or_default())
515 .unwrap_or_default(),
516 oll: values
517 .remove("oll")
518 .map(|id| id.parse::<usize>().unwrap_or_default())
519 .unwrap_or_default(),
520 omem: values
521 .remove("omem")
522 .map(|id| id.parse::<usize>().unwrap_or_default())
523 .unwrap_or_default(),
524 tot_mem: values
525 .remove("tot-mem")
526 .map(|id| id.parse::<usize>().unwrap_or_default())
527 .unwrap_or_default(),
528 events: values.remove("events").unwrap_or_default(),
529 cmd: values.remove("cmd").unwrap_or_default(),
530 user: values.remove("user").unwrap_or_default(),
531 redir: values
532 .remove("redir")
533 .map(|id| id.parse::<i64>().unwrap_or_default())
534 .unwrap_or_default(),
535 resp: values
536 .remove("resp")
537 .map(|id| id.parse::<i32>().unwrap_or_default())
538 .unwrap_or_default(),
539 additional_arguments: values,
540 })
541 }
542}
543
544impl FromValue for ClientInfo {
545 fn from_value(value: Value) -> Result<Self> {
546 ClientInfo::from_line(&value.into::<String>()?)
547 }
548}
549
550pub enum ClientType {
552 Normal,
553 Master,
554 Replica,
555 PubSub,
556}
557
558impl IntoArgs for ClientType {
559 fn into_args(self, args: CommandArgs) -> CommandArgs {
560 args.arg(match self {
561 ClientType::Normal => CommandArg::Str("NORMAL"),
562 ClientType::Master => CommandArg::Str("MASTER"),
563 ClientType::Replica => CommandArg::Str("REPLICA"),
564 ClientType::PubSub => CommandArg::Str("PUBSUB"),
565 })
566 }
567}
568
569#[derive(Default)]
571pub struct ClientListOptions {
572 command_args: CommandArgs,
573}
574
575impl IntoArgs for ClientListOptions {
576 fn into_args(self, args: CommandArgs) -> CommandArgs {
577 args.arg(self.command_args)
578 }
579}
580
581impl ClientListOptions {
582 #[must_use]
583 pub fn client_type(self, client_type: ClientType) -> Self {
584 Self {
585 command_args: self.command_args.arg("TYPE").arg(client_type),
586 }
587 }
588
589 pub fn client_ids<II>(self, client_ids: II) -> Self
590 where
591 II: SingleArgOrCollection<i64>,
592 {
593 Self {
594 command_args: self.command_args.arg("ID").arg(client_ids),
595 }
596 }
597}
598
599#[derive(Debug)]
601pub struct ClientListResult {
602 pub client_infos: Vec<ClientInfo>,
603}
604
605impl FromValue for ClientListResult {
606 fn from_value(value: Value) -> Result<Self> {
607 let lines: String = value.into()?;
608
609 let client_infos: Result<Vec<ClientInfo>> =
610 lines.split('\n').map(ClientInfo::from_line).collect();
611
612 Ok(Self {
613 client_infos: client_infos?,
614 })
615 }
616}
617
618#[derive(Default)]
620pub struct ClientKillOptions {
621 command_args: CommandArgs,
622}
623
624impl ClientKillOptions {
625 #[must_use]
626 pub fn id(self, client_id: i64) -> Self {
627 Self {
628 command_args: self.command_args.arg("ID").arg(client_id),
629 }
630 }
631
632 #[must_use]
633 pub fn client_type(self, client_type: ClientType) -> Self {
634 Self {
635 command_args: self.command_args.arg("TYPE").arg(client_type),
636 }
637 }
638
639 #[must_use]
640 pub fn user<U: Into<CommandArg>>(self, username: U) -> Self {
641 Self {
642 command_args: self.command_args.arg("USER").arg(username),
643 }
644 }
645
646 #[must_use]
651 pub fn addr<A: Into<CommandArg>>(self, addr: A) -> Self {
652 Self {
653 command_args: self.command_args.arg("ADDR").arg(addr),
654 }
655 }
656
657 #[must_use]
659 pub fn laddr<A: Into<CommandArg>>(self, laddr: A) -> Self {
660 Self {
661 command_args: self.command_args.arg("LADDR").arg(laddr),
662 }
663 }
664
665 #[must_use]
668 pub fn skip_me(self, skip_me: bool) -> Self {
669 Self {
670 command_args: self
671 .command_args
672 .arg("SKIPME")
673 .arg(if skip_me { "YES" } else { "NO" }),
674 }
675 }
676}
677
678impl IntoArgs for ClientKillOptions {
679 fn into_args(self, args: CommandArgs) -> CommandArgs {
680 args.arg(self.command_args)
681 }
682}
683
684pub enum ClientPauseMode {
686 Write,
688 All,
690}
691
692impl IntoArgs for ClientPauseMode {
693 fn into_args(self, args: CommandArgs) -> CommandArgs {
694 args.arg(match self {
695 ClientPauseMode::Write => CommandArg::Str("WRITE"),
696 ClientPauseMode::All => CommandArg::Str("ALL"),
697 })
698 }
699}
700
701impl Default for ClientPauseMode {
702 fn default() -> Self {
703 ClientPauseMode::All
704 }
705}
706
707pub enum ClientReplyMode {
709 On,
710 Off,
711 Skip,
712}
713
714impl IntoArgs for ClientReplyMode {
715 fn into_args(self, args: CommandArgs) -> CommandArgs {
716 args.arg(match self {
717 ClientReplyMode::On => CommandArg::Str("ON"),
718 ClientReplyMode::Off => CommandArg::Str("OFF"),
719 ClientReplyMode::Skip => CommandArg::Str("SKIP"),
720 })
721 }
722}
723
724pub enum ClientTrackingStatus {
726 On,
727 Off,
728}
729
730impl IntoArgs for ClientTrackingStatus {
731 fn into_args(self, args: CommandArgs) -> CommandArgs {
732 args.arg(match self {
733 ClientTrackingStatus::On => CommandArg::Str("ON"),
734 ClientTrackingStatus::Off => CommandArg::Str("OFF"),
735 })
736 }
737}
738
739#[derive(Default)]
741pub struct ClientTrackingOptions {
742 command_args: CommandArgs,
743}
744
745impl ClientTrackingOptions {
746 #[must_use]
747 pub fn redirect(self, client_id: i64) -> Self {
749 Self {
750 command_args: self.command_args.arg("REDIRECT").arg(client_id),
751 }
752 }
753
754 pub fn broadcasting(self) -> Self {
756 Self {
757 command_args: self.command_args.arg("BCAST"),
758 }
759 }
760
761 pub fn prefix<P: Into<CommandArg>>(self, prefix: P) -> Self {
766 Self {
767 command_args: self.command_args.arg("PREFIX").arg(prefix),
768 }
769 }
770
771 pub fn optin(self) -> Self {
774 Self {
775 command_args: self.command_args.arg("OPTIN"),
776 }
777 }
778
779 pub fn optout(self) -> Self {
782 Self {
783 command_args: self.command_args.arg("OPTOUT"),
784 }
785 }
786
787 pub fn no_loop(self) -> Self {
789 Self {
790 command_args: self.command_args.arg("NOLOOP"),
791 }
792 }
793}
794
795impl IntoArgs for ClientTrackingOptions {
796 fn into_args(self, args: CommandArgs) -> CommandArgs {
797 args.arg(self.command_args)
798 }
799}
800
801pub struct ClientTrackingInfo {
803 pub flags: Vec<String>,
805
806 pub redirect: i64,
808
809 pub prefixes: Vec<String>,
811}
812
813impl FromValue for ClientTrackingInfo {
814 fn from_value(value: Value) -> Result<Self> {
815 fn into_result(values: &mut HashMap<String, Value>) -> Option<ClientTrackingInfo> {
816 Some(ClientTrackingInfo {
817 flags: values.remove("flags")?.into().ok()?,
818 redirect: values.remove("redirect")?.into().ok()?,
819 prefixes: values.remove("prefixes")?.into().ok()?,
820 })
821 }
822
823 into_result(&mut value.into()?).ok_or_else(|| {
824 Error::Client(
825 "Cannot parse
826 "
827 .to_owned(),
828 )
829 })
830 }
831}
832
833pub enum ClientUnblockMode {
835 Timeout,
837 Error,
839}
840
841impl IntoArgs for ClientUnblockMode {
842 fn into_args(self, args: CommandArgs) -> CommandArgs {
843 args.arg(match self {
844 ClientUnblockMode::Timeout => CommandArg::Str("TIMEOUT"),
845 ClientUnblockMode::Error => CommandArg::Str("ERROR"),
846 })
847 }
848}
849
850impl Default for ClientUnblockMode {
851 fn default() -> Self {
852 ClientUnblockMode::Timeout
853 }
854}
855
856#[derive(Default)]
858pub struct HelloOptions {
859 command_args: CommandArgs,
860}
861
862impl HelloOptions {
863 #[must_use]
864 pub fn new(protover: usize) -> Self {
865 Self {
866 command_args: CommandArgs::default().arg(protover),
867 }
868 }
869
870 #[must_use]
871 pub fn auth<U, P>(self, username: U, password: P) -> Self
872 where
873 U: Into<CommandArg>,
874 P: Into<CommandArg>,
875 {
876 Self {
877 command_args: self.command_args.arg("AUTH").arg(username).arg(password),
878 }
879 }
880
881 #[must_use]
882 pub fn set_name<C>(self, client_name: C) -> Self
883 where
884 C: Into<CommandArg>,
885 {
886 Self {
887 command_args: self.command_args.arg("SETNAME").arg(client_name),
888 }
889 }
890}
891
892impl IntoArgs for HelloOptions {
893 fn into_args(self, args: CommandArgs) -> CommandArgs {
894 args.arg(self.command_args)
895 }
896}
897
898pub struct HelloResult {
899 pub server: String,
900 pub version: String,
901 pub proto: usize,
902 pub id: i64,
903 pub mode: String,
904 pub role: String,
905 pub modules: Vec<String>,
906}
907
908impl FromValue for HelloResult {
909 fn from_value(value: Value) -> Result<Self> {
910 match &value {
911 Value::Array(Some(v)) if v.len() == 14 => {
912 fn into_result(values: &mut HashMap<String, Value>) -> Option<HelloResult> {
913 Some(HelloResult {
914 server: values.remove("server")?.into().ok()?,
915 version: values.remove("version")?.into().ok()?,
916 proto: values.remove("proto")?.into().ok()?,
917 id: values.remove("id")?.into().ok()?,
918 mode: values.remove("mode")?.into().ok()?,
919 role: values.remove("role")?.into().ok()?,
920 modules: values.remove("modules")?.into().ok()?,
921 })
922 }
923
924 into_result(&mut value.into()?)
925 .ok_or_else(|| Error::Client("Cannot parse HelloResult".to_owned()))
926 }
927 _ => Err(Error::Client("Cannot parse HelloResult".to_owned())),
928 }
929 }
930}
931
932#[derive(Default)]
934pub struct PingOptions {
935 command_args: CommandArgs,
936}
937
938impl PingOptions {
939 #[must_use]
940 pub fn message<M: Into<CommandArg>>(self, message: M) -> Self {
941 Self {
942 command_args: self.command_args.arg(message),
943 }
944 }
945}
946
947impl IntoArgs for PingOptions {
948 fn into_args(self, args: CommandArgs) -> CommandArgs {
949 args.arg(self.command_args)
950 }
951}