| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ |
| |
| use std::collections::{HashMap, HashSet}; |
| use std::slice::Iter; |
| |
| use base::id::WebViewId; |
| use serde::{Deserialize, Serialize}; |
| |
| // A device name can never be longer than 29 bytes. An adv packet is at most |
| // 31 bytes long. The length and identifier of the length field take 2 bytes. |
| // That leaves 29 bytes for the name. |
| const MAX_NAME_LENGTH: usize = 29; |
| |
| #[derive(Debug, Deserialize, Serialize)] |
| pub struct ServiceUUIDSequence(Vec<String>); |
| |
| impl ServiceUUIDSequence { |
| pub fn new(vec: Vec<String>) -> ServiceUUIDSequence { |
| ServiceUUIDSequence(vec) |
| } |
| |
| fn get_services_set(&self) -> HashSet<String> { |
| self.0.iter().map(String::clone).collect() |
| } |
| } |
| |
| type ManufacturerData = HashMap<u16, (Vec<u8>, Vec<u8>)>; |
| type ServiceData = HashMap<String, (Vec<u8>, Vec<u8>)>; |
| |
| #[derive(Debug, Deserialize, Serialize)] |
| pub struct BluetoothScanfilter { |
| name: Option<String>, |
| name_prefix: String, |
| services: ServiceUUIDSequence, |
| manufacturer_data: Option<ManufacturerData>, |
| service_data: Option<ServiceData>, |
| } |
| |
| impl BluetoothScanfilter { |
| pub fn new( |
| name: Option<String>, |
| name_prefix: String, |
| services: Vec<String>, |
| manufacturer_data: Option<ManufacturerData>, |
| service_data: Option<ServiceData>, |
| ) -> BluetoothScanfilter { |
| BluetoothScanfilter { |
| name, |
| name_prefix, |
| services: ServiceUUIDSequence::new(services), |
| manufacturer_data, |
| service_data, |
| } |
| } |
| |
| pub fn get_name(&self) -> Option<&str> { |
| self.name.as_deref() |
| } |
| |
| pub fn get_name_prefix(&self) -> &str { |
| &self.name_prefix |
| } |
| |
| pub fn get_services(&self) -> &[String] { |
| &self.services.0 |
| } |
| |
| pub fn get_manufacturer_data(&self) -> Option<&ManufacturerData> { |
| self.manufacturer_data.as_ref() |
| } |
| |
| pub fn get_service_data(&self) -> Option<&ServiceData> { |
| self.service_data.as_ref() |
| } |
| |
| pub fn is_empty_or_invalid(&self) -> bool { |
| (self.name.is_none() && |
| self.name_prefix.is_empty() && |
| self.get_services().is_empty() && |
| self.manufacturer_data.is_none() && |
| self.service_data.is_none()) || |
| self.get_name().unwrap_or("").len() > MAX_NAME_LENGTH || |
| self.name_prefix.len() > MAX_NAME_LENGTH |
| } |
| } |
| |
| #[derive(Debug, Deserialize, Serialize)] |
| pub struct BluetoothScanfilterSequence(Vec<BluetoothScanfilter>); |
| |
| impl BluetoothScanfilterSequence { |
| pub fn new(vec: Vec<BluetoothScanfilter>) -> BluetoothScanfilterSequence { |
| BluetoothScanfilterSequence(vec) |
| } |
| |
| pub fn has_empty_or_invalid_filter(&self) -> bool { |
| self.0.iter().any(BluetoothScanfilter::is_empty_or_invalid) |
| } |
| |
| pub fn iter(&self) -> Iter<'_, BluetoothScanfilter> { |
| self.0.iter() |
| } |
| |
| fn get_services_set(&self) -> HashSet<String> { |
| self.iter() |
| .flat_map(|filter| filter.services.get_services_set()) |
| .collect() |
| } |
| |
| fn is_empty(&self) -> bool { |
| self.0.is_empty() |
| } |
| } |
| |
| #[derive(Debug, Deserialize, Serialize)] |
| pub struct RequestDeviceoptions { |
| webview_id: WebViewId, |
| filters: BluetoothScanfilterSequence, |
| optional_services: ServiceUUIDSequence, |
| } |
| |
| impl RequestDeviceoptions { |
| pub fn new( |
| webview_id: WebViewId, |
| filters: BluetoothScanfilterSequence, |
| services: ServiceUUIDSequence, |
| ) -> RequestDeviceoptions { |
| RequestDeviceoptions { |
| webview_id, |
| filters, |
| optional_services: services, |
| } |
| } |
| |
| pub fn webview_id(&self) -> WebViewId { |
| self.webview_id |
| } |
| |
| pub fn get_filters(&self) -> &BluetoothScanfilterSequence { |
| &self.filters |
| } |
| |
| pub fn get_services_set(&self) -> HashSet<String> { |
| &self.filters.get_services_set() | &self.optional_services.get_services_set() |
| } |
| |
| pub fn is_accepting_all_devices(&self) -> bool { |
| self.filters.is_empty() |
| } |
| } |