Skip to content

Add API to get next fresh message #3777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

### API-Changes
- Add Python API to send reactions #3762
- Add API to get next fresh message #3777

### Fixes
- Make sure malformed messsages will never block receiving further messages anymore #3771
Expand Down
12 changes: 12 additions & 0 deletions deltachat-ffi/deltachat.h
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,18 @@ int dc_estimate_deletion_cnt (dc_context_t* context, int from_ser
dc_array_t* dc_get_fresh_msgs (dc_context_t* context);


/**
* Returns the ID of the fresh message of any chat.
*
* If there is no such message, the function blocks until there is one.
*
* @memberof dc_context_t
* @param context The context object as returned from dc_context_new().
* @return Message ID of the next fresh message. Returns 0 on error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if there is no next fresh message?

*/
dc_array_t* dc_get_next_fresh_msg (dc_context_t* context);


/**
* Mark all messages in a chat as _noticed_.
* _Noticed_ messages are no longer _fresh_ and do not count as being unseen
Expand Down
14 changes: 14 additions & 0 deletions deltachat-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,20 @@ pub unsafe extern "C" fn dc_get_fresh_msgs(
})
}

#[no_mangle]
pub unsafe extern "C" fn dc_get_next_fresh_msg(context: *mut dc_context_t) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_next_fresh_msg()");
return 0;
}
let ctx = &*context;

block_on(ctx.get_next_fresh_msg())
.log_err(ctx, "Failed to get next fresh message")
.unwrap_or_default()
.to_u32()
}

#[no_mangle]
pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id: u32) {
if context.is_null() {
Expand Down
9 changes: 9 additions & 0 deletions deltachat-jsonrpc/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,15 @@ impl CommandApi {
.collect())
}

/// Returns the message ID of the oldest fresh message.
///
/// If there are no such messages, waits until there is one.
async fn get_next_fresh_msg(&self, account_id: u32) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
let msg_id = ctx.get_next_fresh_msg().await?;
Ok(msg_id.to_u32())
}

/// Get the number of _fresh_ messages in a chat.
/// Typically used to implement a badge with a number in the chatlist.
///
Expand Down
5 changes: 5 additions & 0 deletions python/src/deltachat/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ def get_fresh_messages(self) -> Generator[Message, None, None]:
dc_array = ffi.gc(lib.dc_get_fresh_msgs(self._dc_context), lib.dc_array_unref)
yield from iter_array(dc_array, lambda x: Message.from_db(self, x))

def get_next_fresh_message(self) -> Message:
"""Returns the oldest fresh message or waits for a new one to arrive."""
msg_id = lib.dc_get_next_fresh_msg(self._dc_context)
return Message.from_db(self, msg_id)

def create_chat(self, obj) -> Chat:
"""Create a 1:1 chat with Account, Contact or e-mail address."""
return self.create_contact(obj).create_chat()
Expand Down
1 change: 1 addition & 0 deletions python/tests/test_1_online.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ def test_send_and_receive_will_encrypt_decrypt(acfactory, lp):
fresh_msgs = list(ac1.get_fresh_messages())
assert len(fresh_msgs) == 1
assert fresh_msgs[0] == msg3
assert ac1.get_next_fresh_message() == msg3
msg3.mark_seen()
assert not list(ac1.get_fresh_messages())

Expand Down
26 changes: 24 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::time::{Duration, Instant, SystemTime};

use anyhow::{ensure, Result};
use async_channel::{self as channel, Receiver, Sender};
use tokio::sync::{Mutex, RwLock};
use tokio::sync::{Mutex, Notify, RwLock};

use crate::chat::{get_chat_cnt, ChatId};
use crate::config::Config;
Expand Down Expand Up @@ -205,6 +205,11 @@ pub struct InnerContext {
pub(crate) translated_stockstrings: StockStrings,
pub(crate) events: Events,

/// Notify about fresh messages.
///
/// This notification is used only internally for [`InternalContext.get_next_fresh_msg()`].
pub(crate) notify_fresh_message: Notify,

pub(crate) scheduler: RwLock<Option<Scheduler>>,
pub(crate) ratelimit: RwLock<Ratelimit>,

Expand Down Expand Up @@ -354,6 +359,7 @@ impl Context {
wrong_pw_warning_mutex: Mutex::new(()),
translated_stockstrings: stockstrings,
events,
notify_fresh_message: Notify::new(),
scheduler: RwLock::new(None),
ratelimit: RwLock::new(Ratelimit::new(Duration::new(60, 0), 6.0)), // Allow to send 6 messages immediately, no more than once every 10 seconds.
quota: RwLock::new(None),
Expand Down Expand Up @@ -451,9 +457,12 @@ impl Context {
self.emit_event(EventType::MsgsChanged { chat_id, msg_id });
}

/// Emits an IncomingMsg event with specified chat and message ids
/// Emits an IncomingMsg event with specified chat and message ids.
///
/// Notifies `get_next_fresh_msg()` that there might be a new fresh message.
pub fn emit_incoming_msg(&self, chat_id: ChatId, msg_id: MsgId) {
self.emit_event(EventType::IncomingMsg { chat_id, msg_id });
self.notify_fresh_message.notify_one();
}

/// Returns a receiver for emitted events.
Expand Down Expand Up @@ -751,6 +760,19 @@ impl Context {
Ok(list)
}

/// Returns oldest fresh message in unmuted and unblocked chats.
///
/// If there are no such messages, waits until there is one.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waits until there is one.

is this also true for cffi/jsonprc? if so, this information should be added to the docs there as well.

maybe also add a line for the usecase. though i am sure, there is concrete need somewhere, the uscase is not clear to at least to me :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe better rename the function to wait_for_next_fresh_message(), i would not expect a get-function to block for maybe hours.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I named it similarly to get_next_event() for consistency. We can call it something with wait, but then there can be an impression that get_next_event() is somehow different and non-blocking.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, get_next_event() is called on an explicit event emitter object that does not have many other usages, so that seems less confusing than for the context where all the other get() work differently.

but i agree, wait() would have been better for the context emitter as well.

i still suggest to not repeat the "mistake" use sth. with "wait" in the name here. maybe we can rename the other usages accordingly when we iterate over or so.

pub async fn get_next_fresh_msg(&self) -> Result<MsgId> {
loop {
if let Some(msg_id) = self.get_fresh_msgs().await?.last() {
return Ok(*msg_id);
} else {
self.notify_fresh_message.notified().await;
}
}
}

/// Searches for messages containing the query string.
///
/// If `chat_id` is provided this searches only for messages in this chat, if `chat_id`
Expand Down