script/dom/bluetooth/
bluetoothremotegattdescriptor.rs1use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::realm::CurrentRealm;
9use script_bindings::cell::DomRefCell;
10use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
11use servo_base::generic_channel::GenericSender;
12use servo_bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
13use servo_bluetooth_traits::{BluetoothRequest, BluetoothResponse};
14
15use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods;
16use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
17use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
18use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
19use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
20use crate::dom::bindings::error::Error::{self, InvalidModification, Network, Security};
21use crate::dom::bindings::reflector::DomGlobal;
22use crate::dom::bindings::root::{Dom, DomRoot};
23use crate::dom::bindings::str::{ByteString, DOMString};
24use crate::dom::bluetooth::{AsyncBluetoothListener, response_async};
25use crate::dom::bluetoothremotegattcharacteristic::{
26 BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH,
27};
28use crate::dom::globalscope::GlobalScope;
29use crate::dom::promise::Promise;
30use crate::script_runtime::CanGc;
31
32#[dom_struct]
34pub(crate) struct BluetoothRemoteGATTDescriptor {
35 reflector_: Reflector,
36 characteristic: Dom<BluetoothRemoteGATTCharacteristic>,
37 uuid: DOMString,
38 value: DomRefCell<Option<ByteString>>,
39 instance_id: String,
40}
41
42impl BluetoothRemoteGATTDescriptor {
43 pub(crate) fn new_inherited(
44 characteristic: &BluetoothRemoteGATTCharacteristic,
45 uuid: DOMString,
46 instance_id: String,
47 ) -> BluetoothRemoteGATTDescriptor {
48 BluetoothRemoteGATTDescriptor {
49 reflector_: Reflector::new(),
50 characteristic: Dom::from_ref(characteristic),
51 uuid,
52 value: DomRefCell::new(None),
53 instance_id,
54 }
55 }
56
57 pub(crate) fn new(
58 cx: &mut js::context::JSContext,
59 global: &GlobalScope,
60 characteristic: &BluetoothRemoteGATTCharacteristic,
61 uuid: DOMString,
62 instance_id: String,
63 ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
64 reflect_dom_object_with_cx(
65 Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
66 characteristic,
67 uuid,
68 instance_id,
69 )),
70 global,
71 cx,
72 )
73 }
74
75 fn get_bluetooth_thread(&self) -> GenericSender<BluetoothRequest> {
76 self.global().as_window().bluetooth_thread()
77 }
78
79 fn get_instance_id(&self) -> String {
80 self.instance_id.clone()
81 }
82}
83
84impl BluetoothRemoteGATTDescriptorMethods<crate::DomTypeHolder> for BluetoothRemoteGATTDescriptor {
85 fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
87 DomRoot::from_ref(&self.characteristic)
88 }
89
90 fn Uuid(&self) -> DOMString {
92 self.uuid.clone()
93 }
94
95 fn GetValue(&self) -> Option<ByteString> {
97 self.value.borrow().clone()
98 }
99
100 fn ReadValue(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
102 let p = Promise::new_in_realm(cx);
103
104 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Reads) {
106 p.reject_error(Security(None), CanGc::from_cx(cx));
107 return p;
108 }
109
110 if !self
112 .Characteristic()
113 .Service()
114 .Device()
115 .get_gatt(cx)
116 .Connected()
117 {
118 p.reject_error(Network(None), CanGc::from_cx(cx));
119 return p;
120 }
121
122 let sender = response_async(&p, self);
126 self.get_bluetooth_thread()
127 .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
128 .unwrap();
129 p
130 }
131
132 fn WriteValue(
134 &self,
135 cx: &mut CurrentRealm,
136 value: ArrayBufferViewOrArrayBuffer,
137 ) -> Rc<Promise> {
138 let p = Promise::new_in_realm(cx);
139
140 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Writes) {
142 p.reject_error(Security(None), CanGc::from_cx(cx));
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(None), CanGc::from_cx(cx));
153 return p;
154 }
155
156 if !self
158 .Characteristic()
159 .Service()
160 .Device()
161 .get_gatt(cx)
162 .Connected()
163 {
164 p.reject_error(Network(None), CanGc::from_cx(cx));
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(
185 &self,
186 cx: &mut js::context::JSContext,
187 response: BluetoothResponse,
188 promise: &Rc<Promise>,
189 ) {
190 match response {
191 BluetoothResponse::ReadValue(result) => {
193 let value = ByteString::new(result);
198 *self.value.borrow_mut() = Some(value.clone());
199
200 promise.resolve_native(&value, CanGc::from_cx(cx));
202 },
203 BluetoothResponse::WriteValue(result) => {
205 *self.value.borrow_mut() = Some(ByteString::new(result));
210
211 promise.resolve_native(&(), CanGc::from_cx(cx));
214 },
215 _ => promise.reject_error(
216 Error::Type(c"Something went wrong...".to_owned()),
217 CanGc::from_cx(cx),
218 ),
219 }
220 }
221}