Skip to main content

fission_shell_winit/
wifi.rs

1use fission_core::{
2    WifiAvailability, WifiConnectRequest, WifiConnection, WifiDisconnectRequest, WifiError,
3    WifiNetwork, WifiPermission, WifiPermissionRequest, WifiScanRequest, WifiScanResult,
4    WifiSecurity, CONNECT_WIFI_NETWORK, DISCONNECT_WIFI_NETWORK, GET_WIFI_AVAILABILITY,
5    REQUEST_WIFI_PERMISSION, SCAN_WIFI_NETWORKS,
6};
7use fission_shell::async_host::AsyncRegistry;
8use std::sync::Arc;
9
10/// Host-side Wi-Fi provider.
11pub trait WifiHost: Send + Sync + 'static {
12    /// Returns Wi-Fi adapter, permission, and current connection state.
13    fn availability(&self) -> Result<WifiAvailability, WifiError>;
14    /// Requests Wi-Fi, nearby-network, or related location permission from the host.
15    fn request_permission(
16        &self,
17        request: WifiPermissionRequest,
18    ) -> Result<WifiPermission, WifiError>;
19    /// Scans for nearby Wi-Fi networks using the supplied filters.
20    fn scan_networks(&self, request: WifiScanRequest) -> Result<WifiScanResult, WifiError>;
21    /// Requests connection to one Wi-Fi network.
22    fn connect_network(&self, request: WifiConnectRequest) -> Result<WifiConnection, WifiError>;
23    /// Requests disconnection from a Wi-Fi network.
24    fn disconnect_network(&self, request: WifiDisconnectRequest) -> Result<(), WifiError>;
25}
26
27#[derive(Debug, Default)]
28pub struct UnsupportedWifiHost;
29
30impl WifiHost for UnsupportedWifiHost {
31    fn availability(&self) -> Result<WifiAvailability, WifiError> {
32        Ok(WifiAvailability {
33            permission: WifiPermission::Denied,
34            enabled: false,
35            connected_network: None,
36        })
37    }
38
39    fn request_permission(
40        &self,
41        _request: WifiPermissionRequest,
42    ) -> Result<WifiPermission, WifiError> {
43        Err(WifiError::unsupported("request_permission"))
44    }
45
46    fn scan_networks(&self, _request: WifiScanRequest) -> Result<WifiScanResult, WifiError> {
47        Err(WifiError::unsupported("scan_networks"))
48    }
49
50    fn connect_network(&self, _request: WifiConnectRequest) -> Result<WifiConnection, WifiError> {
51        Err(WifiError::unsupported("connect_network"))
52    }
53
54    fn disconnect_network(&self, _request: WifiDisconnectRequest) -> Result<(), WifiError> {
55        Err(WifiError::unsupported("disconnect_network"))
56    }
57}
58
59#[derive(Debug, Clone)]
60pub struct MemoryWifiHost {
61    availability: WifiAvailability,
62    networks: Vec<WifiNetwork>,
63}
64
65impl MemoryWifiHost {
66    pub fn new(availability: WifiAvailability, networks: Vec<WifiNetwork>) -> Self {
67        Self {
68            availability,
69            networks,
70        }
71    }
72}
73
74impl Default for MemoryWifiHost {
75    fn default() -> Self {
76        let network = WifiNetwork {
77            ssid: "Fission".into(),
78            bssid: Some("00:11:22:33:44:55".into()),
79            rssi: Some(-45),
80            frequency_mhz: Some(5_200),
81            security: WifiSecurity::Wpa3,
82            connected: true,
83        };
84        Self::new(
85            WifiAvailability {
86                permission: WifiPermission::Granted,
87                enabled: true,
88                connected_network: Some(network.clone()),
89            },
90            vec![network],
91        )
92    }
93}
94
95impl WifiHost for MemoryWifiHost {
96    fn availability(&self) -> Result<WifiAvailability, WifiError> {
97        Ok(self.availability.clone())
98    }
99
100    fn request_permission(
101        &self,
102        _request: WifiPermissionRequest,
103    ) -> Result<WifiPermission, WifiError> {
104        Ok(self.availability.permission)
105    }
106
107    fn scan_networks(&self, _request: WifiScanRequest) -> Result<WifiScanResult, WifiError> {
108        Ok(WifiScanResult {
109            networks: self.networks.clone(),
110        })
111    }
112
113    fn connect_network(&self, request: WifiConnectRequest) -> Result<WifiConnection, WifiError> {
114        let network = self
115            .networks
116            .iter()
117            .find(|network| network.ssid == request.ssid)
118            .cloned()
119            .ok_or_else(|| WifiError::new("not_found", "Wi-Fi network not found"))?;
120        Ok(WifiConnection { network })
121    }
122
123    fn disconnect_network(&self, _request: WifiDisconnectRequest) -> Result<(), WifiError> {
124        Ok(())
125    }
126}
127
128pub(crate) fn register_wifi_capabilities(
129    async_registry: &mut AsyncRegistry,
130    host: Arc<dyn WifiHost>,
131) {
132    let availability_host = host.clone();
133    async_registry.register_operation_capability(GET_WIFI_AVAILABILITY, move |(), _| {
134        let host = availability_host.clone();
135        async move { host.availability() }
136    });
137
138    let permission_host = host.clone();
139    async_registry.register_operation_capability(REQUEST_WIFI_PERMISSION, move |request, _| {
140        let host = permission_host.clone();
141        async move { host.request_permission(request) }
142    });
143
144    let scan_host = host.clone();
145    async_registry.register_operation_capability(SCAN_WIFI_NETWORKS, move |request, _| {
146        let host = scan_host.clone();
147        async move { host.scan_networks(request) }
148    });
149
150    let connect_host = host.clone();
151    async_registry.register_operation_capability(CONNECT_WIFI_NETWORK, move |request, _| {
152        let host = connect_host.clone();
153        async move { host.connect_network(request) }
154    });
155
156    async_registry.register_operation_capability(DISCONNECT_WIFI_NETWORK, move |request, _| {
157        let host = host.clone();
158        async move { host.disconnect_network(request) }
159    });
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn unsupported_host_reports_errors() {
168        let host = UnsupportedWifiHost;
169        assert!(host.scan_networks(WifiScanRequest::default()).is_err());
170    }
171
172    #[test]
173    fn memory_host_scans_and_connects() {
174        let host = MemoryWifiHost::default();
175        let scan = host.scan_networks(WifiScanRequest::default()).unwrap();
176        assert_eq!(scan.networks.len(), 1);
177
178        let connection = host
179            .connect_network(WifiConnectRequest {
180                ssid: "Fission".into(),
181                security: WifiSecurity::Wpa3,
182                ..Default::default()
183            })
184            .unwrap();
185        assert_eq!(connection.network.ssid, "Fission");
186    }
187}