···322322 },
323323 #[cfg(feature = "webgpu")]
324324 ScriptToConstellationMessage::RequestAdapter(response_sender, options, ids) => self
325325-@@ -2045,6 +2178,391 @@
325325+@@ -2045,6 +2178,407 @@
326326 let _ = event_loop.send(ScriptThreadMessage::TriggerGarbageCollection);
327327 }
328328 },
···559559+ fn handle_pairing_event(&mut self, event: constellation_traits::PairingEvent) {
560560+ if let constellation_traits::PairingEvent::MessageReceived { ref from, ref data } = event {
561561+ debug!("P2P message received from {from}, {} bytes", data.len());
562562++
563563++ // On first message from a peer, sync our channels to them.
564564++ // This handles the case where our initial sync at discovery
565565++ // time failed because the connection wasn't ready yet.
566566++ if self.pairing.confirm_peer(from) {
567567++ let channels: Vec<_> = self
568568++ .broadcast_channels
569569++ .open_channels()
570570++ .into_iter()
571571++ .map(|(origin, name)| (origin.ascii_serialization(), name))
572572++ .collect();
573573++ if !channels.is_empty() {
574574++ self.pairing.sync_channels_to_peer(from, &channels);
575575++ }
576576++ }
577577++
562578+ if let Some((from, message)) = self.pairing.handle_incoming_message(from, data) {
563579+ debug!("Decoded P2P message: {message:?}");
564580+ match message {
···714730 }
715731 }
716732717717-@@ -2364,6 +2882,29 @@
733733+@@ -2364,6 +2898,29 @@
718734 TransferState::TransferInProgress(queue) => queue.push_back(task),
719735 TransferState::CompletionFailed(queue) => queue.push_back(task),
720736 TransferState::CompletionRequested(_, queue) => queue.push_back(task),
···744760 }
745761 }
746762747747-@@ -3243,6 +3784,13 @@
763763+@@ -3243,6 +3800,13 @@
748764 /// <https://html.spec.whatwg.org/multipage/#destroy-a-top-level-traversable>
749765 fn handle_close_top_level_browsing_context(&mut self, webview_id: WebViewId) {
750766 debug!("{webview_id}: Closing");
···758774 let browsing_context_id = BrowsingContextId::from(webview_id);
759775 // Step 5. Remove traversable from the user agent's top-level traversable set.
760776 let browsing_context =
761761-@@ -3519,8 +4067,27 @@
777777+@@ -3519,8 +4083,27 @@
762778 opener_webview_id,
763779 opener_pipeline_id,
764780 response_sender,
···786802 let Some((webview_id_sender, webview_id_receiver)) = generic_channel::channel() else {
787803 warn!("Failed to create channel");
788804 let _ = response_sender.send(None);
789789-@@ -3619,6 +4186,361 @@
805805+@@ -3619,6 +4202,361 @@
790806 });
791807 }
792808···11481164 #[servo_tracing::instrument(skip_all)]
11491165 fn handle_refresh_cursor(&self, pipeline_id: PipelineId) {
11501166 let Some(pipeline) = self.pipelines.get(&pipeline_id) else {
11511151-@@ -4744,7 +5666,7 @@
11671167+@@ -4744,7 +5682,7 @@
11521168 }
1153116911541170 #[servo_tracing::instrument(skip_all)]
···11571173 // Send a flat projection of the history to embedder.
11581174 // The final vector is a concatenation of the URLs of the past
11591175 // entries, the current entry and the future entries.
11601160-@@ -4847,9 +5769,23 @@
11761176+@@ -4847,9 +5785,23 @@
11611177 );
11621178 self.embedder_proxy.send(EmbedderMsg::HistoryChanged(
11631179 webview_id,
+14-2
patches/components/constellation/pairing.rs.patch
···11--- original
22+++ modified
33-@@ -0,0 +1,804 @@
33+@@ -0,0 +1,816 @@
44+// SPDX-License-Identifier: AGPL-3.0-or-later
55+
66+//! P2P pairing service integration with the constellation.
···8383+ /// Remote broadcast channels announced by each paired peer.
8484+ /// Maps a endpoint ID to a set of (origin, channel_name).
8585+ remote_channels: Arc<Mutex<HashMap<String, HashSet<(String, String)>>>>,
8686++ /// Peers that have confirmed bidirectional communication
8787++ /// (we received at least one message from them).
8888++ confirmed_peers: HashSet<String>,
8689+}
8790+
8891+impl PairingService {
···9295+ local_info: Default::default(),
9396+ event_receiver: None,
9497+ remote_channels: Default::default(),
9898++ confirmed_peers: Default::default(),
9599+ }
96100+ }
97101+
···624628+ }
625629+
626630+ /// Clear all remote channel state for a given peer (e.g. on disconnect).
627627-+ pub(crate) fn clear_remote_peer(&self, peer_id: &str) {
631631++ pub(crate) fn clear_remote_peer(&mut self, peer_id: &str) {
632632++ self.confirmed_peers.remove(peer_id);
628633+ let remote_channels = self.remote_channels.clone();
629634+ let peer_id = peer_id.to_owned();
630635+ net::async_runtime::spawn_task(async move {
···682687+ }
683688+ }
684689+ });
690690++ }
691691++
692692++ /// Returns true and marks the peer as confirmed if this is the first
693693++ /// message we've received from them. Used to trigger a reciprocal
694694++ /// channel sync when the connection is proven to be working.
695695++ pub(crate) fn confirm_peer(&mut self, peer_id: &str) -> bool {
696696++ self.confirmed_peers.insert(peer_id.to_owned())
685697+ }
686698+}
687699+