servo_constellation/
broadcastchannel.rs1use std::collections::HashMap;
6
7use log::warn;
8use rustc_hash::FxHashMap;
9use servo_base::generic_channel::GenericCallback;
10use servo_base::id::BroadcastChannelRouterId;
11use servo_constellation_traits::BroadcastChannelMsg;
12use servo_url::ImmutableOrigin;
13
14#[derive(Default)]
15pub(crate) struct BroadcastChannels {
16 routers: FxHashMap<BroadcastChannelRouterId, GenericCallback<BroadcastChannelMsg>>,
18
19 channels: HashMap<ImmutableOrigin, HashMap<String, Vec<BroadcastChannelRouterId>>>,
21}
22
23impl BroadcastChannels {
24 #[servo_tracing::instrument(skip_all)]
26 pub fn new_broadcast_channel_router(
27 &mut self,
28 router_id: BroadcastChannelRouterId,
29 broadcast_callback: GenericCallback<BroadcastChannelMsg>,
30 ) {
31 if self.routers.insert(router_id, broadcast_callback).is_some() {
32 warn!("Multiple attempts to add BroadcastChannel router.");
33 }
34 }
35
36 #[servo_tracing::instrument(skip_all)]
38 pub fn remove_broadcast_channel_router(&mut self, router_id: BroadcastChannelRouterId) {
39 if self.routers.remove(&router_id).is_none() {
40 warn!("Attempt to remove unknown BroadcastChannel router.");
41 }
42 for channels in self.channels.values_mut() {
44 for routers in channels.values_mut() {
45 routers.retain(|router| router != &router_id);
46 }
47 }
48 }
49
50 #[servo_tracing::instrument(skip_all)]
52 pub fn new_broadcast_channel_name_in_router(
53 &mut self,
54 router_id: BroadcastChannelRouterId,
55 channel_name: String,
56 origin: ImmutableOrigin,
57 ) {
58 let channels = self.channels.entry(origin).or_default();
59 let routers = channels.entry(channel_name).or_default();
60 routers.push(router_id);
61 }
62
63 #[servo_tracing::instrument(skip_all)]
65 pub fn remove_broadcast_channel_name_in_router(
66 &mut self,
67 router_id: BroadcastChannelRouterId,
68 channel_name: String,
69 origin: ImmutableOrigin,
70 ) {
71 if let Some(channels) = self.channels.get_mut(&origin) {
72 let is_empty = if let Some(routers) = channels.get_mut(&channel_name) {
73 routers.retain(|router| router != &router_id);
74 routers.is_empty()
75 } else {
76 return warn!(
77 "Multiple attempts to remove name for BroadcastChannel {:?} at {:?}",
78 channel_name, origin
79 );
80 };
81 if is_empty {
82 channels.remove(&channel_name);
83 }
84 } else {
85 warn!(
86 "Attempt to remove a channel name for an origin without channels {:?}",
87 origin
88 );
89 }
90 }
91
92 #[servo_tracing::instrument(skip_all)]
94 pub fn schedule_broadcast(
95 &self,
96 router_id: BroadcastChannelRouterId,
97 message: BroadcastChannelMsg,
98 ) {
99 if let Some(channels) = self.channels.get(&message.origin) {
100 let routers = match channels.get(&message.channel_name) {
101 Some(routers) => routers,
102 None => return warn!("Broadcast to channel name without active routers."),
103 };
104 for router in routers {
105 if router == &router_id {
108 continue;
109 }
110
111 if let Some(broadcast_ipc_sender) = self.routers.get(router) {
112 if broadcast_ipc_sender.send(message.clone()).is_err() {
113 warn!("Failed to broadcast message to router: {:?}", router);
114 }
115 } else {
116 warn!("No sender for broadcast router: {:?}", router);
117 }
118 }
119 } else {
120 warn!(
121 "Attempt to schedule a broadcast for an origin without routers {:?}",
122 message.origin
123 );
124 }
125 }
126}