diff options
author | Josh Matthews <josh@joshmatthews.net> | 2025-02-17 23:13:43 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-18 04:13:43 +0000 |
commit | 1d606bb85cd34c6d37ae8d022b7cb32adadb9b08 (patch) | |
tree | 3c1c70468394f3cd722117f22d84cbcb069cebec /components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs | |
parent | 32f19c1eae3ead86987fa353f3f3e7e6fadb47eb (diff) | |
download | servo-1d606bb85cd34c6d37ae8d022b7cb32adadb9b08.tar.gz servo-1d606bb85cd34c6d37ae8d022b7cb32adadb9b08.zip |
Make WebBluetooth an optional feature. (#35479)
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs')
-rw-r--r-- | components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs new file mode 100644 index 00000000000..3d714884860 --- /dev/null +++ b/components/script/dom/bluetooth/bluetoothremotegattdescriptor.rs @@ -0,0 +1,212 @@ +/* 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::rc::Rc; + +use bluetooth_traits::blocklist::{uuid_is_blocklisted, Blocklist}; +use bluetooth_traits::{BluetoothRequest, BluetoothResponse}; +use dom_struct::dom_struct; +use ipc_channel::ipc::IpcSender; + +use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods; +use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods; +use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; +use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; +use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer; +use crate::dom::bindings::error::Error::{self, InvalidModification, Network, Security}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::{ByteString, DOMString}; +use crate::dom::bluetooth::{response_async, AsyncBluetoothListener}; +use crate::dom::bluetoothremotegattcharacteristic::{ + BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH, +}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::promise::Promise; +use crate::realms::InRealm; +use crate::script_runtime::CanGc; + +// http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor +#[dom_struct] +pub(crate) struct BluetoothRemoteGATTDescriptor { + reflector_: Reflector, + characteristic: Dom<BluetoothRemoteGATTCharacteristic>, + uuid: DOMString, + value: DomRefCell<Option<ByteString>>, + instance_id: String, +} + +impl BluetoothRemoteGATTDescriptor { + pub(crate) fn new_inherited( + characteristic: &BluetoothRemoteGATTCharacteristic, + uuid: DOMString, + instance_id: String, + ) -> BluetoothRemoteGATTDescriptor { + BluetoothRemoteGATTDescriptor { + reflector_: Reflector::new(), + characteristic: Dom::from_ref(characteristic), + uuid, + value: DomRefCell::new(None), + instance_id, + } + } + + pub(crate) fn new( + global: &GlobalScope, + characteristic: &BluetoothRemoteGATTCharacteristic, + uuid: DOMString, + instance_id: String, + ) -> DomRoot<BluetoothRemoteGATTDescriptor> { + reflect_dom_object( + Box::new(BluetoothRemoteGATTDescriptor::new_inherited( + characteristic, + uuid, + instance_id, + )), + global, + CanGc::note(), + ) + } + + fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { + self.global().as_window().bluetooth_thread() + } + + fn get_instance_id(&self) -> String { + self.instance_id.clone() + } +} + +impl BluetoothRemoteGATTDescriptorMethods<crate::DomTypeHolder> for BluetoothRemoteGATTDescriptor { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-characteristic + fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> { + DomRoot::from_ref(&self.characteristic) + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-uuid + fn Uuid(&self) -> DOMString { + self.uuid.clone() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value + fn GetValue(&self) -> Option<ByteString> { + self.value.borrow().clone() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue + fn ReadValue(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> { + let p = Promise::new_in_current_realm(comp, can_gc); + + // Step 1. + if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) { + p.reject_error(Security); + return p; + } + + // Step 2. + if !self + .Characteristic() + .Service() + .Device() + .get_gatt() + .Connected() + { + p.reject_error(Network); + return p; + } + + // TODO: Step 5: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer. + // Note: Steps 3 - 4 and substeps of Step 5 are implemented in components/bluetooth/lib.rs + // in readValue function and in handle_response function. + let sender = response_async(&p, self); + self.get_bluetooth_thread() + .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender)) + .unwrap(); + p + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue + fn WriteValue( + &self, + value: ArrayBufferViewOrArrayBuffer, + comp: InRealm, + can_gc: CanGc, + ) -> Rc<Promise> { + let p = Promise::new_in_current_realm(comp, can_gc); + + // Step 1. + if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) { + p.reject_error(Security); + return p; + } + + // Step 2 - 3. + let vec = match value { + ArrayBufferViewOrArrayBuffer::ArrayBufferView(avb) => avb.to_vec(), + ArrayBufferViewOrArrayBuffer::ArrayBuffer(ab) => ab.to_vec(), + }; + if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH { + p.reject_error(InvalidModification); + return p; + } + + // Step 4. + if !self + .Characteristic() + .Service() + .Device() + .get_gatt() + .Connected() + { + p.reject_error(Network); + return p; + } + + // TODO: Step 7: Implement the `connection-checking-wrapper` algorithm for BluetoothRemoteGATTServer. + // Note: Steps 5 - 6 and substeps of Step 7 are implemented in components/bluetooth/lib.rs + // in writeValue function and in handle_response function. + let sender = response_async(&p, self); + self.get_bluetooth_thread() + .send(BluetoothRequest::WriteValue( + self.get_instance_id(), + vec, + sender, + )) + .unwrap(); + p + } +} + +impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor { + fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, _can_gc: CanGc) { + match response { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue + BluetoothResponse::ReadValue(result) => { + // TODO: Step 5.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer. + + // Step 5.4.2. + // TODO(#5014): Replace ByteString with ArrayBuffer when it is implemented. + let value = ByteString::new(result); + *self.value.borrow_mut() = Some(value.clone()); + + // Step 5.4.3. + promise.resolve_native(&value); + }, + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue + BluetoothResponse::WriteValue(result) => { + // TODO: Step 7.4.1: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer. + + // Step 7.4.2. + // TODO(#5014): Replace ByteString with an ArrayBuffer wrapped in a DataView. + *self.value.borrow_mut() = Some(ByteString::new(result)); + + // Step 7.4.3. + // TODO: Resolve promise with undefined instead of a value. + promise.resolve_native(&()); + }, + _ => promise.reject_error(Error::Type("Something went wrong...".to_owned())), + } + } +} |