@@ -1746,7 +1746,7 @@ impl AppCore {
17461746 self . last_outgoing_ts
17471747 } ;
17481748
1749- let ( client, wrapper , relays , rumor_id_hex) = {
1749+ let ( client, relays , rumor , rumor_id_hex) = {
17501750 let Some ( sess) = self . session . as_mut ( ) else {
17511751 return ;
17521752 } ;
@@ -1788,6 +1788,149 @@ impl AppCore {
17881788 } ,
17891789 ) ;
17901790
1791+ let relays: Vec < RelayUrl > = if network_enabled {
1792+ sess. mdk
1793+ . get_relays ( & group. mls_group_id )
1794+ . ok ( )
1795+ . map ( |s| s. into_iter ( ) . collect ( ) )
1796+ . filter ( |v : & Vec < RelayUrl > | !v. is_empty ( ) )
1797+ . unwrap_or_else ( || fallback_relays. clone ( ) )
1798+ } else {
1799+ vec ! [ ]
1800+ } ;
1801+
1802+ ( sess. client . clone ( ) , relays, rumor, rumor_id_hex)
1803+ } ;
1804+
1805+ self . prune_local_outbox ( & chat_id) ;
1806+ self . refresh_chat_list_from_storage ( ) ;
1807+ self . refresh_current_chat_if_open ( & chat_id) ;
1808+
1809+ if !network_enabled {
1810+ let _ = self . core_sender . send ( CoreMsg :: Internal ( Box :: new (
1811+ InternalEvent :: PublishMessageResult {
1812+ chat_id,
1813+ rumor_id : rumor_id_hex,
1814+ ok : false ,
1815+ error : Some ( "offline" . into ( ) ) ,
1816+ } ,
1817+ ) ) ) ;
1818+ return ;
1819+ }
1820+
1821+ let tx = self . core_sender . clone ( ) ;
1822+ let mut seen_ids = self . processed_group_event_ids . clone ( ) ;
1823+ let chat_id_for_task = chat_id. clone ( ) ;
1824+ self . runtime . spawn ( async move {
1825+ let filter = Filter :: new ( )
1826+ . kind ( Kind :: MlsGroupMessage )
1827+ . custom_tags (
1828+ SingleLetterTag :: lowercase ( Alphabet :: H ) ,
1829+ vec ! [ chat_id_for_task. clone( ) ] ,
1830+ )
1831+ . limit ( 200 ) ;
1832+ let ( mut backlog_events, error) = match client
1833+ . fetch_events_from ( relays. clone ( ) , filter, std:: time:: Duration :: from_secs ( 8 ) )
1834+ . await
1835+ {
1836+ Ok ( evts) => ( evts. into_iter ( ) . collect :: < Vec < Event > > ( ) , None ) ,
1837+ Err ( e) => ( Vec :: new ( ) , Some ( format ! ( "group backlog fetch failed: {e}" ) ) ) ,
1838+ } ;
1839+ backlog_events. retain ( |ev| seen_ids. insert ( ev. id ) ) ;
1840+ backlog_events. sort_by_key ( |ev| ev. created_at . as_secs ( ) ) ;
1841+
1842+ let _ = tx. send ( CoreMsg :: Internal ( Box :: new (
1843+ InternalEvent :: GroupSendCatchupCompleted {
1844+ chat_id : chat_id_for_task,
1845+ rumor,
1846+ backlog_events,
1847+ error,
1848+ } ,
1849+ ) ) ) ;
1850+ } ) ;
1851+ }
1852+
1853+ pub ( super ) fn handle_group_send_catchup_completed (
1854+ & mut self ,
1855+ chat_id : String ,
1856+ rumor : UnsignedEvent ,
1857+ backlog_events : Vec < Event > ,
1858+ error : Option < String > ,
1859+ ) {
1860+ if let Some ( err) = error {
1861+ tracing:: warn!( %chat_id, %err, "group send backlog fetch failed" ) ;
1862+ }
1863+ self . ingest_group_backlog_events ( backlog_events) ;
1864+ self . publish_prepared_group_rumor ( chat_id, rumor) ;
1865+ }
1866+
1867+ fn ingest_group_backlog_events ( & mut self , backlog_events : Vec < Event > ) {
1868+ let mut remaining = backlog_events;
1869+ let mut processed_any = false ;
1870+ for _ in 0 ..3 {
1871+ if remaining. is_empty ( ) {
1872+ break ;
1873+ }
1874+ let current = std:: mem:: take ( & mut remaining) ;
1875+ let mut next = Vec :: new ( ) ;
1876+ for event in current. into_iter ( ) {
1877+ let event_id = event. id ;
1878+ let result = {
1879+ let Some ( sess) = self . session . as_mut ( ) else {
1880+ return ;
1881+ } ;
1882+ sess. mdk . process_message ( & event)
1883+ } ;
1884+ match result {
1885+ Ok ( r) => {
1886+ self . note_processed_group_event_id_in_memory ( event_id) ;
1887+ processed_any = true ;
1888+ self . handle_message_processing_result ( r) ;
1889+ }
1890+ Err ( e) => {
1891+ tracing:: debug!( event_id = %event. id. to_hex( ) , %e, "deferred backlog message" ) ;
1892+ next. push ( event) ;
1893+ }
1894+ }
1895+ }
1896+ if next. is_empty ( ) {
1897+ break ;
1898+ }
1899+ remaining = next;
1900+ }
1901+ if !remaining. is_empty ( ) {
1902+ tracing:: warn!( remaining = remaining. len( ) , "failed to ingest some backlog events" ) ;
1903+ }
1904+ if processed_any {
1905+ self . persist_processed_group_event_ids_cache ( ) ;
1906+ }
1907+ }
1908+
1909+ fn publish_prepared_group_rumor ( & mut self , chat_id : String , mut rumor : UnsignedEvent ) {
1910+ let network_enabled = self . network_enabled ( ) ;
1911+ let fallback_relays = self . default_relays ( ) ;
1912+ let rumor_id_hex = rumor. id ( ) . to_hex ( ) ;
1913+
1914+ let mark_publish_failed = |core : & mut Self , reason : & str | {
1915+ core. handle_publish_message_result (
1916+ chat_id. clone ( ) ,
1917+ rumor_id_hex. clone ( ) ,
1918+ false ,
1919+ Some ( reason. to_string ( ) ) ,
1920+ ) ;
1921+ } ;
1922+
1923+ let ( client, wrapper, relays) = {
1924+ let Some ( sess) = self . session . as_mut ( ) else {
1925+ mark_publish_failed ( self , "session lost" ) ;
1926+ return ;
1927+ } ;
1928+ let Some ( group) = sess. groups . get ( & chat_id) . cloned ( ) else {
1929+ self . toast ( "Chat not found" ) ;
1930+ mark_publish_failed ( self , "chat not found" ) ;
1931+ return ;
1932+ } ;
1933+
17911934 let wrapper = match sess. mdk . create_message ( & group. mls_group_id , rumor) {
17921935 Ok ( e) => e,
17931936 Err ( e) => {
@@ -1821,13 +1964,9 @@ impl AppCore {
18211964 vec ! [ ]
18221965 } ;
18231966
1824- ( sess. client . clone ( ) , wrapper, relays, rumor_id_hex )
1967+ ( sess. client . clone ( ) , wrapper, relays)
18251968 } ;
18261969
1827- self . prune_local_outbox ( & chat_id) ;
1828- self . refresh_chat_list_from_storage ( ) ;
1829- self . refresh_current_chat_if_open ( & chat_id) ;
1830-
18311970 if !network_enabled {
18321971 let _ = self . core_sender . send ( CoreMsg :: Internal ( Box :: new (
18331972 InternalEvent :: PublishMessageResult {
0 commit comments