Refactor and add message command
This commit is contained in:
parent
e87bed00a2
commit
fa959136be
8 changed files with 370 additions and 263 deletions
54
src/cli.rs
54
src/cli.rs
|
@ -4,7 +4,8 @@ use telnet::Telnet;
|
|||
use crate::parameter::{Parameter, ParameterList};
|
||||
use crate::response::channel::ResponseChannel;
|
||||
use crate::response::client::ResponseClient;
|
||||
use crate::utils;
|
||||
use crate::utils::SendTextMessageTarget;
|
||||
use crate::wrappers;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
|
@ -19,6 +20,7 @@ pub enum Commands {
|
|||
Channels(ChannelsArgs),
|
||||
Clients,
|
||||
Fetch(FetchArgs),
|
||||
Message(MessageArgs),
|
||||
Move(MoveArgs),
|
||||
Update(UpdateArgs),
|
||||
}
|
||||
|
@ -41,6 +43,17 @@ pub struct FetchArgs {
|
|||
client: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MessageArgs {
|
||||
#[arg(long)]
|
||||
strict_client: bool,
|
||||
#[arg(long)]
|
||||
client: Option<String>,
|
||||
#[arg(long)]
|
||||
server: bool,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MoveArgs {
|
||||
#[arg(long)]
|
||||
|
@ -76,31 +89,46 @@ impl FetchArgs {
|
|||
|
||||
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
||||
if let Some(channel) = &self.channel {
|
||||
utils::find_channel(connection, channel, self.strict_channel)
|
||||
wrappers::find_channel(connection, channel, self.strict_channel)
|
||||
} else {
|
||||
Err("No channel specified.".to_string())
|
||||
}
|
||||
}
|
||||
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
||||
if let Some(client) = &self.client {
|
||||
utils::find_client(connection, client, self.strict_client)
|
||||
wrappers::find_client(connection, client, self.strict_client)
|
||||
} else {
|
||||
Err("No client specified.".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageArgs {
|
||||
pub fn target(&self, connection: &mut Telnet) -> Result<SendTextMessageTarget, String> {
|
||||
if self.server {
|
||||
Ok(SendTextMessageTarget::Server)
|
||||
} else if let Some(client) = &self.client {
|
||||
if let Some(client) = wrappers::find_client(connection, client, self.strict_client)? {
|
||||
return Ok(SendTextMessageTarget::Client(client.cid));
|
||||
}
|
||||
return Err("Could not find client.".to_string());
|
||||
} else {
|
||||
Ok(SendTextMessageTarget::Channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MoveArgs {
|
||||
pub fn channel(&self, connection: &mut Telnet) -> Result<Option<ResponseChannel>, String> {
|
||||
utils::find_channel(connection, &self.channel, self.strict_channel)
|
||||
wrappers::find_channel(connection, &self.channel, self.strict_channel)
|
||||
}
|
||||
pub fn client(&self, connection: &mut Telnet) -> Result<Option<ResponseClient>, String> {
|
||||
match &self.client {
|
||||
Some(client) => {
|
||||
utils::find_client(connection, client, self.strict_client)
|
||||
wrappers::find_client(connection, client, self.strict_client)
|
||||
}
|
||||
None => {
|
||||
match utils::find_self(connection) {
|
||||
match wrappers::find_self(connection) {
|
||||
Ok(client) => Ok(Some(client)),
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
|
@ -114,24 +142,22 @@ impl UpdateArgs {
|
|||
let mut params: ParameterList = Vec::new();
|
||||
|
||||
if let Some(name) = &self.name {
|
||||
params.push(Parameter::new(String::from("client_nickname"), name.clone()));
|
||||
params.push(Parameter::new("client_nickname", name));
|
||||
}
|
||||
|
||||
if let Some(away) = &self.away {
|
||||
params.push(Parameter::new(String::from("client_away_message"), away.clone()));
|
||||
params.push(Parameter::new(String::from("client_away"), String::from("1")));
|
||||
params.push(Parameter::new("client_away_message", away));
|
||||
params.push(Parameter::new("client_away", "1"));
|
||||
}
|
||||
if self.back {
|
||||
params.push(Parameter::new(String::from("client_away"), String::from("0")));
|
||||
params.push(Parameter::new("client_away", "0"));
|
||||
}
|
||||
|
||||
if let Some(microphone) = self.microphone {
|
||||
let muted = u8::from(!microphone).to_string();
|
||||
params.push(Parameter::new(String::from("client_input_muted"), muted));
|
||||
params.push(Parameter::new("client_input_muted", &u8::from(!microphone).to_string()));
|
||||
}
|
||||
if let Some(speakers) = self.speakers {
|
||||
let muted = u8::from(!speakers).to_string();
|
||||
params.push(Parameter::new(String::from("client_output_muted"), muted));
|
||||
params.push(Parameter::new("client_output_muted", &u8::from(!speakers).to_string()));
|
||||
}
|
||||
|
||||
params
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::utils::SendTextMessageTarget;
|
||||
use telnet::Event::Data;
|
||||
use telnet::Telnet;
|
||||
|
||||
use crate::parameter::ParameterList;
|
||||
use crate::parameter::{Parameter, ParameterList};
|
||||
use crate::response::Response;
|
||||
|
||||
fn to_single_response(resp: Response) -> Response {
|
||||
|
@ -41,6 +42,7 @@ fn read_response_buffer(connection: &mut Telnet, buffer: &mut String) -> Result<
|
|||
}
|
||||
|
||||
fn send_command(connection: &mut Telnet, command: &str, skip_ok: bool) -> Result<Response, String> {
|
||||
let command = format!("{}\n\r", command);
|
||||
connection.write(command.as_bytes()).map_err(|_| "Failed to write to Teamspeak.")?;
|
||||
|
||||
read_response(connection, skip_ok, String::new())
|
||||
|
@ -68,40 +70,40 @@ fn read_response(connection: &mut Telnet, skip_ok: bool, mut buffer: String) ->
|
|||
}
|
||||
|
||||
pub fn login(connection: &mut Telnet, apikey: &str) -> Result<Response, String> {
|
||||
send_command(connection, &format!("auth apikey={}\n", apikey), false)
|
||||
send_command(connection, &format!("auth apikey={}", apikey), false)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_name(connection: &mut Telnet, name: &str) -> Result<Response, String> {
|
||||
send_command(connection, &format!("clientupdate client_nickname={}\n", name), true)
|
||||
send_command(connection, &format!("clientupdate client_nickname={}", name), true)
|
||||
}
|
||||
|
||||
pub fn channellist(connection: &mut Telnet) -> Result<Response, String> {
|
||||
send_command(connection, "channellist\n", true)
|
||||
send_command(connection, "channellist", true)
|
||||
}
|
||||
|
||||
pub fn clientlist(connection: &mut Telnet) -> Result<Response, String> {
|
||||
send_command(connection, "clientlist\n", true)
|
||||
send_command(connection, "clientlist", true)
|
||||
}
|
||||
|
||||
pub fn whoami(connection: &mut Telnet) -> Result<Response, String> {
|
||||
send_command(connection, "whoami\n", true).map(to_single_response)
|
||||
send_command(connection, "whoami", true).map(to_single_response)
|
||||
}
|
||||
|
||||
pub fn clientmove(connection: &mut Telnet, cid: &i32, clid_list: Vec<&i32>) -> Result<Response, String> {
|
||||
let clid_str = clid_list
|
||||
.iter()
|
||||
.map(|clid| format!("clid={}", clid))
|
||||
.collect::<Vec<String>>()
|
||||
.join("|");
|
||||
send_command(connection, &format!("clientmove cid={} {}\n", cid, clid_str), false)
|
||||
let clid_param_list = clid_list
|
||||
.into_iter()
|
||||
.map(|clid| Parameter::new("clid", &clid.to_string()))
|
||||
.collect::<Vec<Parameter>>();
|
||||
let clid_str = Parameter::list_to_string_sep(clid_param_list, "|");
|
||||
send_command(connection, &format!("clientmove cid={} {}", cid, clid_str), false)
|
||||
}
|
||||
|
||||
pub fn clientupdate(connection: &mut Telnet, parameters: &ParameterList) -> Result<Response, String> {
|
||||
let parameters_str = parameters
|
||||
.iter()
|
||||
.map(|param| format!("{}={}", param.name, param.value))
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
send_command(connection, &format!("clientupdate {}\n", parameters_str), false)
|
||||
}
|
||||
pub fn clientupdate(connection: &mut Telnet, parameters: ParameterList) -> Result<Response, String> {
|
||||
let parameters_str = Parameter::list_to_string(parameters);
|
||||
send_command(connection, &format!("clientupdate {}", parameters_str), false)
|
||||
}
|
||||
|
||||
pub fn sendtextmessage(connection: &mut Telnet, target: SendTextMessageTarget, msg: String) -> Result<Response, String> {
|
||||
let msg = String::from(Parameter::new("msg", &msg));
|
||||
send_command(connection, &format!("sendtextmessage {} {}", msg, String::from(target)), false) }
|
||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -7,10 +7,11 @@ use crate::response::channel::ResponseChannel;
|
|||
use crate::response::client::ResponseClient;
|
||||
|
||||
mod response;
|
||||
mod utils;
|
||||
mod wrappers;
|
||||
mod commands;
|
||||
mod parameter;
|
||||
mod cli;
|
||||
mod utils;
|
||||
|
||||
fn channel_or_exit(channel_res: Result<Option<ResponseChannel>, String>) -> ResponseChannel {
|
||||
channel_res.unwrap_or_else(|err| {
|
||||
|
@ -44,14 +45,14 @@ fn main() {
|
|||
}
|
||||
let mut connection = connection.unwrap();
|
||||
|
||||
utils::skip_welcome(&mut connection);
|
||||
utils::login(&mut connection);
|
||||
wrappers::skip_welcome(&mut connection);
|
||||
wrappers::login(&mut connection);
|
||||
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level cmd
|
||||
match &cli {
|
||||
match cli {
|
||||
Commands::Channels(args) => {
|
||||
match utils::get_channels(&mut connection, args.spacers) {
|
||||
match wrappers::get_channels(&mut connection, args.spacers) {
|
||||
Ok(channels) => {
|
||||
for channel in channels {
|
||||
println!("{}", channel.channel_name);
|
||||
|
@ -65,7 +66,7 @@ fn main() {
|
|||
}
|
||||
|
||||
Commands::Clients => {
|
||||
match utils::get_clients(&mut connection) {
|
||||
match wrappers::get_clients(&mut connection) {
|
||||
Ok(clients) => {
|
||||
for client in clients {
|
||||
println!("{}", client.client_nickname);
|
||||
|
@ -91,7 +92,7 @@ fn main() {
|
|||
if args.want_client() {
|
||||
let client = client_or_exit(args.client(&mut connection));
|
||||
|
||||
match utils::fetch_client(&mut connection, &[client]) {
|
||||
match wrappers::fetch_client(&mut connection, &[client]) {
|
||||
Ok(_) => println!("Successfully fetched client."),
|
||||
Err(msg) => {
|
||||
println!("Failed to fetch client: {}", msg);
|
||||
|
@ -103,7 +104,7 @@ fn main() {
|
|||
if args.want_channel() {
|
||||
let channel = channel_or_exit(args.channel(&mut connection));
|
||||
|
||||
match utils::fetch_channel(&mut connection, channel) {
|
||||
match wrappers::fetch_channel(&mut connection, channel) {
|
||||
Ok(_) => println!("Successfully fetched channel."),
|
||||
Err(msg) => {
|
||||
println!("Failed to fetch channel: {}", msg);
|
||||
|
@ -113,11 +114,26 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
Commands::Message(args) => {
|
||||
let target = args.target(&mut connection).unwrap_or_else(|err| {
|
||||
println!("Failed to get message target: {}", err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
match wrappers::send_text_message(&mut connection, target, args.message) {
|
||||
Ok(_) => println!("Successfully sent message."),
|
||||
Err(msg) => {
|
||||
println!("Failed to send message: {}", msg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Commands::Move(args) => {
|
||||
let channel = channel_or_exit(args.channel(&mut connection));
|
||||
let client = client_or_exit(args.client(&mut connection));
|
||||
|
||||
match utils::move_client(&mut connection, &channel, &[client]) {
|
||||
match wrappers::move_client(&mut connection, &channel, &[client]) {
|
||||
Ok(resp) => println!("Successfully moved client: {}", resp),
|
||||
Err(msg) => {
|
||||
println!("Failed to move client: {}", msg);
|
||||
|
@ -127,7 +143,7 @@ fn main() {
|
|||
}
|
||||
|
||||
Commands::Update(args) => {
|
||||
match utils::update_client(&mut connection, &args.to_parameter_list()) {
|
||||
match wrappers::update_client(&mut connection, args.to_parameter_list()) {
|
||||
Ok(_) => println!("Successfully updated client."),
|
||||
Err(msg) => {
|
||||
println!("Failed to update client: {}", msg);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::fmt::{Debug, Display, Formatter};
|
||||
use crate::utils::{decode_value, encode_value};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Parameter {
|
||||
|
@ -49,19 +50,15 @@ pub fn parameter_parse(params_str: &str) -> ParameterList {
|
|||
|
||||
impl From<(&str, &str)> for Parameter {
|
||||
fn from(param: (&str, &str)) -> Parameter {
|
||||
Parameter::new(String::from(param.0), String::from(param.1))
|
||||
Parameter::new(param.0, param.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
pub fn new(name: String, value: String) -> Parameter {
|
||||
let value = value
|
||||
.replace("\\s", " ")
|
||||
.replace("\\p", "|");
|
||||
|
||||
pub fn new(name: &str, value: &str) -> Parameter {
|
||||
Parameter {
|
||||
name,
|
||||
value,
|
||||
name: String::from(name),
|
||||
value: decode_value(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +78,22 @@ impl Parameter {
|
|||
pub fn to_i32(&self, default: i32) -> i32 {
|
||||
self.value.parse::<i32>().unwrap_or(default)
|
||||
}
|
||||
|
||||
pub fn list_to_string(parameter_list: ParameterList) -> String {
|
||||
parameter_list
|
||||
.into_iter()
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub fn list_to_string_sep(parameter_list: ParameterList, sep: &str) -> String {
|
||||
parameter_list
|
||||
.into_iter()
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>()
|
||||
.join(sep)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Parameter {
|
||||
|
@ -97,6 +110,12 @@ impl Debug for Parameter {
|
|||
|
||||
impl Default for Parameter {
|
||||
fn default() -> Self {
|
||||
Parameter::new(String::from(""), String::from(""))
|
||||
Parameter::new("", "")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Parameter> for String {
|
||||
fn from(value: Parameter) -> Self {
|
||||
format!("{}={}", value.name, encode_value(&value.value))
|
||||
}
|
||||
}
|
|
@ -93,10 +93,10 @@ impl ResponseError {
|
|||
fn create_error(params: &Vec<Parameter>) -> ResponseError {
|
||||
ResponseError {
|
||||
id: parameter_find(params, "id")
|
||||
.unwrap_or_else(|| Parameter::new(String::from("id"), String::from("-1")))
|
||||
.unwrap_or_else(|| Parameter::new("id", "-1"))
|
||||
.to_i32(-1),
|
||||
msg: parameter_find(params, "msg")
|
||||
.unwrap_or_else(|| Parameter::new(String::from("msg"), String::from("Unknown error.")))
|
||||
.unwrap_or_else(|| Parameter::new("msg", "Unknown error."))
|
||||
.value,
|
||||
}
|
||||
}
|
||||
|
|
237
src/utils.rs
237
src/utils.rs
|
@ -1,208 +1,39 @@
|
|||
use std::process::exit;
|
||||
use std::time::Duration;
|
||||
use crate::parameter::Parameter;
|
||||
|
||||
use telnet::Event::TimedOut;
|
||||
use telnet::Telnet;
|
||||
pub fn decode_value(value: &str) -> String {
|
||||
value
|
||||
.replace("\\s", " ")
|
||||
.replace("\\p", "|")
|
||||
}
|
||||
|
||||
use crate::{commands, parameter};
|
||||
use crate::parameter::{parameter_list_find_all, ParameterList};
|
||||
use crate::response::channel::ResponseChannel;
|
||||
use crate::response::client::ResponseClient;
|
||||
use crate::response::Response;
|
||||
pub fn encode_value(value: &str) -> String {
|
||||
value
|
||||
.replace(' ', "\\s")
|
||||
.replace('|', "\\p")
|
||||
}
|
||||
|
||||
pub fn skip_welcome(connection: &mut Telnet) {
|
||||
loop {
|
||||
let event_result = connection.read_timeout(Duration::from_millis(100));
|
||||
match event_result {
|
||||
Ok(event) => {
|
||||
if let TimedOut = event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(_) => println!("Failed to read from Teamspeak."),
|
||||
}
|
||||
pub enum SendTextMessageTarget {
|
||||
Client(i32),
|
||||
Channel,
|
||||
Server,
|
||||
}
|
||||
|
||||
impl From<SendTextMessageTarget> for String {
|
||||
fn from(value: SendTextMessageTarget) -> Self {
|
||||
let target_mode = match value {
|
||||
SendTextMessageTarget::Client(_) => "1",
|
||||
SendTextMessageTarget::Channel => "2",
|
||||
SendTextMessageTarget::Server => "3",
|
||||
};
|
||||
|
||||
let target = match value {
|
||||
SendTextMessageTarget::Client(id) => id.to_string(),
|
||||
_ => String::from("0"),
|
||||
};
|
||||
|
||||
Parameter::list_to_string(vec![
|
||||
Parameter::new("targetmode", target_mode),
|
||||
Parameter::new("target", &target)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn login(connection: &mut Telnet) {
|
||||
// read api key from environment variable
|
||||
let apikey = std::env::var("TS3_CLIENT_API_KEY").unwrap_or_else(|_| {
|
||||
println!("No API key found in environment variable TS3_CLIENT_API_KEY.");
|
||||
exit(1);
|
||||
});
|
||||
|
||||
match commands::login(connection, &apikey) {
|
||||
Ok(_) => {}
|
||||
Err(msg) => {
|
||||
println!("Failed to authenticate with Teamspeak: {}", msg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_channels(connection: &mut Telnet, spacers: bool) -> Result<Vec<ResponseChannel>, String> {
|
||||
match commands::channellist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let channels: Vec<ResponseChannel> = parameter_lists.iter()
|
||||
.map(|params| ResponseChannel::from(params.clone()))
|
||||
.collect();
|
||||
let mut channels = ResponseChannel::sort_list(channels);
|
||||
if !spacers {
|
||||
channels.retain(|c| !c.is_spacer());
|
||||
}
|
||||
Ok(channels)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_channel(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseChannel>, String> {
|
||||
match commands::channellist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "channel_name", name, strict) {
|
||||
Some(params) => {
|
||||
Ok(Some(ResponseChannel::from(params)))
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_clients(connection: &mut Telnet) -> Result<Vec<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let mut clients: Vec<ResponseClient> = parameter_lists.iter()
|
||||
.map(|params| ResponseClient::from(params.clone()))
|
||||
.collect();
|
||||
|
||||
clients.sort_by(|a, b| a.client_nickname.cmp(&b.client_nickname));
|
||||
|
||||
Ok(clients)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_client(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "client_nickname", name, strict) {
|
||||
Some(params) => {
|
||||
Ok(Some(ResponseClient::from(params)))
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_channel_clients(connection: &mut Telnet, channel: &ResponseChannel) -> Result<Vec<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let mut clients: Vec<ResponseClient> = Vec::new();
|
||||
for client_params in parameter_list_find_all(¶meter_lists, "cid", &channel.cid.to_string(), true) {
|
||||
clients.push(ResponseClient::from(client_params));
|
||||
}
|
||||
Ok(clients)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_self_clid(connection: &mut Telnet) -> Result<String, String> {
|
||||
match commands::whoami(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::Data(params) => {
|
||||
match parameter::parameter_find(¶ms, "clid") {
|
||||
None => Err(String::from("Could not find clid in response from Teamspeak.")),
|
||||
Some(param) => Ok(param.value)
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak for whoami."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_self(connection: &mut Telnet) -> Result<ResponseClient, String> {
|
||||
let clid = get_self_clid(connection)?;
|
||||
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "clid", &clid, false) {
|
||||
Some(params) => {
|
||||
Ok(ResponseClient::from(params))
|
||||
}
|
||||
None => {
|
||||
Err(String::from("Could not find self in response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak for clientlist."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_client(connection: &mut Telnet, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||
let cid = find_self(connection)?.cid;
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn fetch_channel(connection: &mut Telnet, channel: ResponseChannel) -> Result<Response, String> {
|
||||
let cid = find_self(connection)?.cid;
|
||||
|
||||
let clients = get_channel_clients(connection, &channel)?;
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn move_client(connection: &mut Telnet, channel: &ResponseChannel, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &channel.cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn update_client(connection: &mut Telnet, parameters: &ParameterList) -> Result<Response, String> {
|
||||
commands::clientupdate(connection, parameters)
|
||||
}
|
213
src/wrappers.rs
Normal file
213
src/wrappers.rs
Normal file
|
@ -0,0 +1,213 @@
|
|||
use std::process::exit;
|
||||
use std::time::Duration;
|
||||
|
||||
use telnet::Event::TimedOut;
|
||||
use telnet::Telnet;
|
||||
|
||||
use crate::{commands, parameter};
|
||||
use crate::parameter::{parameter_list_find_all, ParameterList};
|
||||
use crate::response::channel::ResponseChannel;
|
||||
use crate::response::client::ResponseClient;
|
||||
use crate::response::Response;
|
||||
use crate::utils::SendTextMessageTarget;
|
||||
|
||||
pub fn skip_welcome(connection: &mut Telnet) {
|
||||
loop {
|
||||
let event_result = connection.read_timeout(Duration::from_millis(100));
|
||||
match event_result {
|
||||
Ok(event) => {
|
||||
if let TimedOut = event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Err(_) => println!("Failed to read from Teamspeak."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn login(connection: &mut Telnet) {
|
||||
// read api key from environment variable
|
||||
let apikey = std::env::var("TS3_CLIENT_API_KEY").unwrap_or_else(|_| {
|
||||
println!("No API key found in environment variable TS3_CLIENT_API_KEY.");
|
||||
exit(1);
|
||||
});
|
||||
|
||||
match commands::login(connection, &apikey) {
|
||||
Ok(_) => {}
|
||||
Err(msg) => {
|
||||
println!("Failed to authenticate with Teamspeak: {}", msg);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_channels(connection: &mut Telnet, spacers: bool) -> Result<Vec<ResponseChannel>, String> {
|
||||
match commands::channellist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let channels: Vec<ResponseChannel> = parameter_lists.iter()
|
||||
.map(|params| ResponseChannel::from(params.clone()))
|
||||
.collect();
|
||||
let mut channels = ResponseChannel::sort_list(channels);
|
||||
if !spacers {
|
||||
channels.retain(|c| !c.is_spacer());
|
||||
}
|
||||
Ok(channels)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_channel(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseChannel>, String> {
|
||||
match commands::channellist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "channel_name", name, strict) {
|
||||
Some(params) => {
|
||||
Ok(Some(ResponseChannel::from(params)))
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_clients(connection: &mut Telnet) -> Result<Vec<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let mut clients: Vec<ResponseClient> = parameter_lists.iter()
|
||||
.map(|params| ResponseClient::from(params.clone()))
|
||||
.collect();
|
||||
|
||||
clients.sort_by(|a, b| a.client_nickname.cmp(&b.client_nickname));
|
||||
|
||||
Ok(clients)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_client(connection: &mut Telnet, name: &str, strict: bool) -> Result<Option<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "client_nickname", name, strict) {
|
||||
Some(params) => {
|
||||
Ok(Some(ResponseClient::from(params)))
|
||||
}
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_channel_clients(connection: &mut Telnet, channel: &ResponseChannel) -> Result<Vec<ResponseClient>, String> {
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
let mut clients: Vec<ResponseClient> = Vec::new();
|
||||
for client_params in parameter_list_find_all(¶meter_lists, "cid", &channel.cid.to_string(), true) {
|
||||
clients.push(ResponseClient::from(client_params));
|
||||
}
|
||||
Ok(clients)
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_self_clid(connection: &mut Telnet) -> Result<String, String> {
|
||||
match commands::whoami(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::Data(params) => {
|
||||
match parameter::parameter_find(¶ms, "clid") {
|
||||
None => Err(String::from("Could not find clid in response from Teamspeak.")),
|
||||
Some(param) => Ok(param.value)
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak for whoami."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_self(connection: &mut Telnet) -> Result<ResponseClient, String> {
|
||||
let clid = get_self_clid(connection)?;
|
||||
|
||||
match commands::clientlist(connection) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
Response::DataList(parameter_lists) => {
|
||||
match parameter::parameter_list_find(¶meter_lists, "clid", &clid, false) {
|
||||
Some(params) => {
|
||||
Ok(ResponseClient::from(params))
|
||||
}
|
||||
None => {
|
||||
Err(String::from("Could not find self in response from Teamspeak."))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Err(String::from("Received unexpected response from Teamspeak for clientlist."))
|
||||
}
|
||||
}
|
||||
Err(msg) => Err(msg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fetch_client(connection: &mut Telnet, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||
let cid = find_self(connection)?.cid;
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn fetch_channel(connection: &mut Telnet, channel: ResponseChannel) -> Result<Response, String> {
|
||||
let cid = find_self(connection)?.cid;
|
||||
|
||||
let clients = get_channel_clients(connection, &channel)?;
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn move_client(connection: &mut Telnet, channel: &ResponseChannel, clients: &[ResponseClient]) -> Result<Response, String> {
|
||||
let clid_list: Vec<&i32> = clients.iter().map(|c| &c.clid).collect();
|
||||
|
||||
commands::clientmove(connection, &channel.cid, clid_list)
|
||||
}
|
||||
|
||||
pub fn update_client(connection: &mut Telnet, parameters: ParameterList) -> Result<Response, String> {
|
||||
commands::clientupdate(connection, parameters)
|
||||
}
|
||||
|
||||
pub fn send_text_message(connection: &mut Telnet, target: SendTextMessageTarget, msg: String) -> Result<Response, String> {
|
||||
commands::sendtextmessage(connection, target, msg)
|
||||
}
|
10
ts-control
10
ts-control
|
@ -9,7 +9,7 @@ back"
|
|||
action=$(echo "$actions" | $DMENU)
|
||||
|
||||
|
||||
ts_control_move_self() {
|
||||
_ts_control_move_self() {
|
||||
channel=$(teamspeak-query-lib channels | $DMENU)
|
||||
if [ -z "$channel" ]; then
|
||||
return 1
|
||||
|
@ -18,7 +18,7 @@ ts_control_move_self() {
|
|||
return 0
|
||||
}
|
||||
|
||||
ts_control_fetch() {
|
||||
_ts_control_fetch() {
|
||||
target=$(teamspeak-query-lib "$1s" | $DMENU)
|
||||
if [ -z "$target" ]; then
|
||||
exit 1
|
||||
|
@ -28,13 +28,13 @@ ts_control_fetch() {
|
|||
|
||||
case $action in
|
||||
"move")
|
||||
ts_control_move_self
|
||||
_ts_control_move_self
|
||||
;;
|
||||
"fetch-client")
|
||||
ts_control_fetch client
|
||||
_ts_control_fetch client
|
||||
;;
|
||||
"fetch-channel")
|
||||
ts_control_fetch channel
|
||||
_ts_control_fetch channel
|
||||
;;
|
||||
"not away")
|
||||
teamspeak-query-lib move "Not Away From Keyboard"
|
||||
|
|
Loading…
Reference in a new issue