1use crc16::key_hash_slot;
2use redis::{Cmd, Connection, ToRedisArgs, FromRedisValue, RedisResult};
3
4pub struct ClusterCmd {
9 cmd: Cmd,
10 args: Vec<Vec<u8>>,
11}
12
13impl ClusterCmd {
14 pub fn new() -> ClusterCmd {
15 ClusterCmd {
16 cmd: Cmd::new(),
17 args: Vec::new(),
18 }
19 }
20
21 pub fn arg<T: ToRedisArgs>(&mut self, arg: T) -> &mut ClusterCmd {
23 for item in arg.to_redis_args().into_iter() {
24 self.args.push(item);
25 }
26 self.cmd.arg(arg);
27 self
28 }
29
30 pub fn query<T: FromRedisValue>(&self, conn: &Connection) -> RedisResult<T> {
32 self.cmd.query(conn)
33 }
34
35 pub fn slot(&self) -> Option<u16> {
37 slot_for_command(&self.args)
38 }
39}
40
41fn slot_for_command(args: &Vec<Vec<u8>>) -> Option<u16> {
42 if args.len() > 1 {
43 Some(key_hash_slot(args[1].as_slice()))
44 } else {
45 None
46 }
47}
48
49pub fn slot_for_packed_command(cmd: &[u8]) -> Option<u16> {
50 let args = unpack_command(cmd);
51 slot_for_command(&args)
52}
53
54fn unpack_command(cmd: &[u8]) -> Vec<Vec<u8>> {
61 let mut arg: Vec<u8> = Vec::new();
62 let mut args: Vec<Vec<u8>> = Vec::new();
63
64 let mut iter = cmd.iter().skip(2).peekable();
68
69 'outer: loop {
70 let b = *iter.next().unwrap();
71
72 if b == 13 && iter.peek().unwrap() == &&10 {
74 if arg.len() > 0 {
75 args.push(arg.clone());
76 arg.clear();
77 }
78
79 iter.next();
81
82 match iter.next() {
85 Some(_) => (),
86 None => break 'outer,
87 };
88 'inner: loop {
91 let b = *iter.next().unwrap();
92 if b == 13 && iter.peek().unwrap() == &&10 {
93 iter.next();
94 break 'inner;
95 }
96 }
97 } else {
98 arg.push(b);
99 }
100 }
101 args
102}