use kordophone::api::event_socket::{EventSocket, SocketEvent, SocketUpdate}; use kordophone::api::http_client::Credentials; use kordophone::api::http_client::HTTPAPIClient; use kordophone::api::InMemoryAuthenticationStore; use kordophone::APIInterface; use crate::printers::{ConversationPrinter, MessagePrinter}; use anyhow::Result; use clap::Subcommand; use kordophone::model::event::EventData; use kordophone::model::outgoing_message::OutgoingMessage; use futures_util::StreamExt; pub fn make_api_client_from_env() -> HTTPAPIClient { dotenv::dotenv().ok(); // read from env let base_url = std::env::var("KORDOPHONE_API_URL").expect("KORDOPHONE_API_URL must be set"); let credentials = Credentials { username: std::env::var("KORDOPHONE_USERNAME").expect("KORDOPHONE_USERNAME must be set"), password: std::env::var("KORDOPHONE_PASSWORD").expect("KORDOPHONE_PASSWORD must be set"), }; HTTPAPIClient::new( base_url.parse().unwrap(), InMemoryAuthenticationStore::new(Some(credentials)), ) } #[derive(Subcommand)] pub enum Commands { /// Prints all known conversations on the server. Conversations, /// Prints all messages in a conversation. Messages { conversation_id: String }, /// Prints the server Kordophone version. Version, /// Prints all events from the server. Events, /// Prints all raw updates from the server. RawUpdates, /// Sends a message to the server. SendMessage { conversation_id: String, message: String, }, /// Marks a conversation as read. Mark { conversation_id: String }, } impl Commands { pub async fn run(cmd: Commands) -> Result<()> { let mut client = ClientCli::new(); match cmd { Commands::Version => client.print_version().await, Commands::Conversations => client.print_conversations().await, Commands::Messages { conversation_id } => client.print_messages(conversation_id).await, Commands::RawUpdates => client.print_raw_updates().await, Commands::Events => client.print_events().await, Commands::SendMessage { conversation_id, message, } => client.send_message(conversation_id, message).await, Commands::Mark { conversation_id } => { client.mark_conversation_as_read(conversation_id).await } } } } struct ClientCli { api: HTTPAPIClient, } impl ClientCli { pub fn new() -> Self { let api = make_api_client_from_env(); Self { api } } pub async fn print_version(&mut self) -> Result<()> { let version = self.api.get_version().await?; println!("Version: {}", version); Ok(()) } pub async fn print_conversations(&mut self) -> Result<()> { let conversations = self.api.get_conversations().await?; for conversation in conversations { println!("{}", ConversationPrinter::new(&conversation.into())); } Ok(()) } pub async fn print_messages(&mut self, conversation_id: String) -> Result<()> { let messages = self .api .get_messages(&conversation_id, None, None, None) .await?; for message in messages { println!("{}", MessagePrinter::new(&message.into())); } Ok(()) } pub async fn print_events(&mut self) -> Result<()> { let socket = self.api.open_event_socket(None).await?; let (mut stream, _) = socket.events().await; while let Some(Ok(socket_event)) = stream.next().await { match socket_event { SocketEvent::Update(event) => match event.data { EventData::ConversationChanged(conversation) => { println!("Conversation changed: {}", conversation.guid); } EventData::MessageReceived(conversation, message) => { println!( "Message received: msg: {} conversation: {}", message.guid, conversation.guid ); } }, SocketEvent::Pong => { println!("Pong"); } } } Ok(()) } pub async fn print_raw_updates(&mut self) -> Result<()> { let socket = self.api.open_event_socket(None).await?; println!("Listening for raw updates..."); let mut stream = socket.raw_updates().await; loop { match stream.next().await.unwrap() { Ok(update) => { match update { SocketUpdate::Update(updates) => { for update in updates { println!("Got update: {:?}", update); } } SocketUpdate::Pong => { println!("Pong"); } } }, Err(e) => { println!("Update error: {:?}", e); break; } } } Ok(()) } pub async fn send_message(&mut self, conversation_id: String, message: String) -> Result<()> { let outgoing_message = OutgoingMessage::builder() .conversation_id(conversation_id) .text(message) .build(); let message = self.api.send_message(&outgoing_message).await?; println!("Message sent: {}", message.guid); Ok(()) } pub async fn mark_conversation_as_read(&mut self, conversation_id: String) -> Result<()> { self.api.mark_conversation_as_read(&conversation_id).await?; println!("Conversation marked as read: {}", conversation_id); Ok(()) } }