1use std::rc::Rc;
6
7use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
8use bluetooth_traits::{BluetoothRequest, BluetoothResponse, GATTType};
9use dom_struct::dom_struct;
10use ipc_channel::ipc::IpcSender;
11
12use crate::dom::bindings::cell::DomRefCell;
13use crate::dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::BluetoothCharacteristicPropertiesMethods;
14use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods;
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::{
19 self, InvalidModification, Network, NotSupported, Security,
20};
21use crate::dom::bindings::inheritance::Castable;
22use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
23use crate::dom::bindings::root::{Dom, DomRoot};
24use crate::dom::bindings::str::{ByteString, DOMString};
25use crate::dom::bluetooth::{AsyncBluetoothListener, get_gatt_children, response_async};
26use crate::dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
27use crate::dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
28use crate::dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID};
29use crate::dom::eventtarget::EventTarget;
30use crate::dom::globalscope::GlobalScope;
31use crate::dom::promise::Promise;
32use crate::realms::InRealm;
33use crate::script_runtime::CanGc;
34
35pub(crate) const MAXIMUM_ATTRIBUTE_LENGTH: usize = 512;
38
39#[dom_struct]
41pub(crate) struct BluetoothRemoteGATTCharacteristic {
42 eventtarget: EventTarget,
43 service: Dom<BluetoothRemoteGATTService>,
44 uuid: DOMString,
45 properties: Dom<BluetoothCharacteristicProperties>,
46 value: DomRefCell<Option<ByteString>>,
47 instance_id: String,
48}
49
50impl BluetoothRemoteGATTCharacteristic {
51 pub(crate) fn new_inherited(
52 service: &BluetoothRemoteGATTService,
53 uuid: DOMString,
54 properties: &BluetoothCharacteristicProperties,
55 instance_id: String,
56 ) -> BluetoothRemoteGATTCharacteristic {
57 BluetoothRemoteGATTCharacteristic {
58 eventtarget: EventTarget::new_inherited(),
59 service: Dom::from_ref(service),
60 uuid,
61 properties: Dom::from_ref(properties),
62 value: DomRefCell::new(None),
63 instance_id,
64 }
65 }
66
67 pub(crate) fn new(
68 global: &GlobalScope,
69 service: &BluetoothRemoteGATTService,
70 uuid: DOMString,
71 properties: &BluetoothCharacteristicProperties,
72 instance_id: String,
73 can_gc: CanGc,
74 ) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
75 reflect_dom_object(
76 Box::new(BluetoothRemoteGATTCharacteristic::new_inherited(
77 service,
78 uuid,
79 properties,
80 instance_id,
81 )),
82 global,
83 can_gc,
84 )
85 }
86
87 fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
88 self.global().as_window().bluetooth_thread()
89 }
90
91 fn get_instance_id(&self) -> String {
92 self.instance_id.clone()
93 }
94}
95
96impl BluetoothRemoteGATTCharacteristicMethods<crate::DomTypeHolder>
97 for BluetoothRemoteGATTCharacteristic
98{
99 fn Properties(&self) -> DomRoot<BluetoothCharacteristicProperties> {
101 DomRoot::from_ref(&self.properties)
102 }
103
104 fn Service(&self) -> DomRoot<BluetoothRemoteGATTService> {
106 DomRoot::from_ref(&self.service)
107 }
108
109 fn Uuid(&self) -> DOMString {
111 self.uuid.clone()
112 }
113
114 fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID, can_gc: CanGc) -> Rc<Promise> {
116 get_gatt_children(
117 self,
118 true,
119 BluetoothUUID::descriptor,
120 Some(descriptor),
121 self.get_instance_id(),
122 self.Service().Device().get_gatt().Connected(),
123 GATTType::Descriptor,
124 can_gc,
125 )
126 }
127
128 fn GetDescriptors(
130 &self,
131 descriptor: Option<BluetoothDescriptorUUID>,
132 can_gc: CanGc,
133 ) -> Rc<Promise> {
134 get_gatt_children(
135 self,
136 false,
137 BluetoothUUID::descriptor,
138 descriptor,
139 self.get_instance_id(),
140 self.Service().Device().get_gatt().Connected(),
141 GATTType::Descriptor,
142 can_gc,
143 )
144 }
145
146 fn GetValue(&self) -> Option<ByteString> {
148 self.value.borrow().clone()
149 }
150
151 fn ReadValue(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
153 let p = Promise::new_in_current_realm(comp, can_gc);
154
155 if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
157 p.reject_error(Security, can_gc);
158 return p;
159 }
160
161 if !self.Service().Device().get_gatt().Connected() {
163 p.reject_error(Network, can_gc);
164 return p;
165 }
166
167 if !self.Properties().Read() {
171 p.reject_error(NotSupported, can_gc);
172 return p;
173 }
174
175 let sender = response_async(&p, self);
178 self.get_bluetooth_thread()
179 .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
180 .unwrap();
181 p
182 }
183
184 fn WriteValue(
186 &self,
187 value: ArrayBufferViewOrArrayBuffer,
188 comp: InRealm,
189 can_gc: CanGc,
190 ) -> Rc<Promise> {
191 let p = Promise::new_in_current_realm(comp, can_gc);
192
193 if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Writes) {
195 p.reject_error(Security, can_gc);
196 return p;
197 }
198
199 let vec = match value {
201 ArrayBufferViewOrArrayBuffer::ArrayBufferView(avb) => avb.to_vec(),
202 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ab) => ab.to_vec(),
203 };
204
205 if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH {
206 p.reject_error(InvalidModification, can_gc);
207 return p;
208 }
209
210 if !self.Service().Device().get_gatt().Connected() {
212 p.reject_error(Network, can_gc);
213 return p;
214 }
215
216 if !(self.Properties().Write() ||
220 self.Properties().WriteWithoutResponse() ||
221 self.Properties().AuthenticatedSignedWrites())
222 {
223 p.reject_error(NotSupported, can_gc);
224 return p;
225 }
226
227 let sender = response_async(&p, self);
230 self.get_bluetooth_thread()
231 .send(BluetoothRequest::WriteValue(
232 self.get_instance_id(),
233 vec,
234 sender,
235 ))
236 .unwrap();
237 p
238 }
239
240 fn StartNotifications(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
242 let p = Promise::new_in_current_realm(comp, can_gc);
243
244 if uuid_is_blocklisted(self.uuid.as_ref(), Blocklist::Reads) {
246 p.reject_error(Security, can_gc);
247 return p;
248 }
249
250 if !self.Service().Device().get_gatt().Connected() {
252 p.reject_error(Network, can_gc);
253 return p;
254 }
255
256 if !(self.Properties().Notify() || self.Properties().Indicate()) {
258 p.reject_error(NotSupported, can_gc);
259 return p;
260 }
261
262 let sender = response_async(&p, self);
267 self.get_bluetooth_thread()
268 .send(BluetoothRequest::EnableNotification(
269 self.get_instance_id(),
270 true,
271 sender,
272 ))
273 .unwrap();
274 p
275 }
276
277 fn StopNotifications(&self, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
279 let p = Promise::new_in_current_realm(comp, can_gc);
280 let sender = response_async(&p, self);
281
282 self.get_bluetooth_thread()
287 .send(BluetoothRequest::EnableNotification(
288 self.get_instance_id(),
289 false,
290 sender,
291 ))
292 .unwrap();
293 p
294 }
295
296 event_handler!(
298 characteristicvaluechanged,
299 GetOncharacteristicvaluechanged,
300 SetOncharacteristicvaluechanged
301 );
302}
303
304impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
305 fn handle_response(&self, response: BluetoothResponse, promise: &Rc<Promise>, can_gc: CanGc) {
306 let device = self.Service().Device();
307 match response {
308 BluetoothResponse::GetDescriptors(descriptors_vec, single) => {
311 if single {
312 promise.resolve_native(
313 &device.get_or_create_descriptor(&descriptors_vec[0], self, can_gc),
314 can_gc,
315 );
316 return;
317 }
318 let mut descriptors = vec![];
319 for descriptor in descriptors_vec {
320 let bt_descriptor = device.get_or_create_descriptor(&descriptor, self, can_gc);
321 descriptors.push(bt_descriptor);
322 }
323 promise.resolve_native(&descriptors, can_gc);
324 },
325 BluetoothResponse::ReadValue(result) => {
327 let value = ByteString::new(result);
332 *self.value.borrow_mut() = Some(value.clone());
333
334 self.upcast::<EventTarget>()
336 .fire_bubbling_event(atom!("characteristicvaluechanged"), can_gc);
337
338 promise.resolve_native(&value, can_gc);
340 },
341 BluetoothResponse::WriteValue(result) => {
343 *self.value.borrow_mut() = Some(ByteString::new(result));
348
349 promise.resolve_native(&(), can_gc);
351 },
352 BluetoothResponse::EnableNotification(_result) => {
355 promise.resolve_native(self, can_gc);
361 },
362 _ => promise.reject_error(Error::Type("Something went wrong...".to_owned()), can_gc),
363 }
364 }
365}