fix: assign iroh gossip topic to pre-message when post-message is received

Iroh-Gossip-Topic is sent in a post-message. Post-message goes to trash,
so topic should be associated with the existing pre-message that is
updated rather than with the post-message.
This commit is contained in:
link2xt
2026-02-16 21:26:40 +00:00
committed by l
parent a63f695b85
commit 2131f5e9c0
4 changed files with 59 additions and 18 deletions

View File

@@ -24,6 +24,13 @@ def path_to_webxdc(request):
return str(p)
@pytest.fixture
def path_to_large_webxdc(request):
p = request.path.parent.parent.parent.joinpath("test-data/webxdc/realtime-check.xdc")
assert p.exists()
return str(p)
def log(msg):
logging.info(msg)
@@ -227,3 +234,29 @@ def test_advertisement_after_chatting(acfactory, path_to_webxdc):
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
event = ac1.wait_for_event(EventType.WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED)
assert event.msg_id == ac1_webxdc_msg.id
def test_realtime_large_webxdc(acfactory, path_to_large_webxdc):
"""Tests initializing realtime channel on a large webxdc.
This is a regression test for a bug that existed in version 2.42.0.
Large webxdc is split into pre- and post- message,
and this previously resulted in failure to initialize realtime.
"""
ac1, ac2 = acfactory.get_online_accounts(2)
ac1.set_config("webxdc_realtime_enabled", "1")
ac2.set_config("webxdc_realtime_enabled", "1")
ac2.create_chat(ac1)
ac1_ac2_chat = ac1.create_chat(ac2)
ac1_webxdc_msg = ac1_ac2_chat.send_message(text="realtime check", file=path_to_large_webxdc)
# Receive pre-message.
ac2_webxdc_msg = ac2.wait_for_incoming_msg()
# Receive post-message.
ac2_webxdc_msg = ac2.wait_for_msg(EventType.MSGS_CHANGED)
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
event = ac1.wait_for_event(EventType.WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED)
assert event.msg_id == ac1_webxdc_msg.id

View File

@@ -521,6 +521,18 @@ pub(crate) async fn create_iroh_header(ctx: &Context, msg_id: MsgId) -> Result<S
Ok(topic_string)
}
/// Converts `Iroh-Gossip-Header` contents to iroh topic ID.
pub(crate) fn iroh_topic_from_str(topic: &str) -> Result<TopicId> {
let mut topic_raw = [0u8; 32];
BASE32_NOPAD
.decode_mut(topic.to_ascii_uppercase().as_bytes(), &mut topic_raw)
.map_err(|e| e.error)
.context("Wrong gossip topic header")?;
let topic = TopicId::from_bytes(topic_raw);
Ok(topic)
}
async fn subscribe_loop(
context: &Context,
mut stream: iroh_gossip::net::GossipReceiver,

View File

@@ -6,12 +6,10 @@ use std::iter;
use std::sync::LazyLock;
use anyhow::{Context as _, Result, ensure};
use data_encoding::BASE32_NOPAD;
use deltachat_contact_tools::{
ContactAddress, addr_cmp, addr_normalize, may_be_valid_addr, sanitize_bidi_characters,
sanitize_single_line,
};
use iroh_gossip::proto::TopicId;
use mailparse::SingleInfo;
use num_traits::FromPrimitive;
use regex::Regex;
@@ -39,7 +37,7 @@ use crate::mimeparser::{
AvatarAction, GossipedKey, MimeMessage, PreMessageMode, SystemMessage, parse_message_ids,
};
use crate::param::{Param, Params};
use crate::peer_channels::{add_gossip_peer_from_header, insert_topic_stub};
use crate::peer_channels::{add_gossip_peer_from_header, insert_topic_stub, iroh_topic_from_str};
use crate::reaction::{Reaction, set_msg_reaction};
use crate::rusqlite::OptionalExtension;
use crate::securejoin::{
@@ -2298,21 +2296,12 @@ RETURNING id
// Maybe set logging xdc and add gossip topics for webxdcs.
for (part, msg_id) in mime_parser.parts.iter().zip(&created_db_entries) {
// check if any part contains a webxdc topic id
if part.typ == Viewtype::Webxdc {
if let Some(topic) = mime_parser.get_header(HeaderDef::IrohGossipTopic) {
// default encoding of topic ids is `hex`.
let mut topic_raw = [0u8; 32];
BASE32_NOPAD
.decode_mut(topic.to_ascii_uppercase().as_bytes(), &mut topic_raw)
.map_err(|e| e.error)
.context("Wrong gossip topic header")?;
let topic = TopicId::from_bytes(topic_raw);
insert_topic_stub(context, *msg_id, topic).await?;
} else {
warn!(context, "webxdc doesn't have a gossip topic")
}
if mime_parser.pre_message != PreMessageMode::Post
&& part.typ == Viewtype::Webxdc
&& let Some(topic) = mime_parser.get_header(HeaderDef::IrohGossipTopic)
{
let topic = iroh_topic_from_str(topic)?;
insert_topic_stub(context, *msg_id, topic).await?;
}
maybe_set_logging_xdc_inner(
@@ -2517,6 +2506,13 @@ async fn handle_post_message(
return Ok(());
}
if part.typ == Viewtype::Webxdc
&& let Some(topic) = mime_parser.get_header(HeaderDef::IrohGossipTopic)
{
let topic = iroh_topic_from_str(topic)?;
insert_topic_stub(context, msg_id, topic).await?;
}
let mut new_params = original_msg.param.clone();
new_params
.merge_in_params(part.param.clone())

Binary file not shown.