1use std::fmt::
20{
21 Display,
22 Formatter,
23 Result,
24};
25
26use crate::network::MessageCode;
27
28use std::net::TcpStream;
29
30use crate::
31{
32 options,
33 network::{ self, MessagePacket },
34};
35
36#[derive(Clone, PartialEq)]
38pub enum Command
39{
40 Exit, Voice, Mute, Channel, Help, Info, List, Files, Upload, Download, PrivateMessage, UsernameColor, MessageColor, Invalid, }
55
56pub struct CommandArg {
59 pub name: &'static str,
60 pub required: bool,
61}
62
63pub struct CommandInfo {
65 pub command: Command,
66 pub triggers: &'static [&'static str],
67 pub shortcut: Option<char>,
68 pub args: &'static [CommandArg],
69 pub description: &'static str,
70}
71
72pub const COMMAND_LIST: &[CommandInfo] =
73&[
74 CommandInfo
75 {
76 command: Command::Help,
77 triggers: &[ "HELP", "H", "COMMANDS", "USAGE", "GUIDE" ],
78 shortcut: Some('h'),
79 args: &[],
80 description: "Prints all available commands",
81 },
82
83 CommandInfo
84 {
85 command: Command::Info,
86 triggers: &[ "INFO", "COMMAND", "MAN" ],
87 shortcut: None,
88 args: &[CommandArg { name: "COMMAND", required: true }],
89 description: "Shows command info",
90 },
91
92 CommandInfo
93 {
94 command: Command::Voice,
95 triggers: &[ "VOICE", "VOIP", "CALL" ],
96 shortcut: None,
97 args: &[],
98 description: "Toggles voice chat",
99 },
100
101 CommandInfo
102 {
103 command: Command::Mute,
104 triggers: &[ "MUTE", "UNMUTE", "SILENCE", "STFU" ],
105 shortcut: Some('s'),
106 args: &[CommandArg { name: "ID", required: false }],
107 description: "Toggle-mutes user/yourself",
108 },
109
110 CommandInfo
111 {
112 command: Command::Channel,
113 triggers: &[ "CHANNEL", "SWITCH", "CHECKOUT", "AREA" ],
114 shortcut: None,
115 args: &[CommandArg { name: "NAME", required: false }],
116 description: "Switches to channel/lobby if NAME is omitted",
117 },
118
119 CommandInfo
120 {
121 command: Command::Upload,
122 triggers: &[ "UPLOAD", "FILEUP", "PUSH", "UP" ],
123 shortcut: None,
124 args: &[CommandArg { name: "PATH", required: true }],
125 description: "Uploads file to server",
126 },
127
128 CommandInfo
129 {
130 command: Command::Download,
131 triggers: &[ "DOWNLOAD", "FILEDOWN", "PULL", "DOWN", "FETCH" ],
132 shortcut: None,
133 args:
134 &[
135 CommandArg { name: "USER ID", required: true },
136 CommandArg { name: "FILE ID", required: true },
137 ],
138 description: "Downloads file from server",
139 },
140
141 CommandInfo
142 {
143 command: Command::List,
144 triggers: &[ "LIST", "USERS", "CLIENTS", "CHANNELS", "IDS", "ID" ],
145 shortcut: Some('l'),
146 args: &[],
147 description: "Shows connected users and their IDs",
148 },
149
150 CommandInfo
151 {
152 command: Command::Files,
153 triggers: &[ "FILES", "LISTFILES", "UPLOADS", "DOWNLOADS", "SHARES" ],
154 shortcut: Some('u'),
155 args: &[],
156 description: "Shows available files and their IDs",
157 },
158
159 CommandInfo
160 {
161 command: Command::PrivateMessage,
162 triggers: &[ "PM", "DM", "MSG", "TELL" ],
163 shortcut: None,
164 args:
165 &[
166 CommandArg { name: "ID", required: true },
167 CommandArg { name: "MESSAGE", required: true },
168 ],
169 description: "Sends private message",
170 },
171
172 CommandInfo
173 {
174 command: Command::UsernameColor,
175 triggers: &[ "UCOLOR", "USERNAME" ],
176 shortcut: None,
177 args: &[CommandArg { name: "COLOR", required: true }],
178 description: "Sets color of username",
179 },
180
181 CommandInfo
182 {
183 command: Command::MessageColor,
184 triggers: &[ "COLOR", "MESSAGE" ],
185 shortcut: None,
186 args: &[CommandArg { name: "COLOR", required: true }],
187 description: "Sets color of message",
188 },
189
190 CommandInfo
191 {
192 command: Command::Exit,
193 triggers: &[ "EXIT", "LEAVE", "QUIT", "DISCONNECT" ],
194 shortcut: Some('c'),
195 args: &[],
196 description: "Disconnects from the server",
197 },
198];
199
200pub const COMMAND_PREFIX: &str = "/"; impl Command
205{
206 pub fn to_code(&self) -> Option<MessageCode>
208 {
209 match self
210 {
211 Command::Exit => Some(MessageCode::Disconnect),
212 Command::Voice => Some(MessageCode::Voice),
213 Command::Channel => Some(MessageCode::Channel),
214 Command::List => Some(MessageCode::List),
215 Command::PrivateMessage => Some(MessageCode::PrivateMessage),
216 Command::Upload => Some(MessageCode::Upload),
217 Command::Download => Some(MessageCode::Download),
218 Command::Files => Some(MessageCode::Files),
219
220 _ => None,
221 }
222 }
223}
224
225impl Display for Command
226{
227 fn fmt(&self, f: &mut Formatter<'_>) -> Result
229 {
230 let name = COMMAND_LIST.iter()
231 .find(|info| info.command == *self)
232 .map(|info| info.triggers[0].to_lowercase())
233 .unwrap_or_default(); write!(f, "{}{}", COMMAND_PREFIX, name)
236 }
237}
238
239pub fn get_command(input: &str) -> (Option<Command>, Option<String>) {
241 if !input.starts_with(COMMAND_PREFIX) { return (None, None); }
243
244 let no_prefix = &input[COMMAND_PREFIX.len()..]; let (command, parameters) = match no_prefix.split_once(' ') {
248 Some((command, parameters)) => (command.to_ascii_uppercase(), Some(parameters.trim().to_string())),
249 None => (no_prefix.to_ascii_uppercase(), None)
250 };
251
252 for info in COMMAND_LIST
254 {
255 if info.triggers.contains(&command.as_str())
256 {
257 return (Some(info.command.clone()), parameters);
258 }
259 }
260
261 (Some(Command::Invalid), None)
262}
263
264pub fn send_command_code(stream: &mut TcpStream, command: &Command, parameters: &Option<String>) -> bool {
266 if let Some(code) = command.to_code() && command != &Command::Upload
268 {
269 network::send(stream, MessagePacket
270 {
271 text: parameters.clone(),
272 code: Some(code),
273 ..Default::default()
274 }, options::get_keys().as_ref());
275 true
276 } else { false }
277}