Answer "what wanted me", in one query
Issue #10. The highlight flag is already recorded per message when it arrives, by the backend that can actually tell - Discord from its own resolved mentions array, IRC from the nickname because that is all IRC has - so collecting them is one query rather than a walk of every buffer. It has to come from here rather than from what a client has loaded: a mention worth an inbox is usually in a channel nobody has open, so the client has never seen it. Channels only, which is the rule Discord's own list follows. A direct message is addressed to you in its entirety, so "mentioned" adds nothing there and it already has its own page. Leaving them in also dragged along every service robot that talks in a query - NickServ says your nickname in every line it sends, so the page filled with "You are now identified for" and buried the mentions it exists to collect. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -822,6 +822,34 @@ pub async fn dispatch(
|
||||
}
|
||||
},
|
||||
|
||||
// Everything that mentioned this account, across every conversation.
|
||||
//
|
||||
// Asked of the daemon rather than assembled by a client from what it
|
||||
// happens to have loaded: a mention worth an inbox is usually in a
|
||||
// channel nobody has opened, so the client has never seen it.
|
||||
"getMentions" => {
|
||||
// Channels only, which is the same rule Discord's own mentions
|
||||
// list follows. A direct message is addressed to you in its
|
||||
// entirety, so "mentioned" adds nothing there - and it already has
|
||||
// both its own page and its own tile in the column. Leaving them
|
||||
// in also dragged along every service robot that talks in a query:
|
||||
// on IRC, NickServ says your nickname in every line it sends, so
|
||||
// the page filled with "You are now identified for" and buried
|
||||
// the mentions it exists to collect.
|
||||
let buffers: Vec<String> = state
|
||||
.runtime
|
||||
.list_buffers()
|
||||
.into_iter()
|
||||
.filter(|b| b.kind == "channel")
|
||||
.map(|b| b.id)
|
||||
.collect();
|
||||
let limit = p_i64(params, "limit", 100);
|
||||
match state.store.mentions(&buffers, limit) {
|
||||
Ok(messages) => (Some(serde_json::to_value(messages).unwrap()), None),
|
||||
Err(e) => (None, Some(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
// Where a file can be put so it can be linked to, and doing it.
|
||||
//
|
||||
// Listed rather than hard-coded into each client: the choice of where
|
||||
|
||||
@@ -359,6 +359,41 @@ impl Store {
|
||||
}
|
||||
|
||||
impl Store {
|
||||
/// Every message that mentioned this account, newest first, across all of
|
||||
/// its conversations.
|
||||
///
|
||||
/// One query rather than a walk of every buffer: what makes an inbox worth
|
||||
/// having is that it answers "what wanted me" in one place, and the
|
||||
/// highlight flag is already recorded per message at the point it arrives
|
||||
/// - by the backend that knows whether a mention is real, which for
|
||||
/// Discord is its own resolved mentions array rather than a guess at the
|
||||
/// nickname.
|
||||
pub fn mentions(&self, buffer_ids: &[String], limit: i64) -> Result<Vec<Message>> {
|
||||
if buffer_ids.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let conn = self.conn.lock().unwrap();
|
||||
let limit = if limit > 0 { limit } else { 100 };
|
||||
let places = std::iter::repeat("?").take(buffer_ids.len()).collect::<Vec<_>>().join(",");
|
||||
let sql = format!(
|
||||
"SELECT msg_id, from_nick, body, ts, is_action, is_highlight, kind, reply_to_id, reply_to_from, reply_to_body, edited, reactions, is_own, avatar_url, embeds, sender_id, attachments, buffer_id
|
||||
FROM messages
|
||||
WHERE is_highlight = 1 AND is_own = 0 AND buffer_id IN ({places})
|
||||
ORDER BY ts DESC LIMIT ?"
|
||||
);
|
||||
let mut stmt = conn.prepare(&sql)?;
|
||||
let mut params: Vec<&dyn rusqlite::ToSql> = buffer_ids.iter().map(|b| b as &dyn rusqlite::ToSql).collect();
|
||||
params.push(&limit);
|
||||
let rows = stmt.query_map(params.as_slice(), |row| {
|
||||
// The buffer is read back per row rather than stamped from a
|
||||
// parameter, since unlike every other query here this one spans
|
||||
// conversations and each answer belongs to a different one.
|
||||
let buffer_id: String = row.get(17)?;
|
||||
Self::row_to_message(&buffer_id, row)
|
||||
})?;
|
||||
rows.collect::<rusqlite::Result<_>>().map_err(Into::into)
|
||||
}
|
||||
|
||||
/// Messages in one buffer whose text contains `query`.
|
||||
///
|
||||
/// Deliberately a substring match rather than a word index: scrollback
|
||||
|
||||
Reference in New Issue
Block a user