script/dom/bluetooth/
bluetoothremotegattdescriptor.rs1use std::rc::Rc;
6
7use base::generic_channel::GenericSender;
8use bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
9use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
10use dom_struct::dom_struct;
11use js::realm::CurrentRealm;
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods;
15use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
16use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
17use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
18use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
19use crate::dom::bindings::error::Error::{self, InvalidModification, Network, Security};
20use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_cx};
21use crate::dom::bindings::root::{Dom, DomRoot};
22use crate::dom::bindings::str::{ByteString, DOMString};
23use crate::dom::bluetooth::{AsyncBluetoothListener, response_async};
24use crate::dom::bluetoothremotegattcharacteristic::{
25 BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH,
26};
27use crate::dom::globalscope::GlobalScope;
28use crate::dom::promise::Promise;
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 cx: &mut js::context::JSContext,
58 global: &GlobalScope,
59 characteristic: &BluetoothRemoteGATTCharacteristic,
60 uuid: DOMString,
61 instance_id: String,
62 ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
63 reflect_dom_object_with_cx(
64 Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
65 characteristic,
66 uuid,
67 instance_id,
68 )),
69 global,
70 cx,
71 )
72 }
73
74 fn get_bluetooth_thread(&self) -> GenericSender<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, cx: &mut CurrentRealm) -> Rc<Promise> {
101 let p = Promise::new_in_realm(cx);
102
103 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Reads) {
105 p.reject_error(Security(None), CanGc::from_cx(cx));
106 return p;
107 }
108
109 if !self
111 .Characteristic()
112 .Service()
113 .Device()
114 .get_gatt(cx)
115 .Connected()
116 {
117 p.reject_error(Network(None), CanGc::from_cx(cx));
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 cx: &mut CurrentRealm,
135 value: ArrayBufferViewOrArrayBuffer,
136 ) -> Rc<Promise> {
137 let p = Promise::new_in_realm(cx);
138
139 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Writes) {
141 p.reject_error(Security(None), CanGc::from_cx(cx));
142 return p;
143 }
144
145 let vec = match value {
147 ArrayBufferViewOrArrayBuffer::ArrayBufferView(avb) => avb.to_vec(),
148 ArrayBufferViewOrArrayBuffer::ArrayBuffer(ab) => ab.to_vec(),
149 };
150 if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH {
151 p.reject_error(InvalidModification(None), CanGc::from_cx(cx));
152 return p;
153 }
154
155 if !self
157 .Characteristic()
158 .Service()
159 .Device()
160 .get_gatt(cx)
161 .Connected()
162 {
163 p.reject_error(Network(None), CanGc::from_cx(cx));
164 return p;
165 }
166
167 let sender = response_async(&p, self);
171 self.get_bluetooth_thread()
172 .send(BluetoothRequest::WriteValue(
173 self.get_instance_id(),
174 vec,
175 sender,
176 ))
177 .unwrap();
178 p
179 }
180}
181
182impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
183 fn handle_response(
184 &self,
185 cx: &mut js::context::JSContext,
186 response: BluetoothResponse,
187 promise: &Rc<Promise>,
188 ) {
189 match response {
190 BluetoothResponse::ReadValue(result) => {
192 let value = ByteString::new(result);
197 *self.value.borrow_mut() = Some(value.clone());
198
199 promise.resolve_native(&value, CanGc::from_cx(cx));
201 },
202 BluetoothResponse::WriteValue(result) => {
204 *self.value.borrow_mut() = Some(ByteString::new(result));
209
210 promise.resolve_native(&(), CanGc::from_cx(cx));
213 },
214 _ => promise.reject_error(
215 Error::Type(c"Something went wrong...".to_owned()),
216 CanGc::from_cx(cx),
217 ),
218 }
219 }
220}