use std::fmt::
{
Display,
Formatter,
Result,
};
use crate::network::MessageCode;
use std::net::TcpStream;
use crate::
{
options,
network::{ self, MessagePacket },
};
#[derive(Clone, PartialEq)]
pub enum Command
{
Exit, #[cfg(feature = "client_voice")] Voice, #[cfg(feature = "client_voice")] Mute, Channel, Help, Info, List, Files, #[cfg(feature = "client_screen")] Screens, Upload, Download, #[cfg(feature = "client_screen")] Screen, #[cfg(feature = "client_screen")] Attach, #[cfg(feature = "client_screen")] Deattach, PrivateMessage, UsernameColor, MessageColor, Invalid, }
pub struct CommandArg {
pub name: &'static str,
pub required: bool,
}
pub struct CommandInfo {
pub command: Command,
pub triggers: &'static [&'static str],
pub shortcut: Option<char>,
pub args: &'static [CommandArg],
pub description: &'static str,
}
pub const COMMAND_LIST: &[CommandInfo] =
&[
CommandInfo
{
command: Command::Help,
triggers: &[ "HELP", "H", "COMMANDS", "USAGE", "GUIDE" ],
shortcut: Some('h'),
args: &[],
description: "Prints all available commands",
},
CommandInfo
{
command: Command::Info,
triggers: &[ "INFO", "COMMAND", "MAN" ],
shortcut: None,
args: &[CommandArg { name: "COMMAND", required: true }],
description: "Shows command info",
},
#[cfg(feature = "client_voice")]
CommandInfo
{
command: Command::Voice,
triggers: &[ "VOICE", "VOIP", "CALL" ],
shortcut: None,
args: &[],
description: "Toggles voice chat",
},
#[cfg(feature = "client_voice")]
CommandInfo
{
command: Command::Mute,
triggers: &[ "MUTE", "UNMUTE", "SILENCE", "STFU" ],
shortcut: Some('s'),
args: &[CommandArg { name: "ID", required: false }],
description: "Toggle-mutes user/yourself",
},
CommandInfo
{
command: Command::Channel,
triggers: &[ "CHANNEL", "SWITCH", "CHECKOUT", "AREA" ],
shortcut: None,
args: &[CommandArg { name: "NAME", required: false }],
description: "Switches to channel/lobby if NAME is omitted",
},
CommandInfo
{
command: Command::Upload,
triggers: &[ "UPLOAD", "FILEUP", "PUSH", "UP" ],
shortcut: None,
args: &[CommandArg { name: "PATH", required: true }],
description: "Uploads file to server",
},
CommandInfo
{
command: Command::Download,
triggers: &[ "DOWNLOAD", "FILEDOWN", "PULL", "DOWN", "FETCH" ],
shortcut: None,
args:
&[
CommandArg { name: "USER ID", required: true },
CommandArg { name: "FILE ID", required: true },
],
description: "Downloads file from server",
},
#[cfg(feature = "client_screen")]
CommandInfo
{
command: Command::Screen,
triggers: &[ "SCREEN", "SCREENSHARE", "PRESENTATION", "SHARE" ],
shortcut: None,
args: &[],
description: "Toggles screensharing",
},
#[cfg(feature = "client_screen")]
CommandInfo
{
command: Command::Attach,
triggers: &[ "ATTACH", "WATCH", "DISPLAY", "JOIN" ],
shortcut: None,
args: &[CommandArg { name: "ID", required: true }],
description: "Attaches client screenshare.",
},
#[cfg(feature = "client_screen")]
CommandInfo
{
command: Command::Deattach,
triggers: &[ "DEATTACH", "STOP", "CLOSE" ],
shortcut: None,
args: &[],
description: "Dettaches client screenshare.",
},
CommandInfo
{
command: Command::List,
triggers: &[ "LIST", "USERS", "CLIENTS", "CHANNELS", "IDS", "ID" ],
shortcut: Some('l'),
args: &[],
description: "Shows connected users and their IDs",
},
CommandInfo
{
command: Command::Files,
triggers: &[ "FILES", "LISTFILES", "UPLOADS", "DOWNLOADS" ],
shortcut: Some('u'),
args: &[],
description: "Shows available files and their IDs",
},
#[cfg(feature = "client_screen")]
CommandInfo
{
command: Command::Screens,
triggers: &[ "SCREENS", "LISTSCREENS", "SCREENSHARES", "SHARES" ],
shortcut: None,
args: &[],
description: "Shows all screensharing clients.",
},
CommandInfo
{
command: Command::PrivateMessage,
triggers: &[ "PM", "DM", "MSG", "TELL" ],
shortcut: None,
args:
&[
CommandArg { name: "ID", required: true },
CommandArg { name: "MESSAGE", required: true },
],
description: "Sends private message",
},
CommandInfo
{
command: Command::UsernameColor,
triggers: &[ "UCOLOR", "USERNAME" ],
shortcut: None,
args: &[CommandArg { name: "COLOR", required: true }],
description: "Sets color of username",
},
CommandInfo
{
command: Command::MessageColor,
triggers: &[ "COLOR", "MESSAGE" ],
shortcut: None,
args: &[CommandArg { name: "COLOR", required: true }],
description: "Sets color of message",
},
CommandInfo
{
command: Command::Exit,
triggers: &[ "EXIT", "LEAVE", "QUIT", "DISCONNECT" ],
shortcut: Some('c'),
args: &[],
description: "Disconnects from the server",
},
];
pub const COMMAND_PREFIX: &str = "/";
impl Command
{
pub fn to_code(&self) -> Option<MessageCode>
{
match self
{
Command::Exit => Some(MessageCode::Disconnect),
#[cfg(feature = "client_voice")] Command::Voice => Some(MessageCode::Voice),
Command::Channel => Some(MessageCode::Channel),
Command::List => Some(MessageCode::List),
Command::PrivateMessage => Some(MessageCode::PrivateMessage),
Command::Upload => Some(MessageCode::Upload),
Command::Download => Some(MessageCode::Download),
#[cfg(feature = "client_screen")] Command::Screen => Some(MessageCode::Screen),
#[cfg(feature = "client_screen")] Command::Attach => Some(MessageCode::Attach),
#[cfg(feature = "client_screen")] Command::Deattach => Some(MessageCode::Deattach),
Command::Files => Some(MessageCode::Files),
#[cfg(feature = "client_screen")] Command::Screens => Some(MessageCode::Screens),
_ => None,
}
}
}
impl Display for Command
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result
{
let name = COMMAND_LIST.iter()
.find(|info| info.command == *self)
.map(|info| info.triggers[0].to_lowercase())
.unwrap_or_default();
write!(f, "{}{}", COMMAND_PREFIX, name)
}
}
pub fn get_command(input: &str) -> (Option<Command>, Option<String>) {
if !input.starts_with(COMMAND_PREFIX) { return (None, None); }
let no_prefix = &input[COMMAND_PREFIX.len()..]; let (command, parameters) = match no_prefix.split_once(' ') {
Some((command, parameters)) => (command.to_ascii_uppercase(), Some(parameters.trim().to_string())),
None => (no_prefix.to_ascii_uppercase(), None)
};
for info in COMMAND_LIST
{
if info.triggers.contains(&command.as_str())
{
return (Some(info.command.clone()), parameters);
}
}
(Some(Command::Invalid), None)
}
pub fn send_command_code(stream: &mut TcpStream, command: &Command, parameters: &Option<String>) -> bool {
if let Some(code) = command.to_code() && command != &Command::Upload
{
network::send(stream, MessagePacket
{
text: parameters.clone(),
code: Some(code),
..Default::default()
}, options::get_keys().as_ref());
true
} else { false }
}