1use crate::capability::{CapabilityType, OperationCapability};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
7pub enum WifiPermission {
8 #[default]
9 Unknown,
10 Granted,
11 Denied,
12 Restricted,
13}
14
15#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
16pub enum WifiSecurity {
17 Open,
18 Wep,
19 Wpa,
20 #[default]
21 Wpa2,
22 Wpa3,
23 Enterprise,
24 Unknown,
25}
26
27#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
28pub struct WifiNetwork {
29 pub ssid: String,
30 pub bssid: Option<String>,
31 pub rssi: Option<i16>,
32 pub frequency_mhz: Option<u32>,
33 pub security: WifiSecurity,
34 pub connected: bool,
35}
36
37#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
38pub struct WifiAvailability {
39 pub permission: WifiPermission,
40 pub enabled: bool,
41 pub connected_network: Option<WifiNetwork>,
42}
43
44#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
45pub struct WifiPermissionRequest {
46 pub reason: Option<String>,
47}
48
49#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
50pub struct WifiScanRequest {
51 pub ssid_prefix: Option<String>,
52 pub include_hidden: bool,
53 pub timeout_ms: Option<u64>,
54}
55
56#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
57pub struct WifiScanResult {
58 pub networks: Vec<WifiNetwork>,
59}
60
61#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
62pub struct WifiConnectRequest {
63 pub ssid: String,
64 pub passphrase: Option<String>,
65 pub security: WifiSecurity,
66 pub hidden: bool,
67}
68
69#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
70pub struct WifiConnection {
71 pub network: WifiNetwork,
72}
73
74#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
75pub struct WifiDisconnectRequest {
76 pub ssid: Option<String>,
77}
78
79#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
80pub struct WifiError {
81 pub code: String,
82 pub message: String,
83}
84
85impl WifiError {
86 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
93 Self {
94 code: code.into(),
95 message: message.into(),
96 }
97 }
98
99 pub fn unsupported(operation: impl Into<String>) -> Self {
105 Self::new(
106 "unsupported",
107 format!(
108 "Wi-Fi operation `{}` is not supported by this host",
109 operation.into()
110 ),
111 )
112 }
113}
114
115pub struct GetWifiAvailabilityCapability;
116impl OperationCapability for GetWifiAvailabilityCapability {
117 type Request = ();
118 type Ok = WifiAvailability;
119 type Err = WifiError;
120}
121
122pub struct RequestWifiPermissionCapability;
123impl OperationCapability for RequestWifiPermissionCapability {
124 type Request = WifiPermissionRequest;
125 type Ok = WifiPermission;
126 type Err = WifiError;
127}
128
129pub struct ScanWifiNetworksCapability;
130impl OperationCapability for ScanWifiNetworksCapability {
131 type Request = WifiScanRequest;
132 type Ok = WifiScanResult;
133 type Err = WifiError;
134}
135
136pub struct ConnectWifiNetworkCapability;
137impl OperationCapability for ConnectWifiNetworkCapability {
138 type Request = WifiConnectRequest;
139 type Ok = WifiConnection;
140 type Err = WifiError;
141}
142
143pub struct DisconnectWifiNetworkCapability;
144impl OperationCapability for DisconnectWifiNetworkCapability {
145 type Request = WifiDisconnectRequest;
146 type Ok = ();
147 type Err = WifiError;
148}
149
150pub const GET_WIFI_AVAILABILITY: CapabilityType<GetWifiAvailabilityCapability> =
151 CapabilityType::new("fission.wifi.get_availability");
152pub const REQUEST_WIFI_PERMISSION: CapabilityType<RequestWifiPermissionCapability> =
153 CapabilityType::new("fission.wifi.request_permission");
154pub const SCAN_WIFI_NETWORKS: CapabilityType<ScanWifiNetworksCapability> =
155 CapabilityType::new("fission.wifi.scan_networks");
156pub const CONNECT_WIFI_NETWORK: CapabilityType<ConnectWifiNetworkCapability> =
157 CapabilityType::new("fission.wifi.connect_network");
158pub const DISCONNECT_WIFI_NETWORK: CapabilityType<DisconnectWifiNetworkCapability> =
159 CapabilityType::new("fission.wifi.disconnect_network");
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn wifi_scan_result_round_trips() {
167 let result = WifiScanResult {
168 networks: vec![WifiNetwork {
169 ssid: "Fission".into(),
170 bssid: Some("00:11:22:33:44:55".into()),
171 rssi: Some(-50),
172 frequency_mhz: Some(5_200),
173 security: WifiSecurity::Wpa3,
174 connected: false,
175 }],
176 };
177
178 let bytes = serde_json::to_vec(&result).unwrap();
179 let decoded: WifiScanResult = serde_json::from_slice(&bytes).unwrap();
180
181 assert_eq!(decoded, result);
182 }
183}