wlancfg_lib/util/listener/
client.rs1use super::generic::{CurrentStateCache, Listener, Message};
6use crate::client::types as client_types;
7use fidl_fuchsia_wlan_policy as fidl_policy;
8use futures::channel::mpsc;
9use futures::future::LocalBoxFuture;
10use futures::prelude::*;
11
12#[derive(Clone, PartialEq)]
13#[cfg_attr(test, derive(Debug))]
14pub struct ClientNetworkState {
15 pub id: client_types::NetworkIdentifier,
16 pub state: client_types::ConnectionState,
17 pub status: Option<client_types::DisconnectStatus>,
18}
19
20impl From<ClientNetworkState> for fidl_policy::NetworkState {
21 fn from(client_network_state: ClientNetworkState) -> Self {
22 fidl_policy::NetworkState {
23 id: Some(client_network_state.id.into()),
24 state: Some(client_network_state.state),
25 status: client_network_state.status,
26 ..Default::default()
27 }
28 }
29}
30
31#[cfg_attr(test, derive(Debug))]
32#[derive(Clone, PartialEq)]
33pub struct ClientStateUpdate {
34 pub state: fidl_policy::WlanClientState,
35 pub networks: Vec<ClientNetworkState>,
36}
37
38impl From<ClientStateUpdate> for fidl_policy::ClientStateSummary {
39 fn from(update: ClientStateUpdate) -> Self {
40 fidl_policy::ClientStateSummary {
41 state: Some(update.state),
42 networks: Some(update.networks.iter().map(|n| n.clone().into()).collect()),
43 ..Default::default()
44 }
45 }
46}
47
48impl CurrentStateCache for ClientStateUpdate {
49 fn default() -> ClientStateUpdate {
50 ClientStateUpdate {
53 state: fidl_policy::WlanClientState::ConnectionsDisabled,
54 networks: vec![],
55 }
56 }
57
58 fn merge_in_update(&mut self, update: Self) {
59 self.state = update.state;
60 self.networks = self
62 .networks
63 .iter()
64 .filter(|n| !update.networks.iter().any(|u| u.id == n.id))
65 .cloned()
66 .collect();
67 for network in update.networks.iter() {
69 self.networks.push(network.clone());
70 }
71 }
72
73 fn purge(&mut self) {
74 self.networks = self
76 .networks
77 .iter()
78 .filter(|n| match n.state {
79 fidl_policy::ConnectionState::Failed => false,
80 fidl_policy::ConnectionState::Disconnected => false,
81 fidl_policy::ConnectionState::Connecting => true,
82 fidl_policy::ConnectionState::Connected => true,
83 })
84 .cloned()
85 .collect();
86 }
87}
88impl Listener<fidl_policy::ClientStateSummary> for fidl_policy::ClientStateUpdatesProxy {
89 fn notify_listener(
90 self,
91 update: fidl_policy::ClientStateSummary,
92 ) -> LocalBoxFuture<'static, Option<Box<Self>>> {
93 let fut =
94 async move { self.on_client_state_update(&update).await.ok().map(|()| Box::new(self)) };
95 fut.boxed()
96 }
97}
98
99pub type ClientListenerMessage = Message<fidl_policy::ClientStateUpdatesProxy, ClientStateUpdate>;
101pub type ClientListenerMessageSender = mpsc::UnboundedSender<ClientListenerMessage>;
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::client::types::Ssid;
107 use fidl_fuchsia_wlan_policy as fidl_policy;
108
109 #[fuchsia::test]
110 fn merge_update_none_to_one_active() {
111 let mut current_state_cache = ClientStateUpdate::default();
112 assert_eq!(
113 current_state_cache,
114 ClientStateUpdate {
115 state: fidl_policy::WlanClientState::ConnectionsDisabled,
116 networks: vec![]
117 }
118 );
119
120 let update = ClientStateUpdate {
122 state: fidl_policy::WlanClientState::ConnectionsEnabled,
123 networks: vec![ClientNetworkState {
124 id: client_types::NetworkIdentifier {
125 ssid: Ssid::try_from("ssid 1").unwrap(),
126 security_type: client_types::SecurityType::Wpa2,
127 },
128 state: fidl_policy::ConnectionState::Connected,
129 status: None,
130 }],
131 };
132 current_state_cache.merge_in_update(update);
133
134 assert_eq!(
135 current_state_cache,
136 ClientStateUpdate {
137 state: fidl_policy::WlanClientState::ConnectionsEnabled,
138 networks: vec![ClientNetworkState {
139 id: client_types::NetworkIdentifier {
140 ssid: Ssid::try_from("ssid 1").unwrap(),
141 security_type: client_types::SecurityType::Wpa2,
142 },
143 state: fidl_policy::ConnectionState::Connected,
144 status: None,
145 }],
146 }
147 );
148 }
149
150 #[fuchsia::test]
151 fn merge_update_one_to_two_active() {
152 let mut current_state_cache = ClientStateUpdate {
154 state: fidl_policy::WlanClientState::ConnectionsEnabled,
155 networks: vec![ClientNetworkState {
156 id: client_types::NetworkIdentifier {
157 ssid: Ssid::try_from("ssid 1").unwrap(),
158 security_type: client_types::SecurityType::Wpa2,
159 },
160 state: fidl_policy::ConnectionState::Connected,
161 status: None,
162 }],
163 };
164
165 let update = ClientStateUpdate {
167 state: fidl_policy::WlanClientState::ConnectionsEnabled,
168 networks: vec![ClientNetworkState {
169 id: client_types::NetworkIdentifier {
170 ssid: Ssid::try_from("ssid 2").unwrap(),
171 security_type: client_types::SecurityType::Wpa2,
172 },
173 state: fidl_policy::ConnectionState::Connecting,
174 status: None,
175 }],
176 };
177 current_state_cache.merge_in_update(update);
178
179 assert_eq!(
181 current_state_cache,
182 ClientStateUpdate {
183 state: fidl_policy::WlanClientState::ConnectionsEnabled,
184 networks: vec![
185 ClientNetworkState {
186 id: client_types::NetworkIdentifier {
187 ssid: Ssid::try_from("ssid 1").unwrap(),
188 security_type: client_types::SecurityType::Wpa2,
189 },
190 state: fidl_policy::ConnectionState::Connected,
191 status: None,
192 },
193 ClientNetworkState {
194 id: client_types::NetworkIdentifier {
195 ssid: Ssid::try_from("ssid 2").unwrap(),
196 security_type: client_types::SecurityType::Wpa2,
197 },
198 state: fidl_policy::ConnectionState::Connecting,
199 status: None,
200 }
201 ],
202 }
203 );
204 }
205
206 #[fuchsia::test]
207 fn purge_inactive_network_states() {
208 let mut current_state_cache = ClientStateUpdate {
209 state: fidl_policy::WlanClientState::ConnectionsEnabled,
210 networks: vec![
211 ClientNetworkState {
212 id: client_types::NetworkIdentifier {
213 ssid: Ssid::try_from("ssid 1").unwrap(),
214 security_type: client_types::SecurityType::Wpa2,
215 },
216 state: fidl_policy::ConnectionState::Connected,
217 status: None,
218 },
219 ClientNetworkState {
220 id: client_types::NetworkIdentifier {
221 ssid: Ssid::try_from("ssid 2").unwrap(),
222 security_type: client_types::SecurityType::Wpa2,
223 },
224 state: fidl_policy::ConnectionState::Disconnected,
225 status: None,
226 },
227 ClientNetworkState {
228 id: client_types::NetworkIdentifier {
229 ssid: Ssid::try_from("ssid 3").unwrap(),
230 security_type: client_types::SecurityType::Wpa2,
231 },
232 state: fidl_policy::ConnectionState::Failed,
233 status: Some(client_types::DisconnectStatus::ConnectionStopped),
234 },
235 ],
236 };
237
238 current_state_cache.purge();
240
241 assert_eq!(
242 current_state_cache,
243 ClientStateUpdate {
244 state: fidl_policy::WlanClientState::ConnectionsEnabled,
245 networks: vec![ClientNetworkState {
246 id: client_types::NetworkIdentifier {
247 ssid: Ssid::try_from("ssid 1").unwrap(),
248 security_type: client_types::SecurityType::Wpa2,
249 },
250 state: fidl_policy::ConnectionState::Connected,
251 status: None,
252 }],
253 }
254 )
255 }
256
257 #[fuchsia::test]
258 fn into_fidl() {
259 let single_network_state = ClientStateUpdate {
260 state: fidl_policy::WlanClientState::ConnectionsEnabled,
261 networks: vec![ClientNetworkState {
262 id: client_types::NetworkIdentifier {
263 ssid: Ssid::try_from("ssid 1").unwrap(),
264 security_type: client_types::SecurityType::Wpa2,
265 },
266 state: fidl_policy::ConnectionState::Connected,
267 status: None,
268 }],
269 };
270 let fidl_state: fidl_policy::ClientStateSummary = single_network_state.into();
271 assert_eq!(
272 fidl_state,
273 fidl_policy::ClientStateSummary {
274 state: Some(fidl_policy::WlanClientState::ConnectionsEnabled),
275 networks: Some(vec![fidl_policy::NetworkState {
276 id: Some(fidl_policy::NetworkIdentifier {
277 ssid: Ssid::try_from("ssid 1").unwrap().to_vec(),
278 type_: fidl_policy::SecurityType::Wpa2,
279 }),
280 state: Some(fidl_policy::ConnectionState::Connected),
281 status: None,
282 ..Default::default()
283 }]),
284 ..Default::default()
285 }
286 );
287
288 let multi_network_state = ClientStateUpdate {
289 state: fidl_policy::WlanClientState::ConnectionsEnabled,
290 networks: vec![
291 ClientNetworkState {
292 id: client_types::NetworkIdentifier {
293 ssid: Ssid::try_from("ssid 2").unwrap(),
294 security_type: client_types::SecurityType::Wpa2,
295 },
296 state: fidl_policy::ConnectionState::Connecting,
297 status: None,
298 },
299 ClientNetworkState {
300 id: client_types::NetworkIdentifier {
301 ssid: Ssid::try_from("ssid 1").unwrap(),
302 security_type: client_types::SecurityType::Wpa2,
303 },
304 state: fidl_policy::ConnectionState::Disconnected,
305 status: Some(fidl_policy::DisconnectStatus::ConnectionStopped),
306 },
307 ],
308 };
309 let fidl_state: fidl_policy::ClientStateSummary = multi_network_state.into();
310 assert_eq!(
311 fidl_state,
312 fidl_policy::ClientStateSummary {
313 state: Some(fidl_policy::WlanClientState::ConnectionsEnabled),
314 networks: Some(vec![
315 fidl_policy::NetworkState {
316 id: Some(fidl_policy::NetworkIdentifier {
317 ssid: Ssid::try_from("ssid 2").unwrap().to_vec(),
318 type_: fidl_policy::SecurityType::Wpa2,
319 }),
320 state: Some(fidl_policy::ConnectionState::Connecting),
321 status: None,
322 ..Default::default()
323 },
324 fidl_policy::NetworkState {
325 id: Some(fidl_policy::NetworkIdentifier {
326 ssid: Ssid::try_from("ssid 1").unwrap().to_vec(),
327 type_: fidl_policy::SecurityType::Wpa2,
328 }),
329 state: Some(fidl_policy::ConnectionState::Disconnected),
330 status: Some(fidl_policy::DisconnectStatus::ConnectionStopped),
331 ..Default::default()
332 },
333 ]),
334 ..Default::default()
335 }
336 );
337 }
338}