script/dom/bluetooth/
bluetoothremotegattdescriptor.rs1use std::rc::Rc;
6
7use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
8use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
9use dom_struct::dom_struct;
10use ipc_channel::ipc::IpcSender;
11
12use crate::dom::bindings::cell::DomRefCell;
13use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods;
14use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
15use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
16use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
17use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
18use crate::dom::bindings::error::Error::{self, InvalidModification, Network, Security};
19use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
20use crate::dom::bindings::root::{Dom, DomRoot};
21use crate::dom::bindings::str::{ByteString, DOMString};
22use crate::dom::bluetooth::{AsyncBluetoothListener, response_async};
23use crate::dom::bluetoothremotegattcharacteristic::{
24 BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH,
25};
26use crate::dom::globalscope::GlobalScope;
27use crate::dom::promise::Promise;
28use crate::realms::InRealm;
29use crate::script_runtime::CanGc;
30
31#[dom_struct]
33pub(crate) struct BluetoothRemoteGATTDescriptor {
34 reflector_: Reflector,
35 characteristic: Dom<BluetoothRemoteGATTCharacteristic>,
36 uuid: DOMString,
37 value: DomRefCell<Option<ByteString>>,
38 instance_id: String,
39}
40
41impl BluetoothRemoteGATTDescriptor {
42 pub(crate) fn new_inherited(
43 characteristic: &BluetoothRemoteGATTCharacteristic,
44 uuid: DOMString,
45 instance_id: String,
46 ) -> BluetoothRemoteGATTDescriptor {
47 BluetoothRemoteGATTDescriptor {
48 reflector_: Reflector::new(),
49 characteristic: Dom::from_ref(characteristic),
50 uuid,
51 value: DomRefCell::new(None),
52 instance_id,
53 }
54 }
55
56 pub(crate) fn new(
57 global: &GlobalScope,
58 characteristic: &BluetoothRemoteGATTCharacteristic,
59 uuid: DOMString,
60 instance_id: String,
61 can_gc: CanGc,
62 ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
63 reflect_dom_object(
64 Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
65 characteristic,
66 uuid,
67 instance_id,
68 )),
69 global,
70 can_gc,
71 )
72 }
73
74 fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
75 self.global().as_window().bluetooth_thread()
76 }
77
78 fn get_instance_id(&self) -> String {
79 self.instance_id.clone()
80 }
81}
82
83impl BluetoothRemoteGATTDescriptorMethods<crate::DomTypeHolder> for BluetoothRemoteGATTDescriptor {
84 fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
86 DomRoot::from_ref(&self.characteristic)
87 }
88
89 fn Uuid(&self) -> DOMString {
91 self.uuid.clone()
92 }
93
94 fn GetValue(&self) -> Option<ByteString> {
96 self.value.borrow().clone()
97 }
98
99 fn ReadValue(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
101 let p = Promise::new_in_current_realm(comp, can_gc);
102
103 if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
105 p.reject_error(Security, can_gc);
106 return p;
107 }
108
109 if !self
111 .Characteristic()
112 .Service()
113 .Device()
114 .get_gatt()
115 .Connected()
116 {
117 p.reject_error(Network, can_gc);
118 return p;
119 }
120
121 let sender = response_async(&p, self);
125 self.get_bluetooth_thread()
126 .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
127 .unwrap();
128 p
129 }
130
131 fn WriteValue(
133 &self,
134 value: ArrayBufferViewOrArrayBuffer,
135 comp: InRealm,
136 can_gc: CanGc,
137 ) -> Rc<Promise> {
138 let p = Promise::new_in_current_realm(comp, can_gc);
139
140 if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
142 p.reject_error(Security, can_gc);
143 return p;
144 }
145
146 let vec = match value {
148 ArrayBufferViewOrArrayBuffer::ArrayBufferView(avb) => avb.to_vec(),
149 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ab) => ab.to_vec(),
150 };
151 if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH {
152 p.reject_error(InvalidModification, can_gc);
153 return p;
154 }
155
156 if !self
158 .Characteristic()
159 .Service()
160 .Device()
161 .get_gatt()
162 .Connected()
163 {
164 p.reject_error(Network, can_gc);
165 return p;
166 }
167
168 let sender = response_async(&p, self);
172 self.get_bluetooth_thread()
173 .send(BluetoothRequest::WriteValue(
174 self.get_instance_id(),
175 vec,
176 sender,
177 ))
178 .unwrap();
179 p
180 }
181}
182
183impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
184 fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, can_gc: CanGc) {
185 match response {
186 BluetoothResponse::ReadValue(result) => {
188 let value = ByteString::new(result);
193 *self.value.borrow_mut() = Some(value.clone());
194
195 promise.resolve_native(&value, can_gc);
197 },
198 BluetoothResponse::WriteValue(result) => {
200 *self.value.borrow_mut() = Some(ByteString::new(result));
205
206 promise.resolve_native(&(), can_gc);
209 },
210 _ => promise.reject_error(Error::Type("Something went wrong...".to_owned()), can_gc),
211 }
212 }
213}