cargo fmt
This commit is contained in:
@@ -10,14 +10,12 @@ fn main() {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let xml = std::fs::read_to_string(KORDOPHONE_XML)
|
||||
.expect("Error reading server dbus interface");
|
||||
let xml = std::fs::read_to_string(KORDOPHONE_XML).expect("Error reading server dbus interface");
|
||||
|
||||
let output = dbus_codegen::generate(&xml, &opts)
|
||||
.expect("Error generating client dbus interface");
|
||||
let output =
|
||||
dbus_codegen::generate(&xml, &opts).expect("Error generating client dbus interface");
|
||||
|
||||
std::fs::write(out_path, output)
|
||||
.expect("Error writing client dbus code");
|
||||
std::fs::write(out_path, output).expect("Error writing client dbus code");
|
||||
|
||||
println!("cargo:rerun-if-changed={}", KORDOPHONE_XML);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use kordophone::APIInterface;
|
||||
use kordophone::api::http_client::HTTPAPIClient;
|
||||
use kordophone::api::http_client::Credentials;
|
||||
use kordophone::api::InMemoryAuthenticationStore;
|
||||
use kordophone::api::event_socket::EventSocket;
|
||||
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 crate::printers::{ConversationPrinter, MessagePrinter};
|
||||
use kordophone::model::event::EventData;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
|
||||
@@ -16,18 +16,18 @@ pub fn make_api_client_from_env() -> HTTPAPIClient<InMemoryAuthenticationStore>
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
// read from env
|
||||
let base_url = std::env::var("KORDOPHONE_API_URL")
|
||||
.expect("KORDOPHONE_API_URL must be set");
|
||||
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"),
|
||||
username: std::env::var("KORDOPHONE_USERNAME").expect("KORDOPHONE_USERNAME must be set"),
|
||||
|
||||
password: std::env::var("KORDOPHONE_PASSWORD")
|
||||
.expect("KORDOPHONE_PASSWORD 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)))
|
||||
HTTPAPIClient::new(
|
||||
base_url.parse().unwrap(),
|
||||
InMemoryAuthenticationStore::new(Some(credentials)),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@@ -36,9 +36,7 @@ pub enum Commands {
|
||||
Conversations,
|
||||
|
||||
/// Prints all messages in a conversation.
|
||||
Messages {
|
||||
conversation_id: String,
|
||||
},
|
||||
Messages { conversation_id: String },
|
||||
|
||||
/// Prints the server Kordophone version.
|
||||
Version,
|
||||
@@ -65,7 +63,10 @@ impl Commands {
|
||||
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::SendMessage {
|
||||
conversation_id,
|
||||
message,
|
||||
} => client.send_message(conversation_id, message).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +97,10 @@ impl ClientCli {
|
||||
}
|
||||
|
||||
pub async fn print_messages(&mut self, conversation_id: String) -> Result<()> {
|
||||
let messages = self.api.get_messages(&conversation_id, None, None, None).await?;
|
||||
let messages = self
|
||||
.api
|
||||
.get_messages(&conversation_id, None, None, None)
|
||||
.await?;
|
||||
for message in messages {
|
||||
println!("{}", MessagePrinter::new(&message.into()));
|
||||
}
|
||||
@@ -113,8 +117,11 @@ impl ClientCli {
|
||||
println!("Conversation changed: {}", conversation.guid);
|
||||
}
|
||||
EventData::MessageReceived(conversation, message) => {
|
||||
println!("Message received: msg: {} conversation: {}", message.guid, conversation.guid);
|
||||
}
|
||||
println!(
|
||||
"Message received: msg: {} conversation: {}",
|
||||
message.guid, conversation.guid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -143,5 +150,3 @@ impl ClientCli {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::printers::{ConversationPrinter, MessagePrinter};
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
use dbus::blocking::{Connection, Proxy};
|
||||
use prettytable::table;
|
||||
use crate::printers::{ConversationPrinter, MessagePrinter};
|
||||
|
||||
const DBUS_NAME: &str = "net.buzzert.kordophonecd";
|
||||
const DBUS_PATH: &str = "/net/buzzert/kordophonecd/daemon";
|
||||
@@ -21,9 +21,7 @@ pub enum Commands {
|
||||
Conversations,
|
||||
|
||||
/// Runs a full sync operation for a conversation and its messages.
|
||||
Sync {
|
||||
conversation_id: Option<String>,
|
||||
},
|
||||
Sync { conversation_id: Option<String> },
|
||||
|
||||
/// Runs a sync operation for the conversation list.
|
||||
SyncList,
|
||||
@@ -31,7 +29,7 @@ pub enum Commands {
|
||||
/// Prints the server Kordophone version.
|
||||
Version,
|
||||
|
||||
/// Configuration options
|
||||
/// Configuration options
|
||||
Config {
|
||||
#[command(subcommand)]
|
||||
command: ConfigCommands,
|
||||
@@ -62,14 +60,10 @@ pub enum ConfigCommands {
|
||||
Print,
|
||||
|
||||
/// Sets the server URL.
|
||||
SetServerUrl {
|
||||
url: String,
|
||||
},
|
||||
SetServerUrl { url: String },
|
||||
|
||||
/// Sets the username.
|
||||
SetUsername {
|
||||
username: String,
|
||||
},
|
||||
SetUsername { username: String },
|
||||
}
|
||||
|
||||
impl Commands {
|
||||
@@ -82,9 +76,19 @@ impl Commands {
|
||||
Commands::SyncList => client.sync_conversations_list().await,
|
||||
Commands::Config { command } => client.config(command).await,
|
||||
Commands::Signals => client.wait_for_signals().await,
|
||||
Commands::Messages { conversation_id, last_message_id } => client.print_messages(conversation_id, last_message_id).await,
|
||||
Commands::Messages {
|
||||
conversation_id,
|
||||
last_message_id,
|
||||
} => {
|
||||
client
|
||||
.print_messages(conversation_id, last_message_id)
|
||||
.await
|
||||
}
|
||||
Commands::DeleteAllConversations => client.delete_all_conversations().await,
|
||||
Commands::SendMessage { conversation_id, text } => client.enqueue_outgoing_message(conversation_id, text).await,
|
||||
Commands::SendMessage {
|
||||
conversation_id,
|
||||
text,
|
||||
} => client.enqueue_outgoing_message(conversation_id, text).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,12 +100,13 @@ struct DaemonCli {
|
||||
impl DaemonCli {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
conn: Connection::new_session()?
|
||||
conn: Connection::new_session()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn proxy(&self) -> Proxy<&Connection> {
|
||||
self.conn.with_proxy(DBUS_NAME, DBUS_PATH, std::time::Duration::from_millis(5000))
|
||||
self.conn
|
||||
.with_proxy(DBUS_NAME, DBUS_PATH, std::time::Duration::from_millis(5000))
|
||||
}
|
||||
|
||||
pub async fn print_version(&mut self) -> Result<()> {
|
||||
@@ -117,7 +122,7 @@ impl DaemonCli {
|
||||
for conversation in conversations {
|
||||
println!("{}", ConversationPrinter::new(&conversation.into()));
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -136,8 +141,16 @@ impl DaemonCli {
|
||||
.map_err(|e| anyhow::anyhow!("Failed to sync conversations: {}", e))
|
||||
}
|
||||
|
||||
pub async fn print_messages(&mut self, conversation_id: String, last_message_id: Option<String>) -> Result<()> {
|
||||
let messages = KordophoneRepository::get_messages(&self.proxy(), &conversation_id, &last_message_id.unwrap_or_default())?;
|
||||
pub async fn print_messages(
|
||||
&mut self,
|
||||
conversation_id: String,
|
||||
last_message_id: Option<String>,
|
||||
) -> Result<()> {
|
||||
let messages = KordophoneRepository::get_messages(
|
||||
&self.proxy(),
|
||||
&conversation_id,
|
||||
&last_message_id.unwrap_or_default(),
|
||||
)?;
|
||||
println!("Number of messages: {}", messages.len());
|
||||
|
||||
for message in messages {
|
||||
@@ -147,8 +160,13 @@ impl DaemonCli {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn enqueue_outgoing_message(&mut self, conversation_id: String, text: String) -> Result<()> {
|
||||
let outgoing_message_id = KordophoneRepository::send_message(&self.proxy(), &conversation_id, &text)?;
|
||||
pub async fn enqueue_outgoing_message(
|
||||
&mut self,
|
||||
conversation_id: String,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let outgoing_message_id =
|
||||
KordophoneRepository::send_message(&self.proxy(), &conversation_id, &text)?;
|
||||
println!("Outgoing message ID: {}", outgoing_message_id);
|
||||
Ok(())
|
||||
}
|
||||
@@ -159,10 +177,12 @@ impl DaemonCli {
|
||||
pub use super::dbus_interface::NetBuzzertKordophoneRepositoryConversationsUpdated as ConversationsUpdated;
|
||||
}
|
||||
|
||||
let _id = self.proxy().match_signal(|h: dbus_signals::ConversationsUpdated, _: &Connection, _: &Message| {
|
||||
println!("Signal: Conversations updated");
|
||||
true
|
||||
});
|
||||
let _id = self.proxy().match_signal(
|
||||
|h: dbus_signals::ConversationsUpdated, _: &Connection, _: &Message| {
|
||||
println!("Signal: Conversations updated");
|
||||
true
|
||||
},
|
||||
);
|
||||
|
||||
println!("Waiting for signals...");
|
||||
loop {
|
||||
@@ -205,4 +225,4 @@ impl DaemonCli {
|
||||
KordophoneRepository::delete_all_conversations(&self.proxy())
|
||||
.map_err(|e| anyhow::anyhow!("Failed to delete all conversations: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,37 @@ use clap::Subcommand;
|
||||
use kordophone::APIInterface;
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
client,
|
||||
printers::{ConversationPrinter, MessagePrinter},
|
||||
};
|
||||
use kordophone_db::database::{Database, DatabaseAccess};
|
||||
use crate::{client, printers::{ConversationPrinter, MessagePrinter}};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// For dealing with the table of cached conversations.
|
||||
Conversations {
|
||||
#[clap(subcommand)]
|
||||
command: ConversationCommands
|
||||
command: ConversationCommands,
|
||||
},
|
||||
|
||||
/// For dealing with the table of cached messages.
|
||||
Messages {
|
||||
#[clap(subcommand)]
|
||||
command: MessageCommands
|
||||
command: MessageCommands,
|
||||
},
|
||||
|
||||
/// For managing settings in the database.
|
||||
Settings {
|
||||
#[clap(subcommand)]
|
||||
command: SettingsCommands
|
||||
command: SettingsCommands,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum ConversationCommands {
|
||||
/// Lists all conversations currently in the database.
|
||||
List,
|
||||
List,
|
||||
|
||||
/// Syncs with an API client.
|
||||
Sync,
|
||||
@@ -39,9 +42,7 @@ pub enum ConversationCommands {
|
||||
#[derive(Subcommand)]
|
||||
pub enum MessageCommands {
|
||||
/// Prints all messages in a conversation.
|
||||
List {
|
||||
conversation_id: String
|
||||
},
|
||||
List { conversation_id: String },
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@@ -49,7 +50,7 @@ pub enum SettingsCommands {
|
||||
/// Lists all settings or gets a specific setting.
|
||||
Get {
|
||||
/// The key to get. If not provided, all settings will be listed.
|
||||
key: Option<String>
|
||||
key: Option<String>,
|
||||
},
|
||||
|
||||
/// Sets a setting value.
|
||||
@@ -76,7 +77,9 @@ impl Commands {
|
||||
ConversationCommands::Sync => db.sync_with_client().await,
|
||||
},
|
||||
Commands::Messages { command: cmd } => match cmd {
|
||||
MessageCommands::List { conversation_id } => db.print_messages(&conversation_id).await,
|
||||
MessageCommands::List { conversation_id } => {
|
||||
db.print_messages(&conversation_id).await
|
||||
}
|
||||
},
|
||||
Commands::Settings { command: cmd } => match cmd {
|
||||
SettingsCommands::Get { key } => db.get_setting(key).await,
|
||||
@@ -88,15 +91,17 @@ impl Commands {
|
||||
}
|
||||
|
||||
struct DbClient {
|
||||
database: Database
|
||||
database: Database,
|
||||
}
|
||||
|
||||
impl DbClient {
|
||||
fn database_path() -> PathBuf {
|
||||
env::var("KORDOPHONE_DB_PATH").unwrap_or_else(|_| {
|
||||
let temp_dir = env::temp_dir();
|
||||
temp_dir.join("kpcli_chat.db").to_str().unwrap().to_string()
|
||||
}).into()
|
||||
env::var("KORDOPHONE_DB_PATH")
|
||||
.unwrap_or_else(|_| {
|
||||
let temp_dir = env::temp_dir();
|
||||
temp_dir.join("kpcli_chat.db").to_str().unwrap().to_string()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self> {
|
||||
@@ -106,13 +111,14 @@ impl DbClient {
|
||||
println!("kpcli: Using db at {}", path_str);
|
||||
|
||||
let db = Database::new(path_str)?;
|
||||
Ok( Self { database: db })
|
||||
Ok(Self { database: db })
|
||||
}
|
||||
|
||||
pub async fn print_conversations(&mut self) -> Result<()> {
|
||||
let all_conversations = self.database.with_repository(|repository| {
|
||||
repository.all_conversations(i32::MAX, 0)
|
||||
}).await?;
|
||||
let all_conversations = self
|
||||
.database
|
||||
.with_repository(|repository| repository.all_conversations(i32::MAX, 0))
|
||||
.await?;
|
||||
|
||||
println!("{} Conversations: ", all_conversations.len());
|
||||
for conversation in all_conversations {
|
||||
@@ -123,9 +129,10 @@ impl DbClient {
|
||||
}
|
||||
|
||||
pub async fn print_messages(&mut self, conversation_id: &str) -> Result<()> {
|
||||
let messages = self.database.with_repository(|repository| {
|
||||
repository.get_messages_for_conversation(conversation_id)
|
||||
}).await?;
|
||||
let messages = self
|
||||
.database
|
||||
.with_repository(|repository| repository.get_messages_for_conversation(conversation_id))
|
||||
.await?;
|
||||
|
||||
for message in messages {
|
||||
println!("{}", MessagePrinter::new(&message.into()));
|
||||
@@ -136,85 +143,97 @@ impl DbClient {
|
||||
pub async fn sync_with_client(&mut self) -> Result<()> {
|
||||
let mut client = client::make_api_client_from_env();
|
||||
let fetched_conversations = client.get_conversations().await?;
|
||||
let db_conversations: Vec<kordophone_db::models::Conversation> = fetched_conversations.into_iter()
|
||||
let db_conversations: Vec<kordophone_db::models::Conversation> = fetched_conversations
|
||||
.into_iter()
|
||||
.map(kordophone_db::models::Conversation::from)
|
||||
.collect();
|
||||
|
||||
// Process each conversation
|
||||
for conversation in db_conversations {
|
||||
let conversation_id = conversation.guid.clone();
|
||||
|
||||
|
||||
// Insert the conversation
|
||||
self.database.with_repository(|repository| {
|
||||
repository.insert_conversation(conversation)
|
||||
}).await?;
|
||||
self.database
|
||||
.with_repository(|repository| repository.insert_conversation(conversation))
|
||||
.await?;
|
||||
|
||||
// Fetch and sync messages for this conversation
|
||||
let messages = client.get_messages(&conversation_id, None, None, None).await?;
|
||||
let db_messages: Vec<kordophone_db::models::Message> = messages.into_iter()
|
||||
let messages = client
|
||||
.get_messages(&conversation_id, None, None, None)
|
||||
.await?;
|
||||
let db_messages: Vec<kordophone_db::models::Message> = messages
|
||||
.into_iter()
|
||||
.map(kordophone_db::models::Message::from)
|
||||
.collect();
|
||||
|
||||
// Insert each message
|
||||
self.database.with_repository(|repository| -> Result<()> {
|
||||
for message in db_messages {
|
||||
repository.insert_message(&conversation_id, message)?;
|
||||
}
|
||||
self.database
|
||||
.with_repository(|repository| -> Result<()> {
|
||||
for message in db_messages {
|
||||
repository.insert_message(&conversation_id, message)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}).await?;
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_setting(&mut self, key: Option<String>) -> Result<()> {
|
||||
self.database.with_settings(|settings| {
|
||||
match key {
|
||||
Some(key) => {
|
||||
// Get a specific setting
|
||||
let value: Option<String> = settings.get(&key)?;
|
||||
match value {
|
||||
Some(v) => println!("{} = {}", key, v),
|
||||
None => println!("Setting '{}' not found", key),
|
||||
self.database
|
||||
.with_settings(|settings| {
|
||||
match key {
|
||||
Some(key) => {
|
||||
// Get a specific setting
|
||||
let value: Option<String> = settings.get(&key)?;
|
||||
match value {
|
||||
Some(v) => println!("{} = {}", key, v),
|
||||
None => println!("Setting '{}' not found", key),
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// List all settings
|
||||
let keys = settings.list_keys()?;
|
||||
if keys.is_empty() {
|
||||
println!("No settings found");
|
||||
} else {
|
||||
println!("Settings:");
|
||||
for key in keys {
|
||||
let value: Option<String> = settings.get(&key)?;
|
||||
match value {
|
||||
Some(v) => println!(" {} = {}", key, v),
|
||||
None => println!(" {} = <error reading value>", key),
|
||||
None => {
|
||||
// List all settings
|
||||
let keys = settings.list_keys()?;
|
||||
if keys.is_empty() {
|
||||
println!("No settings found");
|
||||
} else {
|
||||
println!("Settings:");
|
||||
for key in keys {
|
||||
let value: Option<String> = settings.get(&key)?;
|
||||
match value {
|
||||
Some(v) => println!(" {} = {}", key, v),
|
||||
None => println!(" {} = <error reading value>", key),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}).await
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn put_setting(&mut self, key: String, value: String) -> Result<()> {
|
||||
self.database.with_settings(|settings| {
|
||||
settings.put(&key, &value)?;
|
||||
Ok(())
|
||||
}).await
|
||||
self.database
|
||||
.with_settings(|settings| {
|
||||
settings.put(&key, &value)?;
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_setting(&mut self, key: String) -> Result<()> {
|
||||
self.database.with_settings(|settings| {
|
||||
let count = settings.del(&key)?;
|
||||
if count == 0 {
|
||||
println!("Setting '{}' not found", key);
|
||||
}
|
||||
Ok(())
|
||||
}).await
|
||||
self.database
|
||||
.with_settings(|settings| {
|
||||
let count = settings.del(&key)?;
|
||||
if count == 0 {
|
||||
println!("Setting '{}' not found", key);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
mod client;
|
||||
mod daemon;
|
||||
mod db;
|
||||
mod printers;
|
||||
mod daemon;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
@@ -33,7 +33,7 @@ enum Commands {
|
||||
Daemon {
|
||||
#[command(subcommand)]
|
||||
command: daemon::Commands,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
async fn run_command(command: Commands) -> Result<()> {
|
||||
@@ -50,7 +50,7 @@ fn initialize_logging() {
|
||||
.map(|s| s.parse::<LevelFilter>().unwrap_or(LevelFilter::Info))
|
||||
.unwrap_or(LevelFilter::Info);
|
||||
|
||||
env_logger::Builder::from_default_env()
|
||||
env_logger::Builder::from_default_env()
|
||||
.format_timestamp_secs()
|
||||
.filter_level(log_level)
|
||||
.init();
|
||||
@@ -62,7 +62,8 @@ async fn main() {
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
run_command(cli.command).await
|
||||
run_command(cli.command)
|
||||
.await
|
||||
.map_err(|e| println!("Error: {}", e))
|
||||
.err();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::fmt::Display;
|
||||
use std::collections::HashMap;
|
||||
use time::OffsetDateTime;
|
||||
use pretty::RcDoc;
|
||||
use dbus::arg::{self, RefArg};
|
||||
use kordophone::model::message::AttachmentMetadata;
|
||||
use pretty::RcDoc;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub struct PrintableConversation {
|
||||
pub guid: String,
|
||||
@@ -17,7 +17,7 @@ pub struct PrintableConversation {
|
||||
impl From<kordophone::model::Conversation> for PrintableConversation {
|
||||
fn from(value: kordophone::model::Conversation) -> Self {
|
||||
Self {
|
||||
guid: value.guid,
|
||||
guid: value.guid,
|
||||
date: value.date,
|
||||
unread_count: value.unread_count,
|
||||
last_message_preview: value.last_message_preview,
|
||||
@@ -34,7 +34,11 @@ impl From<kordophone_db::models::Conversation> for PrintableConversation {
|
||||
date: OffsetDateTime::from_unix_timestamp(value.date.and_utc().timestamp()).unwrap(),
|
||||
unread_count: value.unread_count.into(),
|
||||
last_message_preview: value.last_message_preview,
|
||||
participants: value.participants.into_iter().map(|p| p.display_name()).collect(),
|
||||
participants: value
|
||||
.participants
|
||||
.into_iter()
|
||||
.map(|p| p.display_name())
|
||||
.collect(),
|
||||
display_name: value.display_name,
|
||||
}
|
||||
}
|
||||
@@ -44,17 +48,33 @@ impl From<arg::PropMap> for PrintableConversation {
|
||||
fn from(value: arg::PropMap) -> Self {
|
||||
Self {
|
||||
guid: value.get("guid").unwrap().as_str().unwrap().to_string(),
|
||||
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap()).unwrap(),
|
||||
unread_count: value.get("unread_count").unwrap().as_i64().unwrap().try_into().unwrap(),
|
||||
last_message_preview: value.get("last_message_preview").unwrap().as_str().map(|s| s.to_string()),
|
||||
participants: value.get("participants")
|
||||
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap())
|
||||
.unwrap(),
|
||||
unread_count: value
|
||||
.get("unread_count")
|
||||
.unwrap()
|
||||
.as_i64()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
last_message_preview: value
|
||||
.get("last_message_preview")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.map(|s| s.to_string()),
|
||||
participants: value
|
||||
.get("participants")
|
||||
.unwrap()
|
||||
.0
|
||||
.as_iter()
|
||||
.unwrap()
|
||||
.map(|s| s.as_str().unwrap().to_string())
|
||||
.collect(),
|
||||
display_name: value.get("display_name").unwrap().as_str().map(|s| s.to_string()),
|
||||
display_name: value
|
||||
.get("display_name")
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.map(|s| s.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,19 +117,22 @@ impl From<kordophone_db::models::Message> for PrintableMessage {
|
||||
impl From<arg::PropMap> for PrintableMessage {
|
||||
fn from(value: arg::PropMap) -> Self {
|
||||
// Parse file transfer GUIDs from JSON if present
|
||||
let file_transfer_guids = value.get("file_transfer_guids")
|
||||
let file_transfer_guids = value
|
||||
.get("file_transfer_guids")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|json_str| serde_json::from_str(json_str).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Parse attachment metadata from JSON if present
|
||||
let attachment_metadata = value.get("attachment_metadata")
|
||||
let attachment_metadata = value
|
||||
.get("attachment_metadata")
|
||||
.and_then(|v| v.as_str())
|
||||
.and_then(|json_str| serde_json::from_str(json_str).ok());
|
||||
|
||||
Self {
|
||||
guid: value.get("id").unwrap().as_str().unwrap().to_string(),
|
||||
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap()).unwrap(),
|
||||
date: OffsetDateTime::from_unix_timestamp(value.get("date").unwrap().as_i64().unwrap())
|
||||
.unwrap(),
|
||||
sender: value.get("sender").unwrap().as_str().unwrap().to_string(),
|
||||
text: value.get("text").unwrap().as_str().unwrap().to_string(),
|
||||
file_transfer_guids,
|
||||
@@ -119,12 +142,13 @@ impl From<arg::PropMap> for PrintableMessage {
|
||||
}
|
||||
|
||||
pub struct ConversationPrinter<'a> {
|
||||
doc: RcDoc<'a, PrintableConversation>
|
||||
doc: RcDoc<'a, PrintableConversation>,
|
||||
}
|
||||
|
||||
impl<'a> ConversationPrinter<'a> {
|
||||
pub fn new(conversation: &'a PrintableConversation) -> Self {
|
||||
let preview = conversation.last_message_preview
|
||||
let preview = conversation
|
||||
.last_message_preview
|
||||
.as_deref()
|
||||
.unwrap_or("<null>")
|
||||
.replace('\n', " ");
|
||||
@@ -134,33 +158,31 @@ impl<'a> ConversationPrinter<'a> {
|
||||
RcDoc::line()
|
||||
.append("Display Name: ")
|
||||
.append(conversation.display_name.as_deref().unwrap_or("<null>"))
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::line())
|
||||
.append("Date: ")
|
||||
.append(conversation.date.to_string())
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::line())
|
||||
.append("Unread Count: ")
|
||||
.append(conversation.unread_count.to_string())
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::line())
|
||||
.append("Participants: ")
|
||||
.append("[")
|
||||
.append(RcDoc::line()
|
||||
.append(
|
||||
conversation.participants
|
||||
.iter()
|
||||
.map(|name|
|
||||
RcDoc::text(name)
|
||||
.append(",")
|
||||
.append(RcDoc::line())
|
||||
)
|
||||
.fold(RcDoc::nil(), |acc, x| acc.append(x))
|
||||
)
|
||||
.nest(4)
|
||||
.append(
|
||||
RcDoc::line()
|
||||
.append(
|
||||
conversation
|
||||
.participants
|
||||
.iter()
|
||||
.map(|name| RcDoc::text(name).append(",").append(RcDoc::line()))
|
||||
.fold(RcDoc::nil(), |acc, x| acc.append(x)),
|
||||
)
|
||||
.nest(4),
|
||||
)
|
||||
.append("]")
|
||||
.append(RcDoc::line())
|
||||
.append(RcDoc::line())
|
||||
.append("Last Message Preview: ")
|
||||
.append(preview)
|
||||
.nest(4)
|
||||
.nest(4),
|
||||
)
|
||||
.append(RcDoc::line())
|
||||
.append(">");
|
||||
@@ -176,7 +198,7 @@ impl Display for ConversationPrinter<'_> {
|
||||
}
|
||||
|
||||
pub struct MessagePrinter<'a> {
|
||||
doc: RcDoc<'a, PrintableMessage>
|
||||
doc: RcDoc<'a, PrintableMessage>,
|
||||
}
|
||||
|
||||
impl Display for MessagePrinter<'_> {
|
||||
@@ -187,37 +209,40 @@ impl Display for MessagePrinter<'_> {
|
||||
|
||||
impl<'a> MessagePrinter<'a> {
|
||||
pub fn new(message: &'a PrintableMessage) -> Self {
|
||||
let mut doc = RcDoc::text(format!("<Message: \"{}\"", &message.guid))
|
||||
.append(
|
||||
RcDoc::line()
|
||||
.append("Date: ")
|
||||
.append(message.date.to_string())
|
||||
let mut doc = RcDoc::text(format!("<Message: \"{}\"", &message.guid)).append(
|
||||
RcDoc::line()
|
||||
.append("Date: ")
|
||||
.append(message.date.to_string())
|
||||
.append(RcDoc::line())
|
||||
.append("Sender: ")
|
||||
.append(&message.sender)
|
||||
.append("Sender: ")
|
||||
.append(&message.sender)
|
||||
.append(RcDoc::line())
|
||||
.append("Body: ")
|
||||
.append(&message.text)
|
||||
.nest(4)
|
||||
);
|
||||
.append("Body: ")
|
||||
.append(&message.text)
|
||||
.nest(4),
|
||||
);
|
||||
|
||||
// Add file transfer GUIDs and attachment metadata if present
|
||||
if !message.file_transfer_guids.is_empty() {
|
||||
doc = doc.append(RcDoc::line())
|
||||
.append(
|
||||
RcDoc::line()
|
||||
.append("Attachments:")
|
||||
.append(
|
||||
message.file_transfer_guids.iter().map(|guid| {
|
||||
let mut attachment_doc = RcDoc::line()
|
||||
.append("- ")
|
||||
.append(guid);
|
||||
doc = doc.append(RcDoc::line()).append(
|
||||
RcDoc::line()
|
||||
.append("Attachments:")
|
||||
.append(
|
||||
message
|
||||
.file_transfer_guids
|
||||
.iter()
|
||||
.map(|guid| {
|
||||
let mut attachment_doc = RcDoc::line().append("- ").append(guid);
|
||||
|
||||
// Add metadata if available for this GUID
|
||||
if let Some(ref metadata) = message.attachment_metadata {
|
||||
if let Some(attachment_meta) = metadata.get(guid) {
|
||||
if let Some(ref attribution) = attachment_meta.attribution_info {
|
||||
if let (Some(width), Some(height)) = (attribution.width, attribution.height) {
|
||||
if let Some(ref attribution) =
|
||||
attachment_meta.attribution_info
|
||||
{
|
||||
if let (Some(width), Some(height)) =
|
||||
(attribution.width, attribution.height)
|
||||
{
|
||||
attachment_doc = attachment_doc
|
||||
.append(RcDoc::line())
|
||||
.append(" Dimensions: ")
|
||||
@@ -231,14 +256,14 @@ impl<'a> MessagePrinter<'a> {
|
||||
|
||||
attachment_doc
|
||||
})
|
||||
.fold(RcDoc::nil(), |acc, x| acc.append(x))
|
||||
)
|
||||
.nest(4)
|
||||
);
|
||||
.fold(RcDoc::nil(), |acc, x| acc.append(x)),
|
||||
)
|
||||
.nest(4),
|
||||
);
|
||||
}
|
||||
|
||||
doc = doc.append(RcDoc::line()).append(">");
|
||||
|
||||
MessagePrinter { doc }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user