bluetooth/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5pub mod adapter;
6pub mod bluetooth;
7#[cfg(not(any(
8    all(target_os = "linux", feature = "native-bluetooth"),
9    all(target_os = "android", feature = "native-bluetooth"),
10    all(target_os = "macos", feature = "native-bluetooth")
11)))]
12mod empty;
13mod macros;
14pub mod test;
15
16use std::borrow::ToOwned;
17use std::collections::{HashMap, HashSet};
18use std::string::String;
19use std::thread;
20use std::time::Duration;
21
22use base::generic_channel::{self, GenericReceiver, GenericSender};
23use base::id::WebViewId;
24use bitflags::bitflags;
25use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
26use bluetooth_traits::scanfilter::{
27    BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions,
28};
29use bluetooth_traits::{
30    BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothDeviceMsg, BluetoothError,
31    BluetoothRequest, BluetoothResponse, BluetoothResponseResult, BluetoothResult,
32    BluetoothServiceMsg, GATTType,
33};
34use embedder_traits::{EmbedderMsg, EmbedderProxy};
35use log::warn;
36use rand::{self, Rng};
37use servo_config::pref;
38
39use crate::bluetooth::{
40    BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
41    BluetoothGATTService,
42};
43
44// A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed.
45// https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480)
46const MAXIMUM_TRANSACTION_TIME: u8 = 30;
47const CONNECTION_TIMEOUT_MS: u64 = 1000;
48// The discovery session needs some time to find any nearby devices
49const DISCOVERY_TIMEOUT_MS: u64 = 1500;
50
51bitflags! {
52    struct Flags: u32 {
53        const BROADCAST                   = 0b000000001;
54        const READ                        = 0b000000010;
55        const WRITE_WITHOUT_RESPONSE      = 0b000000100;
56        const WRITE                       = 0b000001000;
57        const NOTIFY                      = 0b000010000;
58        const INDICATE                    = 0b000100000;
59        const AUTHENTICATED_SIGNED_WRITES = 0b001000000;
60        const RELIABLE_WRITE              = 0b010000000;
61        const WRITABLE_AUXILIARIES        = 0b100000000;
62    }
63}
64
65macro_rules! return_if_cached(
66    ($cache:expr, $key:expr) => (
67        if $cache.contains_key($key) {
68            return $cache.get($key);
69        }
70    );
71);
72
73pub trait BluetoothThreadFactory {
74    fn new(embedder_proxy: EmbedderProxy) -> Self;
75}
76
77impl BluetoothThreadFactory for GenericSender<BluetoothRequest> {
78    fn new(embedder_proxy: EmbedderProxy) -> GenericSender<BluetoothRequest> {
79        let (sender, receiver) = generic_channel::channel().unwrap();
80        let adapter = if pref!(dom_bluetooth_enabled) {
81            BluetoothAdapter::new()
82        } else {
83            BluetoothAdapter::new_mock()
84        }
85        .ok();
86        thread::Builder::new()
87            .name("Bluetooth".to_owned())
88            .spawn(move || {
89                BluetoothManager::new(receiver, adapter, embedder_proxy).start();
90            })
91            .expect("Thread spawning failed");
92        sender
93    }
94}
95
96/// <https://webbluetoothcg.github.io/web-bluetooth/#matches-a-filter>
97fn matches_filter(device: &BluetoothDevice, filter: &BluetoothScanfilter) -> bool {
98    if filter.is_empty_or_invalid() {
99        return false;
100    }
101
102    // Step 1.
103    if let Some(name) = filter.get_name() {
104        if device.get_name().ok() != Some(name.to_string()) {
105            return false;
106        }
107    }
108
109    // Step 2.
110    if !filter.get_name_prefix().is_empty() {
111        if let Ok(device_name) = device.get_name() {
112            if !device_name.starts_with(filter.get_name_prefix()) {
113                return false;
114            }
115        } else {
116            return false;
117        }
118    }
119
120    // Step 3.
121    if !filter.get_services().is_empty() {
122        if let Ok(device_uuids) = device.get_uuids() {
123            for service in filter.get_services() {
124                if !device_uuids.iter().any(|x| x == service) {
125                    return false;
126                }
127            }
128        }
129    }
130
131    // Step 4.
132    if let Some(manufacturer_data) = filter.get_manufacturer_data() {
133        let advertised_manufacturer_data = match device.get_manufacturer_data() {
134            Ok(data) => data,
135            Err(_) => return false,
136        };
137        for (id, (prefix, mask)) in manufacturer_data.iter() {
138            if let Some(advertised_data) = advertised_manufacturer_data.get(id) {
139                if !data_filter_matches(advertised_data, prefix, mask) {
140                    return false;
141                }
142            } else {
143                return false;
144            }
145        }
146    }
147
148    // Step 5.
149    if let Some(service_data) = filter.get_service_data() {
150        let advertised_service_data = match device.get_service_data() {
151            Ok(data) => data,
152            Err(_) => return false,
153        };
154        for (uuid, (prefix, mask)) in service_data.iter() {
155            if let Some(advertised_data) = advertised_service_data.get(uuid.as_str()) {
156                if !data_filter_matches(advertised_data, prefix, mask) {
157                    return false;
158                }
159            } else {
160                return false;
161            }
162        }
163    }
164
165    // Step 6.
166    true
167}
168
169/// <https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdatafilterinit-matches>
170fn data_filter_matches(data: &[u8], prefix: &[u8], mask: &[u8]) -> bool {
171    // Step 1-2: No need to copy the bytes here.
172    // Step 3.
173    if data.len() < prefix.len() {
174        return false;
175    }
176
177    // Step 4.
178    for ((data, mask), prefix) in data.iter().zip(mask.iter()).zip(prefix.iter()) {
179        if data & mask != prefix & mask {
180            return false;
181        }
182    }
183
184    // Step 5.
185    true
186}
187
188fn matches_filters(device: &BluetoothDevice, filters: &BluetoothScanfilterSequence) -> bool {
189    if filters.has_empty_or_invalid_filter() {
190        return false;
191    }
192
193    filters.iter().any(|f| matches_filter(device, f))
194}
195
196fn is_mock_adapter(adapter: &BluetoothAdapter) -> bool {
197    matches!(adapter, &BluetoothAdapter::Mock(_))
198}
199
200pub struct BluetoothManager {
201    receiver: GenericReceiver<BluetoothRequest>,
202    adapter: Option<BluetoothAdapter>,
203    address_to_id: HashMap<String, String>,
204    service_to_device: HashMap<String, String>,
205    characteristic_to_service: HashMap<String, String>,
206    descriptor_to_characteristic: HashMap<String, String>,
207    cached_devices: HashMap<String, BluetoothDevice>,
208    cached_services: HashMap<String, BluetoothGATTService>,
209    cached_characteristics: HashMap<String, BluetoothGATTCharacteristic>,
210    cached_descriptors: HashMap<String, BluetoothGATTDescriptor>,
211    allowed_services: HashMap<String, HashSet<String>>,
212    embedder_proxy: EmbedderProxy,
213}
214
215impl BluetoothManager {
216    pub fn new(
217        receiver: GenericReceiver<BluetoothRequest>,
218        adapter: Option<BluetoothAdapter>,
219        embedder_proxy: EmbedderProxy,
220    ) -> BluetoothManager {
221        BluetoothManager {
222            receiver,
223            adapter,
224            address_to_id: HashMap::new(),
225            service_to_device: HashMap::new(),
226            characteristic_to_service: HashMap::new(),
227            descriptor_to_characteristic: HashMap::new(),
228            cached_devices: HashMap::new(),
229            cached_services: HashMap::new(),
230            cached_characteristics: HashMap::new(),
231            cached_descriptors: HashMap::new(),
232            allowed_services: HashMap::new(),
233            embedder_proxy,
234        }
235    }
236
237    fn start(&mut self) {
238        while let Ok(msg) = self.receiver.recv() {
239            match msg {
240                BluetoothRequest::RequestDevice(options, sender) => {
241                    let _ = sender.send(self.request_device(options));
242                },
243                BluetoothRequest::GATTServerConnect(device_id, sender) => {
244                    let _ = sender.send(self.gatt_server_connect(device_id));
245                },
246                BluetoothRequest::GATTServerDisconnect(device_id, sender) => {
247                    let _ = sender.send(self.gatt_server_disconnect(device_id));
248                },
249                BluetoothRequest::GetGATTChildren(id, uuid, single, child_type, sender) => {
250                    let _ = sender.send(self.get_gatt_children(id, uuid, single, child_type));
251                },
252                BluetoothRequest::ReadValue(id, sender) => {
253                    let _ = sender.send(self.read_value(id));
254                },
255                BluetoothRequest::WriteValue(id, value, sender) => {
256                    let _ = sender.send(self.write_value(id, value));
257                },
258                BluetoothRequest::EnableNotification(id, enable, sender) => {
259                    let _ = sender.send(self.enable_notification(id, enable));
260                },
261                BluetoothRequest::WatchAdvertisements(id, sender) => {
262                    let _ = sender.send(self.watch_advertisements(id));
263                },
264                BluetoothRequest::Test(data_set_name, sender) => {
265                    let _ = sender.send(self.test(data_set_name));
266                },
267                BluetoothRequest::SetRepresentedToNull(
268                    service_ids,
269                    characteristic_ids,
270                    descriptor_ids,
271                ) => self.remove_ids_from_caches(service_ids, characteristic_ids, descriptor_ids),
272                BluetoothRequest::IsRepresentedDeviceNull(id, sender) => {
273                    let _ = sender.send(!self.device_is_cached(&id));
274                },
275                BluetoothRequest::GetAvailability(sender) => {
276                    let _ = sender.send(self.get_availability());
277                },
278                BluetoothRequest::MatchesFilter(id, filters, sender) => {
279                    let _ = sender.send(self.device_matches_filter(&id, &filters));
280                },
281                BluetoothRequest::Exit => break,
282            }
283        }
284    }
285
286    // Test
287
288    fn test(&mut self, data_set_name: String) -> BluetoothResult<()> {
289        self.address_to_id.clear();
290        self.service_to_device.clear();
291        self.characteristic_to_service.clear();
292        self.descriptor_to_characteristic.clear();
293        self.cached_devices.clear();
294        self.cached_services.clear();
295        self.cached_characteristics.clear();
296        self.cached_descriptors.clear();
297        self.allowed_services.clear();
298        self.adapter = BluetoothAdapter::new_mock().ok();
299        match test::test(self, data_set_name) {
300            Ok(_) => Ok(()),
301            Err(error) => Err(BluetoothError::Type(error.to_string())),
302        }
303    }
304
305    fn remove_ids_from_caches(
306        &mut self,
307        service_ids: Vec<String>,
308        characteristic_ids: Vec<String>,
309        descriptor_ids: Vec<String>,
310    ) {
311        for id in service_ids {
312            self.cached_services.remove(&id);
313            self.service_to_device.remove(&id);
314        }
315
316        for id in characteristic_ids {
317            self.cached_characteristics.remove(&id);
318            self.characteristic_to_service.remove(&id);
319        }
320
321        for id in descriptor_ids {
322            self.cached_descriptors.remove(&id);
323            self.descriptor_to_characteristic.remove(&id);
324        }
325    }
326
327    // Adapter
328
329    pub fn get_or_create_adapter(&mut self) -> Option<BluetoothAdapter> {
330        let adapter_valid = self
331            .adapter
332            .as_ref()
333            .is_some_and(|a| a.get_address().is_ok());
334        if !adapter_valid {
335            self.adapter = BluetoothAdapter::new().ok();
336        }
337
338        let adapter = self.adapter.as_ref()?;
339
340        if is_mock_adapter(adapter) && !adapter.is_present().unwrap_or(false) {
341            return None;
342        }
343
344        self.adapter.clone()
345    }
346
347    fn get_adapter(&mut self) -> BluetoothResult<BluetoothAdapter> {
348        match self.get_or_create_adapter() {
349            Some(adapter) => {
350                if !adapter.is_powered().unwrap_or(false) {
351                    return Err(BluetoothError::NotFound);
352                }
353                Ok(adapter)
354            },
355            None => Err(BluetoothError::NotFound),
356        }
357    }
358
359    // Device
360
361    fn get_and_cache_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec<BluetoothDevice> {
362        let devices = adapter.get_devices().unwrap_or_default();
363        for device in &devices {
364            if let Ok(address) = device.get_address() {
365                #[allow(clippy::map_entry)] // False positive, the fix creates a borrowing error
366                if !self.address_to_id.contains_key(&address) {
367                    let generated_id = self.generate_device_id();
368                    self.address_to_id.insert(address, generated_id.clone());
369                    self.cached_devices
370                        .insert(generated_id.clone(), device.clone());
371                    self.allowed_services.insert(generated_id, HashSet::new());
372                }
373            }
374        }
375        self.cached_devices.values().cloned().collect()
376    }
377
378    fn get_device(
379        &mut self,
380        adapter: &mut BluetoothAdapter,
381        device_id: &str,
382    ) -> Option<&BluetoothDevice> {
383        return_if_cached!(self.cached_devices, device_id);
384        self.get_and_cache_devices(adapter);
385        return_if_cached!(self.cached_devices, device_id);
386        None
387    }
388
389    fn select_device(
390        &mut self,
391        webview_id: WebViewId,
392        devices: Vec<BluetoothDevice>,
393        adapter: &BluetoothAdapter,
394    ) -> Option<String> {
395        if is_mock_adapter(adapter) {
396            for device in &devices {
397                if let Ok(address) = device.get_address() {
398                    return Some(address);
399                }
400            }
401            return None;
402        }
403
404        let mut dialog_rows: Vec<String> = vec![];
405        for device in devices {
406            dialog_rows.extend_from_slice(&[
407                device.get_address().unwrap_or("".to_string()),
408                device.get_name().unwrap_or("".to_string()),
409            ]);
410        }
411
412        let (ipc_sender, ipc_receiver) =
413            generic_channel::channel().expect("Failed to create IPC channel!");
414        self.embedder_proxy
415            .send(EmbedderMsg::GetSelectedBluetoothDevice(
416                webview_id,
417                dialog_rows,
418                ipc_sender,
419            ));
420
421        match ipc_receiver.recv() {
422            Ok(result) => result,
423            Err(e) => {
424                warn!("Failed to receive files from embedder ({:?}).", e);
425                None
426            },
427        }
428    }
429
430    fn generate_device_id(&mut self) -> String {
431        let mut device_id;
432        let mut rng = rand::rng();
433        loop {
434            device_id = rng.random::<u32>().to_string();
435            if !self.cached_devices.contains_key(&device_id) {
436                break;
437            }
438        }
439        device_id
440    }
441
442    fn device_from_service_id(&self, service_id: &str) -> Option<BluetoothDevice> {
443        let device_id = self.service_to_device.get(service_id)?;
444        self.cached_devices.get(device_id).cloned()
445    }
446
447    fn device_is_cached(&self, device_id: &str) -> bool {
448        self.cached_devices.contains_key(device_id) &&
449            self.address_to_id.values().any(|v| v == device_id)
450    }
451
452    fn device_matches_filter(
453        &mut self,
454        device_id: &str,
455        filters: &BluetoothScanfilterSequence,
456    ) -> BluetoothResult<bool> {
457        let mut adapter = self.get_adapter()?;
458        match self.get_device(&mut adapter, device_id) {
459            Some(device) => Ok(matches_filters(device, filters)),
460            None => Ok(false),
461        }
462    }
463
464    // Service
465
466    fn get_and_cache_gatt_services(
467        &mut self,
468        adapter: &mut BluetoothAdapter,
469        device_id: &str,
470    ) -> Vec<BluetoothGATTService> {
471        let mut services = match self.get_device(adapter, device_id) {
472            Some(d) => d.get_gatt_services().unwrap_or_default(),
473            None => vec![],
474        };
475
476        services.retain(|s| {
477            !uuid_is_blocklisted(&s.get_uuid().unwrap_or_default(), Blocklist::All) &&
478                self.allowed_services
479                    .get(device_id)
480                    .is_some_and(|uuids| uuids.contains(&s.get_uuid().unwrap_or_default()))
481        });
482        for service in &services {
483            self.cached_services
484                .insert(service.get_id(), service.clone());
485            self.service_to_device
486                .insert(service.get_id(), device_id.to_owned());
487        }
488        services
489    }
490
491    fn get_gatt_service(
492        &mut self,
493        adapter: &mut BluetoothAdapter,
494        service_id: &str,
495    ) -> Option<&BluetoothGATTService> {
496        return_if_cached!(self.cached_services, service_id);
497        let device_id = self.service_to_device.get(service_id)?.clone();
498        self.get_and_cache_gatt_services(adapter, &device_id);
499        return_if_cached!(self.cached_services, service_id);
500        None
501    }
502
503    fn service_is_cached(&self, service_id: &str) -> bool {
504        self.cached_services.contains_key(service_id) &&
505            self.service_to_device.contains_key(service_id)
506    }
507
508    // Characteristic
509
510    fn get_and_cache_gatt_characteristics(
511        &mut self,
512        adapter: &mut BluetoothAdapter,
513        service_id: &str,
514    ) -> Vec<BluetoothGATTCharacteristic> {
515        let mut characteristics = match self.get_gatt_service(adapter, service_id) {
516            Some(s) => s.get_gatt_characteristics().unwrap_or_default(),
517            None => vec![],
518        };
519
520        characteristics
521            .retain(|c| !uuid_is_blocklisted(&c.get_uuid().unwrap_or_default(), Blocklist::All));
522        for characteristic in &characteristics {
523            self.cached_characteristics
524                .insert(characteristic.get_id(), characteristic.clone());
525            self.characteristic_to_service
526                .insert(characteristic.get_id(), service_id.to_owned());
527        }
528        characteristics
529    }
530
531    fn get_gatt_characteristic(
532        &mut self,
533        adapter: &mut BluetoothAdapter,
534        characteristic_id: &str,
535    ) -> Option<&BluetoothGATTCharacteristic> {
536        return_if_cached!(self.cached_characteristics, characteristic_id);
537        let service_id = self
538            .characteristic_to_service
539            .get(characteristic_id)?
540            .clone();
541        self.get_and_cache_gatt_characteristics(adapter, &service_id);
542        return_if_cached!(self.cached_characteristics, characteristic_id);
543        None
544    }
545
546    fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> Flags {
547        let mut props: Flags = Flags::empty();
548        let flags = characteristic.get_flags().unwrap_or_default();
549        for flag in flags {
550            match flag.as_ref() {
551                "broadcast" => props.insert(Flags::BROADCAST),
552                "read" => props.insert(Flags::READ),
553                "write-without-response" => props.insert(Flags::WRITE_WITHOUT_RESPONSE),
554                "write" => props.insert(Flags::WRITE),
555                "notify" => props.insert(Flags::NOTIFY),
556                "indicate" => props.insert(Flags::INDICATE),
557                "authenticated-signed-writes" => props.insert(Flags::AUTHENTICATED_SIGNED_WRITES),
558                "reliable-write" => props.insert(Flags::RELIABLE_WRITE),
559                "writable-auxiliaries" => props.insert(Flags::WRITABLE_AUXILIARIES),
560                _ => (),
561            }
562        }
563        props
564    }
565
566    fn characteristic_is_cached(&self, characteristic_id: &str) -> bool {
567        self.cached_characteristics.contains_key(characteristic_id) &&
568            self.characteristic_to_service
569                .contains_key(characteristic_id)
570    }
571
572    // Descriptor
573
574    fn get_and_cache_gatt_descriptors(
575        &mut self,
576        adapter: &mut BluetoothAdapter,
577        characteristic_id: &str,
578    ) -> Vec<BluetoothGATTDescriptor> {
579        let mut descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) {
580            Some(c) => c.get_gatt_descriptors().unwrap_or_default(),
581            None => vec![],
582        };
583
584        descriptors
585            .retain(|d| !uuid_is_blocklisted(&d.get_uuid().unwrap_or_default(), Blocklist::All));
586        for descriptor in &descriptors {
587            self.cached_descriptors
588                .insert(descriptor.get_id(), descriptor.clone());
589            self.descriptor_to_characteristic
590                .insert(descriptor.get_id(), characteristic_id.to_owned());
591        }
592        descriptors
593    }
594
595    fn get_gatt_descriptor(
596        &mut self,
597        adapter: &mut BluetoothAdapter,
598        descriptor_id: &str,
599    ) -> Option<&BluetoothGATTDescriptor> {
600        return_if_cached!(self.cached_descriptors, descriptor_id);
601        let characteristic_id = self
602            .descriptor_to_characteristic
603            .get(descriptor_id)?
604            .clone();
605        self.get_and_cache_gatt_descriptors(adapter, &characteristic_id);
606        return_if_cached!(self.cached_descriptors, descriptor_id);
607        None
608    }
609
610    // Methods
611
612    /// <https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices>
613    fn request_device(&mut self, options: RequestDeviceoptions) -> BluetoothResponseResult {
614        // Step 6.
615        let mut adapter = self.get_adapter()?;
616
617        // Step 7.
618        // Note: There are no requiredServiceUUIDS, we scan for all devices.
619        if let Ok(ref session) = adapter.create_discovery_session() {
620            if session.start_discovery().is_ok() && !is_mock_adapter(&adapter) {
621                thread::sleep(Duration::from_millis(DISCOVERY_TIMEOUT_MS));
622            }
623
624            let _ = session.stop_discovery();
625        }
626
627        let mut matched_devices = self.get_and_cache_devices(&mut adapter);
628
629        // Step 8.
630        if !options.is_accepting_all_devices() {
631            matched_devices.retain(|d| matches_filters(d, options.get_filters()));
632        }
633
634        // Step 9.
635        if let Some(address) = self.select_device(options.webview_id(), matched_devices, &adapter) {
636            let device_id = match self.address_to_id.get(&address) {
637                Some(id) => id.clone(),
638                None => return Err(BluetoothError::NotFound),
639            };
640            let mut services = options.get_services_set();
641            if let Some(services_set) = self.allowed_services.get(&device_id) {
642                services = services_set | &services;
643            }
644            self.allowed_services.insert(device_id.clone(), services);
645            if let Some(device) = self.get_device(&mut adapter, &device_id) {
646                let message = BluetoothDeviceMsg {
647                    id: device_id,
648                    name: device.get_name().ok(),
649                };
650                return Ok(BluetoothResponse::RequestDevice(message));
651            }
652        }
653        // Step 10.
654        Err(BluetoothError::NotFound)
655        // Step 12: Missing, because it is optional.
656    }
657
658    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect>
659    fn gatt_server_connect(&mut self, device_id: String) -> BluetoothResponseResult {
660        // Step 2.
661        if !self.device_is_cached(&device_id) {
662            return Err(BluetoothError::Network);
663        }
664        let mut adapter = self.get_adapter()?;
665
666        // Step 5.1.1.
667        match self.get_device(&mut adapter, &device_id) {
668            Some(d) => {
669                if d.is_connected().unwrap_or(false) {
670                    return Ok(BluetoothResponse::GATTServerConnect(true));
671                }
672                let _ = d.connect();
673                for _ in 0..MAXIMUM_TRANSACTION_TIME {
674                    if d.is_connected().unwrap_or(false) {
675                        return Ok(BluetoothResponse::GATTServerConnect(true));
676                    } else {
677                        if is_mock_adapter(&adapter) {
678                            break;
679                        }
680                        thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS));
681                    }
682                    // TODO: Step 5.1.4: Use the exchange MTU procedure.
683                }
684                // Step 5.1.3.
685                Err(BluetoothError::Network)
686            },
687            None => Err(BluetoothError::NotFound),
688        }
689    }
690
691    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect>
692    fn gatt_server_disconnect(&mut self, device_id: String) -> BluetoothResult<()> {
693        let mut adapter = self.get_adapter()?;
694        match self.get_device(&mut adapter, &device_id) {
695            Some(d) => {
696                // Step 2.
697                if !d.is_connected().unwrap_or(true) {
698                    return Ok(());
699                }
700                let _ = d.disconnect();
701                for _ in 0..MAXIMUM_TRANSACTION_TIME {
702                    if d.is_connected().unwrap_or(true) {
703                        thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS))
704                    } else {
705                        return Ok(());
706                    }
707                }
708                Err(BluetoothError::Network)
709            },
710            None => Err(BluetoothError::NotFound),
711        }
712    }
713
714    /// <https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren>
715    fn get_gatt_children(
716        &mut self,
717        id: String,
718        uuid: Option<String>,
719        single: bool,
720        child_type: GATTType,
721    ) -> BluetoothResponseResult {
722        let mut adapter = self.get_adapter()?;
723        match child_type {
724            GATTType::PrimaryService => {
725                // Step 5.
726                if !self.device_is_cached(&id) {
727                    return Err(BluetoothError::InvalidState);
728                }
729                // Step 6.
730                if let Some(ref uuid) = uuid {
731                    if !self
732                        .allowed_services
733                        .get(&id)
734                        .is_some_and(|s| s.contains(uuid))
735                    {
736                        return Err(BluetoothError::Security);
737                    }
738                }
739                let mut services = self.get_and_cache_gatt_services(&mut adapter, &id);
740                if let Some(uuid) = uuid {
741                    services.retain(|e| e.get_uuid().unwrap_or_default() == uuid);
742                }
743                let mut services_vec = vec![];
744                for service in services {
745                    if service.is_primary().unwrap_or(false) {
746                        if let Ok(uuid) = service.get_uuid() {
747                            services_vec.push(BluetoothServiceMsg {
748                                uuid,
749                                is_primary: true,
750                                instance_id: service.get_id(),
751                            });
752                        }
753                    }
754                }
755                // Step 7.
756                if services_vec.is_empty() {
757                    return Err(BluetoothError::NotFound);
758                }
759
760                Ok(BluetoothResponse::GetPrimaryServices(services_vec, single))
761            },
762            GATTType::Characteristic => {
763                // Step 5.
764                if !self.service_is_cached(&id) {
765                    return Err(BluetoothError::InvalidState);
766                }
767                // Step 6.
768                let mut characteristics =
769                    self.get_and_cache_gatt_characteristics(&mut adapter, &id);
770                if let Some(uuid) = uuid {
771                    characteristics.retain(|e| e.get_uuid().unwrap_or_default() == uuid);
772                }
773                let mut characteristics_vec = vec![];
774                for characteristic in characteristics {
775                    if let Ok(uuid) = characteristic.get_uuid() {
776                        let properties = self.get_characteristic_properties(&characteristic);
777                        characteristics_vec.push(BluetoothCharacteristicMsg {
778                            uuid,
779                            instance_id: characteristic.get_id(),
780                            broadcast: properties.contains(Flags::BROADCAST),
781                            read: properties.contains(Flags::READ),
782                            write_without_response: properties
783                                .contains(Flags::WRITE_WITHOUT_RESPONSE),
784                            write: properties.contains(Flags::WRITE),
785                            notify: properties.contains(Flags::NOTIFY),
786                            indicate: properties.contains(Flags::INDICATE),
787                            authenticated_signed_writes: properties
788                                .contains(Flags::AUTHENTICATED_SIGNED_WRITES),
789                            reliable_write: properties.contains(Flags::RELIABLE_WRITE),
790                            writable_auxiliaries: properties.contains(Flags::WRITABLE_AUXILIARIES),
791                        });
792                    }
793                }
794
795                // Step 7.
796                if characteristics_vec.is_empty() {
797                    return Err(BluetoothError::NotFound);
798                }
799
800                Ok(BluetoothResponse::GetCharacteristics(
801                    characteristics_vec,
802                    single,
803                ))
804            },
805            GATTType::IncludedService => {
806                // Step 5.
807                if !self.service_is_cached(&id) {
808                    return Err(BluetoothError::InvalidState);
809                }
810                // Step 6.
811                let device = match self.device_from_service_id(&id) {
812                    Some(device) => device,
813                    None => return Err(BluetoothError::NotFound),
814                };
815                let primary_service = match self.get_gatt_service(&mut adapter, &id) {
816                    Some(s) => s,
817                    None => return Err(BluetoothError::NotFound),
818                };
819                let services = primary_service.get_includes(device).unwrap_or(vec![]);
820                let mut services_vec = vec![];
821                for service in services {
822                    if let Ok(service_uuid) = service.get_uuid() {
823                        services_vec.push(BluetoothServiceMsg {
824                            uuid: service_uuid,
825                            is_primary: service.is_primary().unwrap_or(false),
826                            instance_id: service.get_id(),
827                        });
828                    }
829                }
830                if let Some(uuid) = uuid {
831                    services_vec.retain(|s| s.uuid == uuid);
832                }
833                services_vec.retain(|s| !uuid_is_blocklisted(&s.uuid, Blocklist::All));
834
835                // Step 7.
836                if services_vec.is_empty() {
837                    return Err(BluetoothError::NotFound);
838                }
839
840                Ok(BluetoothResponse::GetIncludedServices(services_vec, single))
841            },
842            GATTType::Descriptor => {
843                // Step 5.
844                if !self.characteristic_is_cached(&id) {
845                    return Err(BluetoothError::InvalidState);
846                }
847                // Step 6.
848                let mut descriptors = self.get_and_cache_gatt_descriptors(&mut adapter, &id);
849                if let Some(uuid) = uuid {
850                    descriptors.retain(|e| e.get_uuid().unwrap_or_default() == uuid);
851                }
852                let mut descriptors_vec = vec![];
853                for descriptor in descriptors {
854                    if let Ok(uuid) = descriptor.get_uuid() {
855                        descriptors_vec.push(BluetoothDescriptorMsg {
856                            uuid,
857                            instance_id: descriptor.get_id(),
858                        });
859                    }
860                }
861
862                // Step 7.
863                if descriptors_vec.is_empty() {
864                    return Err(BluetoothError::NotFound);
865                }
866                Ok(BluetoothResponse::GetDescriptors(descriptors_vec, single))
867            },
868        }
869    }
870
871    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue>
872    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue>
873    fn read_value(&mut self, id: String) -> BluetoothResponseResult {
874        // (Characteristic) Step 5.2: Missing because it is optional.
875        // (Descriptor)     Step 5.1: Missing because it is optional.
876        let mut adapter = self.get_adapter()?;
877
878        // (Characteristic) Step 5.3.
879        let mut value = self
880            .get_gatt_characteristic(&mut adapter, &id)
881            .map(|c| c.read_value().unwrap_or_default());
882
883        // (Characteristic) TODO: Step 5.4: Handle all the errors returned from the read_value call.
884
885        // (Descriptor) Step 5.2.
886        if value.is_none() {
887            value = self
888                .get_gatt_descriptor(&mut adapter, &id)
889                .map(|d| d.read_value().unwrap_or_default());
890        }
891
892        // (Descriptor) TODO: Step 5.3: Handle all the errors returned from the read_value call.
893
894        match value {
895            // (Characteristic) Step 5.5.4.
896            // (Descriptor)     Step 5.4.3.
897            Some(v) => Ok(BluetoothResponse::ReadValue(v)),
898
899            // (Characteristic) Step 4.
900            // (Descriptor)     Step 4.
901            None => Err(BluetoothError::InvalidState),
902        }
903    }
904
905    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue>
906    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue>
907    fn write_value(&mut self, id: String, value: Vec<u8>) -> BluetoothResponseResult {
908        // (Characteristic) Step 7.2: Missing because it is optional.
909        // (Descriptor)     Step 7.1: Missing because it is optional.
910        let mut adapter = self.get_adapter()?;
911
912        // (Characteristic) Step 7.3.
913        let mut result = self
914            .get_gatt_characteristic(&mut adapter, &id)
915            .map(|c| c.write_value(value.clone()));
916
917        // (Characteristic) TODO: Step 7.4: Handle all the errors returned from the write_value call.
918
919        // (Descriptor) Step 7.2.
920        if result.is_none() {
921            result = self
922                .get_gatt_descriptor(&mut adapter, &id)
923                .map(|d| d.write_value(value.clone()));
924        }
925
926        // (Descriptor) TODO: Step 7.3: Handle all the errors returned from the write_value call.
927
928        match result {
929            Some(v) => match v {
930                // (Characteristic) Step 7.5.3.
931                // (Descriptor) Step 7.4.3.
932                Ok(_) => Ok(BluetoothResponse::WriteValue(value)),
933
934                // (Characteristic) Step 7.1.
935                Err(_) => Err(BluetoothError::NotSupported),
936            },
937
938            // (Characteristic) Step 6.
939            // (Descriptor)     Step 6.
940            None => Err(BluetoothError::InvalidState),
941        }
942    }
943
944    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-startnotifications>
945    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-stopnotifications>
946    fn enable_notification(&mut self, id: String, enable: bool) -> BluetoothResponseResult {
947        // (StartNotifications) Step 3 - 4.
948        // (StopNotifications) Step 1 - 2.
949        if !self.characteristic_is_cached(&id) {
950            return Err(BluetoothError::InvalidState);
951        }
952
953        // (StartNotification) TODO: Step 7: Missing because it is optional.
954        let mut adapter = self.get_adapter()?;
955        match self.get_gatt_characteristic(&mut adapter, &id) {
956            Some(c) => {
957                let result = if enable {
958                    // (StartNotification) Step 8.
959                    // TODO: Handle all the errors returned from the start_notify call.
960                    c.start_notify()
961                } else {
962                    // (StopNotification) Step 4.
963                    c.stop_notify()
964                };
965                match result {
966                    // (StartNotification) Step 11.
967                    // (StopNotification)  Step 5.
968                    Ok(_) => Ok(BluetoothResponse::EnableNotification(())),
969
970                    // (StartNotification) Step 5.
971                    Err(_) => Err(BluetoothError::NotSupported),
972                }
973            },
974            // (StartNotification) Step 4.
975            None => Err(BluetoothError::InvalidState),
976        }
977    }
978
979    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements>
980    fn watch_advertisements(&mut self, _device_id: String) -> BluetoothResponseResult {
981        // Step 2.
982        // TODO: Implement this when supported in lower level
983        Err(BluetoothError::NotSupported)
984    }
985
986    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-getavailability>
987    fn get_availability(&mut self) -> BluetoothResponseResult {
988        Ok(BluetoothResponse::GetAvailability(
989            self.get_adapter().is_ok(),
990        ))
991    }
992}