implements settings, conversation dbus encoding
This commit is contained in:
@@ -13,7 +13,10 @@
|
||||
'id' (string): Unique identifier
|
||||
'title' (string): Display name
|
||||
'last_message' (string): Preview text
|
||||
'is_unread' (boolean): Unread status"/>
|
||||
'is_unread' (boolean): Unread status
|
||||
'date' (int64): Date of last message
|
||||
'participants' (array of strings): List of participants
|
||||
'unread_count' (int32): Number of unread messages"/>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use tokio::sync::oneshot;
|
||||
use kordophone_db::models::Conversation;
|
||||
use crate::daemon::settings::Settings;
|
||||
|
||||
pub type Reply<T> = oneshot::Sender<T>;
|
||||
|
||||
@@ -13,6 +14,12 @@ pub enum Event {
|
||||
|
||||
/// Returns all known conversations from the database.
|
||||
GetAllConversations(Reply<Vec<Conversation>>),
|
||||
|
||||
/// Returns all known settings from the database.
|
||||
GetAllSettings(Reply<Settings>),
|
||||
|
||||
/// Update settings in the database.
|
||||
UpdateSettings(Settings, Reply<()>),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,6 +50,10 @@ impl TokenStore for DatabaseTokenStore {
|
||||
}
|
||||
}
|
||||
|
||||
mod target {
|
||||
pub static SYNC: &str = "sync";
|
||||
}
|
||||
|
||||
pub struct Daemon {
|
||||
pub event_sender: Sender<Event>,
|
||||
event_receiver: Receiver<Event>,
|
||||
@@ -110,6 +114,25 @@ impl Daemon {
|
||||
let conversations = self.get_conversations().await;
|
||||
reply.send(conversations).unwrap();
|
||||
},
|
||||
|
||||
Event::GetAllSettings(reply) => {
|
||||
let settings = self.get_settings().await
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to get settings: {:#?}", e);
|
||||
Settings::default()
|
||||
});
|
||||
|
||||
reply.send(settings).unwrap();
|
||||
},
|
||||
|
||||
Event::UpdateSettings(settings, reply) => {
|
||||
self.update_settings(settings).await
|
||||
.unwrap_or_else(|e| {
|
||||
log::error!("Failed to update settings: {}", e);
|
||||
});
|
||||
|
||||
reply.send(()).unwrap();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,32 +141,9 @@ impl Daemon {
|
||||
}
|
||||
|
||||
async fn sync_all_conversations_impl(mut database: Arc<Mutex<Database>>) -> Result<()> {
|
||||
log::info!("Starting conversation sync");
|
||||
|
||||
// Get client from the database
|
||||
let settings = database.with_settings(|s| Settings::from_db(s))
|
||||
.await?;
|
||||
log::info!(target: target::SYNC, "Starting conversation sync");
|
||||
|
||||
let server_url = settings.server_url
|
||||
.ok_or(DaemonError::ClientNotConfigured)?;
|
||||
|
||||
let mut client = HTTPAPIClient::new(
|
||||
server_url.parse().unwrap(),
|
||||
match (settings.username, settings.credential_item) {
|
||||
(Some(username), Some(password)) => Some(
|
||||
Credentials {
|
||||
username,
|
||||
password,
|
||||
}
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
DatabaseTokenStore { database: database.clone() }
|
||||
);
|
||||
|
||||
// This function needed to implement TokenManagement
|
||||
// let token = database.lock().await.get_token();
|
||||
// TODO: Clent.token = token
|
||||
let mut client = Self::get_client_impl(database.clone()).await?;
|
||||
|
||||
// Fetch conversations from server
|
||||
let fetched_conversations = client.get_conversations().await?;
|
||||
@@ -152,6 +152,7 @@ impl Daemon {
|
||||
.collect();
|
||||
|
||||
// Process each conversation
|
||||
let num_conversations = db_conversations.len();
|
||||
for conversation in db_conversations {
|
||||
let conversation_id = conversation.guid.clone();
|
||||
|
||||
@@ -159,21 +160,18 @@ impl Daemon {
|
||||
database.with_repository(|r| r.insert_conversation(conversation)).await?;
|
||||
|
||||
// Fetch and sync messages for this conversation
|
||||
log::info!(target: target::SYNC, "Fetching messages for conversation {}", conversation_id);
|
||||
let messages = client.get_messages(&conversation_id).await?;
|
||||
let db_messages: Vec<kordophone_db::models::Message> = messages.into_iter()
|
||||
.map(|m| kordophone_db::models::Message::from(m))
|
||||
.collect();
|
||||
|
||||
// Insert each message
|
||||
database.with_repository(|r| -> Result<()> {
|
||||
for message in db_messages {
|
||||
r.insert_message(&conversation_id, message)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}).await?;
|
||||
log::info!(target: target::SYNC, "Inserting {} messages for conversation {}", db_messages.len(), conversation_id);
|
||||
database.with_repository(|r| r.insert_messages(&conversation_id, db_messages)).await?;
|
||||
}
|
||||
|
||||
|
||||
log::info!(target: target::SYNC, "Synchronized {} conversations", num_conversations);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -185,8 +183,16 @@ impl Daemon {
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
async fn update_settings(&mut self, settings: Settings) -> Result<()> {
|
||||
self.database.with_settings(|s| settings.save(s)).await
|
||||
}
|
||||
|
||||
async fn get_client(&mut self) -> Result<HTTPAPIClient<DatabaseTokenStore>> {
|
||||
let settings = self.database.with_settings(|s|
|
||||
Self::get_client_impl(self.database.clone()).await
|
||||
}
|
||||
|
||||
async fn get_client_impl(mut database: Arc<Mutex<Database>>) -> Result<HTTPAPIClient<DatabaseTokenStore>> {
|
||||
let settings = database.with_settings(|s|
|
||||
Settings::from_db(s)
|
||||
).await?;
|
||||
|
||||
@@ -205,7 +211,7 @@ impl Daemon {
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
DatabaseTokenStore { database: self.database.clone() }
|
||||
DatabaseTokenStore { database: database.clone() }
|
||||
);
|
||||
|
||||
Ok(client)
|
||||
|
||||
@@ -16,9 +16,9 @@ pub struct Settings {
|
||||
|
||||
impl Settings {
|
||||
pub fn from_db(db_settings: &mut DbSettings) -> Result<Self> {
|
||||
let server_url = db_settings.get(keys::SERVER_URL)?;
|
||||
let username = db_settings.get(keys::USERNAME)?;
|
||||
let credential_item = db_settings.get(keys::CREDENTIAL_ITEM)?;
|
||||
let server_url: Option<String> = db_settings.get(keys::SERVER_URL)?;
|
||||
let username: Option<String> = db_settings.get(keys::USERNAME)?;
|
||||
let credential_item: Option<String> = db_settings.get(keys::CREDENTIAL_ITEM)?;
|
||||
|
||||
Ok(Self {
|
||||
server_url,
|
||||
@@ -28,9 +28,25 @@ impl Settings {
|
||||
}
|
||||
|
||||
pub fn save(&self, db_settings: &mut DbSettings) -> Result<()> {
|
||||
db_settings.put(keys::SERVER_URL, &self.server_url)?;
|
||||
db_settings.put(keys::USERNAME, &self.username)?;
|
||||
db_settings.put(keys::CREDENTIAL_ITEM, &self.credential_item)?;
|
||||
if let Some(server_url) = &self.server_url {
|
||||
db_settings.put(keys::SERVER_URL, &server_url)?;
|
||||
}
|
||||
if let Some(username) = &self.username {
|
||||
db_settings.put(keys::USERNAME, &username)?;
|
||||
}
|
||||
if let Some(credential_item) = &self.credential_item {
|
||||
db_settings.put(keys::CREDENTIAL_ITEM, &credential_item)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
server_url: None,
|
||||
username: None,
|
||||
credential_item: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
use dbus::arg;
|
||||
use dbus_tree::MethodErr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex, MutexGuard};
|
||||
use tokio::sync::mpsc;
|
||||
use std::future::Future;
|
||||
use std::thread;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::sync::mpsc;
|
||||
use futures_util::future::FutureExt;
|
||||
|
||||
use crate::daemon::{
|
||||
Daemon,
|
||||
DaemonResult,
|
||||
events::{Event, Reply},
|
||||
settings::Settings,
|
||||
};
|
||||
|
||||
use crate::dbus::interface::NetBuzzertKordophoneRepository as DbusRepository;
|
||||
@@ -63,7 +60,10 @@ impl DbusRepository for ServerImpl {
|
||||
map.insert("guid".into(), arg::Variant(Box::new(conv.guid)));
|
||||
map.insert("display_name".into(), arg::Variant(Box::new(conv.display_name.unwrap_or_default())));
|
||||
map.insert("unread_count".into(), arg::Variant(Box::new(conv.unread_count as i32)));
|
||||
map
|
||||
map.insert("last_message_preview".into(), arg::Variant(Box::new(conv.last_message_preview.unwrap_or_default())));
|
||||
map.insert("participants".into(), arg::Variant(Box::new(conv.participants.into_iter().map(|p| p.display_name()).collect::<Vec<String>>())));
|
||||
map.insert("date".into(), arg::Variant(Box::new(conv.date.and_utc().timestamp())));
|
||||
map
|
||||
}).collect();
|
||||
|
||||
Ok(result)
|
||||
@@ -77,35 +77,77 @@ impl DbusRepository for ServerImpl {
|
||||
|
||||
impl DbusSettings for ServerImpl {
|
||||
fn set_server(&mut self, url: String, user: String) -> Result<(), dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(|r|
|
||||
Event::UpdateSettings(Settings {
|
||||
server_url: Some(url),
|
||||
username: Some(user),
|
||||
credential_item: None,
|
||||
}, r)
|
||||
)
|
||||
}
|
||||
|
||||
fn set_credential_item_(&mut self, item_path: dbus::Path<'static>) -> Result<(), dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(|r|
|
||||
Event::UpdateSettings(Settings {
|
||||
server_url: None,
|
||||
username: None,
|
||||
credential_item: Some(item_path.to_string()),
|
||||
}, r)
|
||||
)
|
||||
}
|
||||
|
||||
fn server_url(&self) -> Result<String, dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(Event::GetAllSettings)
|
||||
.and_then(|settings| {
|
||||
Ok(settings.server_url.unwrap_or_default())
|
||||
})
|
||||
}
|
||||
|
||||
fn set_server_url(&self, value: String) -> Result<(), dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(|r|
|
||||
Event::UpdateSettings(Settings {
|
||||
server_url: Some(value),
|
||||
username: None,
|
||||
credential_item: None,
|
||||
}, r)
|
||||
)
|
||||
}
|
||||
|
||||
fn username(&self) -> Result<String, dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(Event::GetAllSettings)
|
||||
.and_then(|settings| {
|
||||
Ok(settings.username.unwrap_or_default())
|
||||
})
|
||||
}
|
||||
|
||||
fn set_username(&self, value: String) -> Result<(), dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(|r|
|
||||
Event::UpdateSettings(Settings {
|
||||
server_url: None,
|
||||
username: Some(value),
|
||||
credential_item: None,
|
||||
}, r)
|
||||
)
|
||||
}
|
||||
|
||||
fn credential_item(&self) -> Result<dbus::Path<'static>, dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(Event::GetAllSettings)
|
||||
.and_then(|settings| {
|
||||
Ok(settings.credential_item.unwrap_or_default())
|
||||
})
|
||||
.and_then(|item| {
|
||||
Ok(dbus::Path::new(item).unwrap_or_default())
|
||||
})
|
||||
}
|
||||
|
||||
fn set_credential_item(&self, value: dbus::Path<'static>) -> Result<(), dbus::MethodErr> {
|
||||
todo!()
|
||||
self.send_event_sync(|r|
|
||||
Event::UpdateSettings(Settings {
|
||||
server_url: None,
|
||||
username: None,
|
||||
credential_item: Some(value.to_string()),
|
||||
}, r)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user