script/dom/bluetooth/
bluetoothremotegattdescriptor.rs1use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::realm::CurrentRealm;
10use script_bindings::cell::DomRefCell;
11use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
12use servo_base::generic_channel::GenericSender;
13use servo_bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
14use servo_bluetooth_traits::{BluetoothRequest, BluetoothResponse};
15
16use crate::dom::bindings::buffer_source::get_buffer_source_copy;
17use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::BluetoothRemoteGATTCharacteristicMethods;
18use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
19use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
20use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
21use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
22use crate::dom::bindings::error::Error::{self, InvalidModification, Network, Security};
23use crate::dom::bindings::reflector::DomGlobal;
24use crate::dom::bindings::root::{Dom, DomRoot};
25use crate::dom::bindings::str::{ByteString, DOMString};
26use crate::dom::bluetooth::{AsyncBluetoothListener, response_async};
27use crate::dom::bluetoothremotegattcharacteristic::{
28 BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH,
29};
30use crate::dom::globalscope::GlobalScope;
31use crate::dom::promise::Promise;
32
33#[dom_struct]
35pub(crate) struct BluetoothRemoteGATTDescriptor {
36 reflector_: Reflector,
37 characteristic: Dom<BluetoothRemoteGATTCharacteristic>,
38 uuid: DOMString,
39 value: DomRefCell<Option<ByteString>>,
40 instance_id: String,
41}
42
43impl BluetoothRemoteGATTDescriptor {
44 pub(crate) fn new_inherited(
45 characteristic: &BluetoothRemoteGATTCharacteristic,
46 uuid: DOMString,
47 instance_id: String,
48 ) -> BluetoothRemoteGATTDescriptor {
49 BluetoothRemoteGATTDescriptor {
50 reflector_: Reflector::new(),
51 characteristic: Dom::from_ref(characteristic),
52 uuid,
53 value: DomRefCell::new(None),
54 instance_id,
55 }
56 }
57
58 pub(crate) fn new(
59 cx: &mut JSContext,
60 global: &GlobalScope,
61 characteristic: &BluetoothRemoteGATTCharacteristic,
62 uuid: DOMString,
63 instance_id: String,
64 ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
65 reflect_dom_object_with_cx(
66 Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
67 characteristic,
68 uuid,
69 instance_id,
70 )),
71 global,
72 cx,
73 )
74 }
75
76 fn get_bluetooth_thread(&self) -> GenericSender<BluetoothRequest> {
77 self.global().as_window().bluetooth_thread()
78 }
79
80 fn get_instance_id(&self) -> String {
81 self.instance_id.clone()
82 }
83}
84
85impl BluetoothRemoteGATTDescriptorMethods<crate::DomTypeHolder> for BluetoothRemoteGATTDescriptor {
86 fn Characteristic(&self) -> DomRoot<BluetoothRemoteGATTCharacteristic> {
88 DomRoot::from_ref(&self.characteristic)
89 }
90
91 fn Uuid(&self) -> DOMString {
93 self.uuid.clone()
94 }
95
96 fn GetValue(&self) -> Option<ByteString> {
98 self.value.borrow().clone()
99 }
100
101 fn ReadValue(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
103 let p = Promise::new_in_realm(cx);
104
105 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Reads) {
107 p.reject_error(cx, Security(None));
108 return p;
109 }
110
111 if !self
113 .Characteristic()
114 .Service()
115 .Device()
116 .get_gatt(cx)
117 .Connected()
118 {
119 p.reject_error(cx, Network(None));
120 return p;
121 }
122
123 let sender = response_async(&p, self);
127 self.get_bluetooth_thread()
128 .send(BluetoothRequest::ReadValue(self.get_instance_id(), sender))
129 .unwrap();
130 p
131 }
132
133 fn WriteValue(
135 &self,
136 cx: &mut CurrentRealm,
137 value: ArrayBufferViewOrArrayBuffer,
138 ) -> Rc<Promise> {
139 let p = Promise::new_in_realm(cx);
140
141 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Writes) {
143 p.reject_error(cx, Security(None));
144 return p;
145 }
146
147 let vec = get_buffer_source_copy((&value).into());
149 if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH {
150 p.reject_error(cx, InvalidModification(None));
151 return p;
152 }
153
154 if !self
156 .Characteristic()
157 .Service()
158 .Device()
159 .get_gatt(cx)
160 .Connected()
161 {
162 p.reject_error(cx, Network(None));
163 return p;
164 }
165
166 let sender = response_async(&p, self);
170 self.get_bluetooth_thread()
171 .send(BluetoothRequest::WriteValue(
172 self.get_instance_id(),
173 vec,
174 sender,
175 ))
176 .unwrap();
177 p
178 }
179}
180
181impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
182 fn handle_response(
183 &self,
184 cx: &mut JSContext,
185 response: BluetoothResponse,
186 promise: &Rc<Promise>,
187 ) {
188 match response {
189 BluetoothResponse::ReadValue(result) => {
191 let value = ByteString::new(result);
196 *self.value.safe_borrow_mut(cx.no_gc()) = Some(value.clone());
197
198 promise.resolve_native(cx, &value);
200 },
201 BluetoothResponse::WriteValue(result) => {
203 *self.value.safe_borrow_mut(cx.no_gc()) = Some(ByteString::new(result));
208
209 promise.resolve_native(cx, &());
212 },
213 _ => promise.reject_error(cx, Error::Type(c"Something went wrong...".to_owned())),
214 }
215 }
216}