feox_server/protocol/command/
mod.rs

1use crate::protocol::resp::RespValue;
2use bytes::Bytes;
3
4mod client;
5mod executor;
6mod list;
7mod parser;
8
9pub use executor::CommandExecutor;
10
11#[derive(Debug, Clone)]
12pub enum Command {
13    // Basic commands
14    Get(Vec<u8>),
15    Set {
16        key: Vec<u8>,
17        value: Bytes,
18        ex: Option<u64>,
19        px: Option<u64>,
20    },
21    Del(Vec<Vec<u8>>),
22    Exists(Vec<Vec<u8>>),
23
24    // Atomic operations
25    Incr(Vec<u8>),
26    IncrBy {
27        key: Vec<u8>,
28        delta: i64,
29    },
30    Decr(Vec<u8>),
31    DecrBy {
32        key: Vec<u8>,
33        delta: i64,
34    },
35
36    // TTL commands
37    Expire {
38        key: Vec<u8>,
39        seconds: u64,
40    },
41    PExpire {
42        key: Vec<u8>,
43        milliseconds: u64,
44    },
45    Ttl(Vec<u8>),
46    PTtl(Vec<u8>),
47    Persist(Vec<u8>),
48
49    // Bulk operations
50    MGet(Vec<Vec<u8>>),
51    MSet(Vec<(Vec<u8>, Bytes)>),
52
53    // Server commands
54    Ping(Option<Bytes>),
55    Echo(Bytes),
56    Info(Option<String>),
57    Config {
58        action: String,
59        args: Vec<Bytes>,
60    },
61    Command,
62    Quit,
63    FlushDb,
64
65    // Key scanning
66    Keys(String), // Pattern
67    Scan {
68        cursor: Vec<u8>,
69        count: usize,
70        pattern: Option<String>,
71    },
72
73    // FeOx-specific
74    JsonPatch {
75        key: Vec<u8>,
76        patch: Bytes,
77    },
78    Cas {
79        key: Vec<u8>,
80        expected: Bytes,
81        new_value: Bytes,
82    },
83
84    // Authentication
85    Auth(Vec<u8>),
86
87    // List commands
88    LPush {
89        key: Vec<u8>,
90        values: Vec<Bytes>,
91    },
92    RPush {
93        key: Vec<u8>,
94        values: Vec<Bytes>,
95    },
96    LPop {
97        key: Vec<u8>,
98        count: Option<usize>,
99    },
100    RPop {
101        key: Vec<u8>,
102        count: Option<usize>,
103    },
104    LLen(Vec<u8>),
105    LRange {
106        key: Vec<u8>,
107        start: i64,
108        stop: i64,
109    },
110    LIndex {
111        key: Vec<u8>,
112        index: i64,
113    },
114
115    Subscribe(Vec<Vec<u8>>),
116    Unsubscribe(Option<Vec<Vec<u8>>>),
117    PSubscribe(Vec<Vec<u8>>),
118    PUnsubscribe(Option<Vec<Vec<u8>>>),
119    Publish {
120        channel: Vec<u8>,
121        message: Vec<u8>,
122    },
123    PubSub {
124        subcommand: String,
125        args: Vec<Vec<u8>>,
126    },
127
128    // Client management
129    Client {
130        subcommand: String,
131        args: Vec<Vec<u8>>,
132    },
133}
134
135impl Command {
136    /// Parse command from RESP array
137    #[inline(always)]
138    pub fn from_resp(value: RespValue) -> Result<Self, String> {
139        parser::parse_command(value)
140    }
141
142    /// Check if this is a pub/sub command
143    pub fn is_pubsub_command(&self) -> bool {
144        matches!(
145            self,
146            Command::Subscribe(_)
147                | Command::Unsubscribe(_)
148                | Command::PSubscribe(_)
149                | Command::PUnsubscribe(_)
150                | Command::Publish { .. }
151                | Command::PubSub { .. }
152        )
153    }
154
155    /// Check if this command is allowed in pub/sub mode
156    pub fn is_allowed_in_pubsub_mode(&self) -> bool {
157        matches!(
158            self,
159            Command::Subscribe(_)
160                | Command::Unsubscribe(_)
161                | Command::PSubscribe(_)
162                | Command::PUnsubscribe(_)
163                | Command::Ping(_)
164                | Command::Quit
165        )
166    }
167
168    /// Convert to PubSubOp if this is a pub/sub command
169    pub fn to_pubsub_op(self) -> Option<crate::network::PubSubOp> {
170        match self {
171            Command::Subscribe(channels) => Some(crate::network::PubSubOp::Subscribe(channels)),
172            Command::Unsubscribe(channels) => Some(crate::network::PubSubOp::Unsubscribe(channels)),
173            Command::PSubscribe(patterns) => Some(crate::network::PubSubOp::PSubscribe(patterns)),
174            Command::PUnsubscribe(patterns) => {
175                Some(crate::network::PubSubOp::PUnsubscribe(patterns))
176            }
177            Command::Publish { channel, message } => {
178                Some(crate::network::PubSubOp::Publish { channel, message })
179            }
180            Command::PubSub { subcommand, args } => match subcommand.to_uppercase().as_str() {
181                "CHANNELS" => Some(crate::network::PubSubOp::PubSubChannels {
182                    pattern: args.first().cloned(),
183                }),
184                "NUMSUB" => Some(crate::network::PubSubOp::PubSubNumSub { channels: args }),
185                "NUMPAT" => Some(crate::network::PubSubOp::PubSubNumPat),
186                _ => None,
187            },
188            _ => None,
189        }
190    }
191}