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