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