wlancfg_lib/util/listener/
access_point.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::generic::{CurrentStateCache, Listener, Message};
6use crate::access_point::types;
7use fidl_fuchsia_wlan_policy as fidl_policy;
8use futures::channel::mpsc;
9use futures::future::LocalBoxFuture;
10use futures::prelude::*;
11
12#[derive(Copy, Clone, Debug, PartialEq)]
13pub struct ConnectedClientInformation {
14    pub count: u8,
15}
16
17impl From<ConnectedClientInformation> for fidl_policy::ConnectedClientInformation {
18    fn from(connected_client_info: ConnectedClientInformation) -> Self {
19        fidl_policy::ConnectedClientInformation {
20            count: Some(connected_client_info.count),
21            ..Default::default()
22        }
23    }
24}
25
26#[cfg_attr(test, derive(Debug))]
27#[derive(Clone, PartialEq)]
28pub struct ApStatesUpdate {
29    pub access_points: Vec<ApStateUpdate>,
30}
31
32#[cfg_attr(test, derive(Debug))]
33#[derive(Clone, PartialEq)]
34pub struct ApStateUpdate {
35    pub id: types::NetworkIdentifier,
36    pub state: types::OperatingState,
37    pub mode: Option<types::ConnectivityMode>,
38    pub band: Option<types::OperatingBand>,
39    pub frequency: Option<u32>,
40    pub clients: Option<ConnectedClientInformation>,
41}
42
43impl ApStateUpdate {
44    pub fn new(
45        id: types::NetworkIdentifier,
46        state: types::OperatingState,
47        mode: types::ConnectivityMode,
48        band: types::OperatingBand,
49    ) -> Self {
50        ApStateUpdate {
51            id,
52            state,
53            mode: Some(mode),
54            band: Some(band),
55            frequency: None,
56            clients: None,
57        }
58    }
59}
60
61impl From<ApStatesUpdate> for Vec<fidl_policy::AccessPointState> {
62    fn from(ap_updates: ApStatesUpdate) -> Self {
63        ap_updates
64            .access_points
65            .iter()
66            .map(|ap| fidl_policy::AccessPointState {
67                id: Some(fidl_policy::NetworkIdentifier::from(ap.id.clone())),
68                state: Some(fidl_policy::OperatingState::from(ap.state)),
69                mode: ap.mode.map(fidl_policy::ConnectivityMode::from),
70                band: ap.band.map(fidl_policy::OperatingBand::from),
71                frequency: ap.frequency,
72                clients: ap.clients.map(|c| c.into()),
73                ..Default::default()
74            })
75            .collect()
76    }
77}
78
79impl CurrentStateCache for ApStatesUpdate {
80    fn default() -> ApStatesUpdate {
81        ApStatesUpdate { access_points: vec![] }
82    }
83
84    fn merge_in_update(&mut self, update: Self) {
85        self.access_points = update.access_points;
86    }
87
88    fn purge(&mut self) {}
89}
90
91impl Listener<Vec<fidl_policy::AccessPointState>> for fidl_policy::AccessPointStateUpdatesProxy {
92    fn notify_listener(
93        self,
94        update: Vec<fidl_policy::AccessPointState>,
95    ) -> LocalBoxFuture<'static, Option<Box<Self>>> {
96        let fut = async move {
97            let fut = self.on_access_point_state_update(&update);
98            fut.await.ok().map(|()| Box::new(self))
99        };
100        fut.boxed()
101    }
102}
103
104// Helpful aliases for servicing client updates
105pub type ApMessage = Message<fidl_policy::AccessPointStateUpdatesProxy, ApStatesUpdate>;
106pub type ApListenerMessageSender = mpsc::UnboundedSender<ApMessage>;
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111    use crate::client::types::Ssid;
112    use fidl_fuchsia_wlan_policy as fidl_policy;
113
114    fn create_network_id() -> types::NetworkIdentifier {
115        types::NetworkIdentifier {
116            ssid: Ssid::try_from("test").unwrap(),
117            security_type: types::SecurityType::None,
118        }
119    }
120
121    #[fuchsia::test]
122    fn merge_updates() {
123        let mut current_state_cache = ApStatesUpdate::default();
124        assert_eq!(current_state_cache, ApStatesUpdate { access_points: vec![] });
125
126        // Merge in an update with one connected network.
127        let update = ApStatesUpdate {
128            access_points: vec![{
129                ApStateUpdate {
130                    id: create_network_id(),
131                    state: types::OperatingState::Starting,
132                    mode: Some(types::ConnectivityMode::Unrestricted),
133                    band: Some(types::OperatingBand::Any),
134                    frequency: None,
135                    clients: Some(ConnectedClientInformation { count: 0 }),
136                }
137            }],
138        };
139        current_state_cache.merge_in_update(update);
140
141        assert_eq!(
142            current_state_cache,
143            ApStatesUpdate {
144                access_points: vec![{
145                    ApStateUpdate {
146                        id: create_network_id(),
147                        state: types::OperatingState::Starting,
148                        mode: Some(types::ConnectivityMode::Unrestricted),
149                        band: Some(types::OperatingBand::Any),
150                        frequency: None,
151                        clients: Some(ConnectedClientInformation { count: 0 }),
152                    }
153                }],
154            }
155        );
156    }
157
158    #[fuchsia::test]
159    fn into_fidl() {
160        let state = ApStatesUpdate {
161            access_points: vec![{
162                ApStateUpdate {
163                    id: create_network_id(),
164                    state: types::OperatingState::Starting,
165                    mode: Some(types::ConnectivityMode::Unrestricted),
166                    band: Some(types::OperatingBand::Any),
167                    frequency: Some(200),
168                    clients: Some(ConnectedClientInformation { count: 1 }),
169                }
170            }],
171        };
172        let fidl_state: Vec<fidl_policy::AccessPointState> = state.into();
173        assert_eq!(
174            fidl_state,
175            vec![fidl_policy::AccessPointState {
176                id: Some(fidl_policy::NetworkIdentifier {
177                    ssid: Ssid::try_from("test").unwrap().to_vec(),
178                    type_: fidl_policy::SecurityType::None,
179                }),
180                state: Some(fidl_policy::OperatingState::Starting),
181                mode: Some(fidl_policy::ConnectivityMode::Unrestricted),
182                band: Some(fidl_policy::OperatingBand::Any),
183                frequency: Some(200),
184                clients: Some(fidl_policy::ConnectedClientInformation {
185                    count: Some(1),
186                    ..Default::default()
187                }),
188                ..Default::default()
189            }]
190        );
191    }
192}