From ae411b6dcc24e5a92bc3a684c52c7941f6d04d64 Mon Sep 17 00:00:00 2001 From: Tobias Reisinger Date: Wed, 10 Apr 2024 17:36:51 +0200 Subject: [PATCH] Improve events Add known clients (cache) for leaving clients Add message to returned json object --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/command_utils/events.rs | 14 +++-- src/models/client.rs | 2 +- src/models/event.rs | 109 ++++++++++++++++++++++++++++++++---- src/parameter.rs | 2 +- ts-control | 10 ++-- 7 files changed, 117 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e5639b..c66e204 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,7 +182,7 @@ dependencies = [ [[package]] name = "teamspeak-query-lib" -version = "0.1.2" +version = "0.1.4" dependencies = [ "clap", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8930810..abc17c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "teamspeak-query-lib" -version = "0.1.2" +version = "0.1.4" edition = "2021" [dependencies] diff --git a/src/command_utils/events.rs b/src/command_utils/events.rs index b4a8773..00ccaca 100644 --- a/src/command_utils/events.rs +++ b/src/command_utils/events.rs @@ -1,6 +1,6 @@ use telnet::Telnet; -use crate::commands; -use crate::models::{Event, EventType}; +use crate::{commands, wrappers}; +use crate::models::{Client, Event, EventType}; use crate::response::Response; pub fn register_events(connection: &mut Telnet, events: Vec) -> Result<(), String> { @@ -12,10 +12,10 @@ pub fn register_events(connection: &mut Telnet, events: Vec) -> Resul Ok(()) } -pub fn handle_event_response(connection: &mut Telnet, response: Response) { +pub fn handle_event_response(connection: &mut Telnet, response: Response, known_clients: &mut Vec) { if let Response::Event(event_type, params) = response { - let event = Event::new(connection, event_type, params); + let event = Event::new(connection, event_type, params, &known_clients); match serde_json::to_string(&event) { Ok(json) => println!("{}", json), Err(err) => { @@ -24,13 +24,17 @@ pub fn handle_event_response(connection: &mut Telnet, response: Response) { } } + if let Ok(new_clients) = wrappers::get_clients(connection) { + *known_clients = new_clients; + } } } pub fn loop_response_reader(connection: &mut Telnet) { + let mut known_clients = wrappers::get_clients(connection).unwrap_or_else(|_| Vec::new()); loop { match commands::read_response(connection, true, String::new()) { - Ok(response) => handle_event_response(connection, response), + Ok(response) => handle_event_response(connection, response, &mut known_clients), Err(_) => { // print error? return; diff --git a/src/models/client.rs b/src/models/client.rs index fe38e06..41351e9 100644 --- a/src/models/client.rs +++ b/src/models/client.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::parameter::{parameter_find, ParameterList}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct Client { pub cid: i32, pub clid: i32, diff --git a/src/models/event.rs b/src/models/event.rs index 1d383c8..50360bd 100644 --- a/src/models/event.rs +++ b/src/models/event.rs @@ -1,7 +1,8 @@ use std::fmt::{Display, Formatter}; use std::str::FromStr; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, Serializer}; +use serde::ser::SerializeStruct; use telnet::Telnet; use crate::models::{Channel, Client}; @@ -43,7 +44,7 @@ pub enum EventType { NotifyConnectStatusChange, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Debug)] pub struct Event { pub event_type: EventType, pub params: ParameterList, @@ -152,36 +153,58 @@ impl Display for EventType { } impl EventType { + + pub fn find_channel(&self, connection: &mut Telnet, params: &ParameterList, param_name: &str) -> Option { + let id = parameter_find(params, param_name)? + .parse::().unwrap_or(0); + wrappers::find_channel(connection, "cid", &id.to_string(), true).unwrap().or(None) + } pub fn get_channel(&self, connection: &mut Telnet, params: &ParameterList) -> Option { match self { EventType::NotifyClientMoved => { - let id = parameter_find(params, "ctid")? - .parse::().unwrap_or(0); - wrappers::find_channel(connection, "cid", &id.to_string(), true).unwrap().or(None) + self.find_channel(connection, params, "ctid") } _ => None, } } + pub fn find_client(&self, connection: &mut Telnet, params: &ParameterList, param_name: &str) -> Option { + let id = parameter_find(params, param_name)? + .parse::().unwrap_or(0); + wrappers::find_client(connection, "clid", &id.to_string(), true).unwrap().or(None) + } + pub fn get_client(&self, connection: &mut Telnet, params: &ParameterList) -> Option { match self { EventType::NotifyClientMoved => { - let id = parameter_find(params, "clid")? - .parse::().unwrap_or(0); - wrappers::find_client(connection, "clid", &id.to_string(), true).unwrap().or(None) + self.find_client(connection, params, "clid") } EventType::NotifyClientEnterView => { Some(Client::from(params.clone())) } + EventType::NotifyTextMessage => { + self.find_client(connection, params, "invokerid") + } + EventType::NotifyClientPoke => { + self.find_client(connection, params, "invokerid") + } _ => None, } } } impl Event { - pub fn new(connection: &mut Telnet, event_type: EventType, params: ParameterList) -> Event { + pub fn new(connection: &mut Telnet, event_type: EventType, params: ParameterList, known_clients: &[Client]) -> Event { let channel = event_type.get_channel(connection, ¶ms); - let client = event_type.get_client(connection, ¶ms); + let mut client = event_type.get_client(connection, ¶ms); + + if client.is_none() { + let id = parameter_find(¶ms, "clid") + .unwrap_or_else(|| String::from("0")) + .parse::().unwrap_or(0); + let client_id = id.to_string(); + client = known_clients.iter().find(|c| c.clid.to_string() == client_id).cloned(); + } Event { event_type, @@ -190,4 +213,70 @@ impl Event { client, } } + + pub fn get_client_name(&self) -> String { + match &self.client { + Some(client) => client.client_nickname.clone(), + None => String::from("UNKNOWN"), + } + } + + pub fn get_channel_name(&self) -> String { + match &self.channel { + Some(channel) => channel.channel_name.clone(), + None => String::from("UNKNOWN"), + } + } + + pub fn get_event_msg(&self) -> String { + parameter_find(&self.params, "msg").unwrap_or_else(|| String::from("")) + } + + pub fn get_message(&self) -> String { + match &self.event_type { + EventType::NotifyClientPoke => { + format!("{}: {}", + self.get_client_name(), + self.get_event_msg() + ) + } + EventType::NotifyTextMessage => { + format!("{}: {}", + self.get_client_name(), + self.get_event_msg() + ) + } + EventType::NotifyClientMoved => { + format!("{} joined {}", + self.get_client_name(), + self.get_channel_name() + ) + } + EventType::NotifyClientLeftView => { + format!("{} left", + self.get_client_name() + ) + } + EventType::NotifyClientEnterView => { + format!("{} connected", + self.get_client_name() + ) + } + _ => String::from(""), + } + } +} + +impl Serialize for Event { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut x = serializer.serialize_struct("Event", 4)?; + x.serialize_field("type", &self.event_type)?; + x.serialize_field("channel", &self.channel)?; + x.serialize_field("client", &self.client)?; + x.serialize_field("message", &self.get_message())?; + x.end() + } } \ No newline at end of file diff --git a/src/parameter.rs b/src/parameter.rs index 6424ecb..206412b 100644 --- a/src/parameter.rs +++ b/src/parameter.rs @@ -44,7 +44,7 @@ pub fn parameter_parse(params_str: &str) -> ParameterList { let mut response_params = ParameterList::new(); parts.iter().for_each(|part| { - let (key, value) = part.split_once('=').unwrap_or((part, "1")); + let (key, value) = part.split_once('=').unwrap_or((part, "")); response_params.insert(key.to_string(), decode_value(value)); }); diff --git a/ts-control b/ts-control index 462cb7c..31adc4e 100755 --- a/ts-control +++ b/ts-control @@ -9,7 +9,7 @@ not away back message message-user -events-move" +events" _ts_control_get_entity() { entity=$(_ts_control_single_or_dmenu "$(teamspeak-query-lib "$1s")" "$2") @@ -98,8 +98,8 @@ case $action in message=$(_ts_control_get_message "$3") teamspeak-query-lib message --strict-client --client "$user" "$message" ;; - "events-move") - teamspeak-query-lib events NotifyClientMoved NotifyClientEnterView \ - | jq -r --unbuffered '.client.client_nickname + " joined " + .channel.channel_name // "the server"' \ - | tee >(xargs -I{} notify-send "TS3 movement" "{}") + "events") + teamspeak-query-lib events NotifyClientMoved NotifyClientEnterView NotifyClientLeftView NotifyTextMessage NotifyClientPoke \ + | jq -r --unbuffered '.message' \ + | tee >(xargs -I{} notify-send "TS3 Event" "{}") esac