Private
Public Access
1
0

new message: initial commit

This commit is contained in:
2026-04-01 15:29:37 -07:00
parent 45285892de
commit c2a697f2c1
23 changed files with 674 additions and 262 deletions

View File

@@ -477,9 +477,8 @@ impl Daemon {
.await;
// Convert DB messages to daemon model, substituting local_id when an alias exists.
let mut result: Vec<Message> = Vec::with_capacity(
db_messages.len() + outgoing_messages.len(),
);
let mut result: Vec<Message> =
Vec::with_capacity(db_messages.len() + outgoing_messages.len());
for m in db_messages.into_iter() {
let server_id = m.id.clone();
let mut dm: Message = m.into();

View File

@@ -8,6 +8,7 @@ use tokio_condvar::Condvar;
use crate::daemon::events::Event as DaemonEvent;
use kordophone::api::APIInterface;
use kordophone::model::outgoing_message::OutgoingMessage;
use kordophone::model::OutgoingMessageTarget;
use anyhow::Result;
@@ -102,10 +103,29 @@ impl<C: APIInterface, F: AsyncFnMut() -> Result<C>> PostOffice<C, F> {
Ok(sent_message) => {
log::info!(target: target::POST_OFFICE, "Message sent successfully: {}", message.guid);
let conversation_id = message.conversation_id.clone();
let event =
DaemonEvent::MessageSent(sent_message.into(), message, conversation_id);
event_sink.send(event).await.unwrap();
let conversation_id = sent_message.conversation_id.clone().or_else(|| {
match &message.target {
OutgoingMessageTarget::Conversation(conversation_id) => {
Some(conversation_id.clone())
}
OutgoingMessageTarget::Handles(_) => None,
}
});
if let Some(conversation_id) = conversation_id {
let event = DaemonEvent::MessageSent(
sent_message.message.into(),
message,
conversation_id,
);
event_sink.send(event).await.unwrap();
} else {
log::error!(
target: target::POST_OFFICE,
"Message sent but no conversation id was available for {}",
message.guid
);
}
}
Err(e) => {

View File

@@ -318,49 +318,49 @@ impl DbusRepository for DBusAgent {
.attachments
.into_iter()
.map(|attachment| {
attachment_count += 1;
let mut attachment_map = arg::PropMap::new();
attachment_map.insert(
"guid".into(),
arg::Variant(Box::new(attachment.guid.clone())),
);
attachment_map.insert(
"downloaded".into(),
arg::Variant(Box::new(attachment.is_downloaded(false))),
);
attachment_map.insert(
"preview_downloaded".into(),
arg::Variant(Box::new(attachment.is_downloaded(true))),
);
attachment_count += 1;
let mut attachment_map = arg::PropMap::new();
attachment_map.insert(
"guid".into(),
arg::Variant(Box::new(attachment.guid.clone())),
);
attachment_map.insert(
"downloaded".into(),
arg::Variant(Box::new(attachment.is_downloaded(false))),
);
attachment_map.insert(
"preview_downloaded".into(),
arg::Variant(Box::new(attachment.is_downloaded(true))),
);
if let Some(ref metadata) = attachment.metadata {
let mut metadata_map = arg::PropMap::new();
if let Some(ref metadata) = attachment.metadata {
let mut metadata_map = arg::PropMap::new();
if let Some(ref attribution_info) = metadata.attribution_info {
let mut attribution_map = arg::PropMap::new();
if let Some(width) = attribution_info.width {
attribution_map.insert(
"width".into(),
arg::Variant(Box::new(width as i32)),
if let Some(ref attribution_info) = metadata.attribution_info {
let mut attribution_map = arg::PropMap::new();
if let Some(width) = attribution_info.width {
attribution_map.insert(
"width".into(),
arg::Variant(Box::new(width as i32)),
);
}
if let Some(height) = attribution_info.height {
attribution_map.insert(
"height".into(),
arg::Variant(Box::new(height as i32)),
);
}
metadata_map.insert(
"attribution_info".into(),
arg::Variant(Box::new(attribution_map)),
);
}
if let Some(height) = attribution_info.height {
attribution_map.insert(
"height".into(),
arg::Variant(Box::new(height as i32)),
);
}
metadata_map.insert(
"attribution_info".into(),
arg::Variant(Box::new(attribution_map)),
attachment_map.insert(
"metadata".into(),
arg::Variant(Box::new(metadata_map)),
);
}
attachment_map.insert(
"metadata".into(),
arg::Variant(Box::new(metadata_map)),
);
}
attachment_map
})
.collect();

View File

@@ -15,10 +15,16 @@ pub struct DispatchResult {
impl DispatchResult {
pub fn new(message: Message) -> Self {
Self { message, cleanup: None }
Self {
message,
cleanup: None,
}
}
pub fn with_cleanup<T: Any + Send + 'static>(message: Message, cleanup: T) -> Self {
Self { message, cleanup: Some(Box::new(cleanup)) }
Self {
message,
cleanup: Some(Box::new(cleanup)),
}
}
}

View File

@@ -105,7 +105,12 @@ pub async fn dispatch(
.and_then(|m| dict_get_str(m, "conversation_id"))
{
Some(id) => id,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing conversation_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing conversation_id",
))
}
};
match agent
.send_event(|r| Event::SyncConversation(conversation_id, r))
@@ -122,7 +127,12 @@ pub async fn dispatch(
.and_then(|m| dict_get_str(m, "conversation_id"))
{
Some(id) => id,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing conversation_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing conversation_id",
))
}
};
match agent
.send_event(|r| Event::MarkConversationAsRead(conversation_id, r))
@@ -137,11 +147,21 @@ pub async fn dispatch(
"GetMessages" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let conversation_id = match dict_get_str(args, "conversation_id") {
Some(id) => id,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing conversation_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing conversation_id",
))
}
};
let last_message_id = dict_get_str(args, "last_message_id");
match agent
@@ -158,13 +178,10 @@ pub async fn dispatch(
dict_put_str(&mut m, "sender", &msg.sender.display_name());
// Include attachment GUIDs for the client to resolve/download
let attachment_guids: Vec<String> = msg
.attachments
.iter()
.map(|a| a.guid.clone())
.collect();
let attachment_guids: Vec<String> =
msg.attachments.iter().map(|a| a.guid.clone()).collect();
m.insert(cstr("attachment_guids"), array_from_strs(attachment_guids));
// Full attachments array with metadata (mirrors DBus fields)
let mut attachments_items: Vec<Message> = Vec::new();
for attachment in msg.attachments.iter() {
@@ -193,12 +210,23 @@ pub async fn dispatch(
if let Some(attribution_info) = &metadata.attribution_info {
let mut attribution_map: XpcMap = HashMap::new();
if let Some(width) = attribution_info.width {
dict_put_i64_as_str(&mut attribution_map, "width", width as i64);
dict_put_i64_as_str(
&mut attribution_map,
"width",
width as i64,
);
}
if let Some(height) = attribution_info.height {
dict_put_i64_as_str(&mut attribution_map, "height", height as i64);
dict_put_i64_as_str(
&mut attribution_map,
"height",
height as i64,
);
}
metadata_map.insert(cstr("attribution_info"), Message::Dictionary(attribution_map));
metadata_map.insert(
cstr("attribution_info"),
Message::Dictionary(attribution_map),
);
}
if !metadata_map.is_empty() {
a.insert(cstr("metadata"), Message::Dictionary(metadata_map));
@@ -208,7 +236,7 @@ pub async fn dispatch(
attachments_items.push(Message::Dictionary(a));
}
m.insert(cstr("attachments"), Message::Array(attachments_items));
items.push(Message::Dictionary(m));
}
let mut reply: XpcMap = HashMap::new();
@@ -230,11 +258,21 @@ pub async fn dispatch(
"SendMessage" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let conversation_id = match dict_get_str(args, "conversation_id") {
Some(v) => v,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing conversation_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing conversation_id",
))
}
};
let text = dict_get_str(args, "text").unwrap_or_default();
let attachment_guids: Vec<String> = match args.get(&cstr("attachment_guids")) {
@@ -265,11 +303,21 @@ pub async fn dispatch(
"GetAttachmentInfo" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let attachment_id = match dict_get_str(args, "attachment_id") {
Some(v) => v,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing attachment_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing attachment_id",
))
}
};
match agent
.send_event(|r| Event::GetAttachment(attachment_id, r))
@@ -308,11 +356,21 @@ pub async fn dispatch(
"OpenAttachmentFd" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let attachment_id = match dict_get_str(args, "attachment_id") {
Some(v) => v,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing attachment_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing attachment_id",
))
}
};
let preview = dict_get_str(args, "preview")
.map(|s| s == "true")
@@ -324,7 +382,7 @@ pub async fn dispatch(
{
Ok(attachment) => {
use std::os::fd::AsRawFd;
let path = attachment.get_path_for_preview(preview);
match std::fs::OpenOptions::new().read(true).open(&path) {
Ok(file) => {
@@ -335,9 +393,14 @@ pub async fn dispatch(
dict_put_str(&mut reply, "type", "OpenAttachmentFdResponse");
reply.insert(cstr("fd"), Message::Fd(fd));
DispatchResult { message: Message::Dictionary(reply), cleanup: Some(Box::new(file)) }
DispatchResult {
message: Message::Dictionary(reply),
cleanup: Some(Box::new(file)),
}
}
Err(e) => {
DispatchResult::new(make_error_reply("OpenFailed", &format!("{}", e)))
}
Err(e) => DispatchResult::new(make_error_reply("OpenFailed", &format!("{}", e))),
}
}
Err(e) => DispatchResult::new(make_error_reply("DaemonError", &format!("{}", e))),
@@ -348,11 +411,21 @@ pub async fn dispatch(
"DownloadAttachment" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let attachment_id = match dict_get_str(args, "attachment_id") {
Some(v) => v,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing attachment_id")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing attachment_id",
))
}
};
let preview = dict_get_str(args, "preview")
.map(|s| s == "true")
@@ -371,11 +444,18 @@ pub async fn dispatch(
use std::path::PathBuf;
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let path = match dict_get_str(args, "path") {
Some(v) => v,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing path")),
None => {
return DispatchResult::new(make_error_reply("InvalidRequest", "Missing path"))
}
};
match agent
.send_event(|r| Event::UploadAttachment(PathBuf::from(path), r))
@@ -413,7 +493,12 @@ pub async fn dispatch(
"UpdateSettings" => {
let args = match get_dictionary_field(root, "arguments") {
Some(a) => a,
None => return DispatchResult::new(make_error_reply("InvalidRequest", "Missing arguments")),
None => {
return DispatchResult::new(make_error_reply(
"InvalidRequest",
"Missing arguments",
))
}
};
let server_url = dict_get_str(args, "server_url");
let username = dict_get_str(args, "username");