script/dom/bluetooth/
bluetoothremotegattdescriptor.rs1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::realm::CurrentRealm;
8use script_bindings::cell::DomRefCell;
9use script_bindings::reflector::{Reflector, reflect_dom_object};
10use servo_base::generic_channel::GenericSender;
11use servo_bluetooth_traits::blocklist::{Blocklist, uuid_is_blocklisted};
12use servo_bluetooth_traits::{BluetoothRequest, BluetoothResponse};
13
14use crate::dom::bindings::buffer_source::get_buffer_source_copy;
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, RootedPromise};
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 JSContext,
58 global: &GlobalScope,
59 characteristic: &BluetoothRemoteGATTCharacteristic,
60 uuid: DOMString,
61 instance_id: String,
62 ) -> DomRoot<BluetoothRemoteGATTDescriptor> {
63 reflect_dom_object(
64 cx,
65 Box::new(BluetoothRemoteGATTDescriptor::new_inherited(
66 characteristic,
67 uuid,
68 instance_id,
69 )),
70 global,
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) -> RootedPromise {
101 let p = Promise::new_in_realm_rooted(cx);
102
103 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Reads) {
105 p.reject_error(cx, Security(None));
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(cx, Network(None));
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 ) -> RootedPromise {
137 let p = Promise::new_in_realm_rooted(cx);
138
139 if uuid_is_blocklisted(&self.uuid.str(), Blocklist::Writes) {
141 p.reject_error(cx, Security(None));
142 return p;
143 }
144
145 let vec = get_buffer_source_copy((&value).into());
147 if vec.len() > MAXIMUM_ATTRIBUTE_LENGTH {
148 p.reject_error(cx, InvalidModification(None));
149 return p;
150 }
151
152 if !self
154 .Characteristic()
155 .Service()
156 .Device()
157 .get_gatt(cx)
158 .Connected()
159 {
160 p.reject_error(cx, Network(None));
161 return p;
162 }
163
164 let sender = response_async(&p, self);
168 self.get_bluetooth_thread()
169 .send(BluetoothRequest::WriteValue(
170 self.get_instance_id(),
171 vec,
172 sender,
173 ))
174 .unwrap();
175 p
176 }
177}
178
179impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
180 fn handle_response(
181 &self,
182 cx: &mut JSContext,
183 response: BluetoothResponse,
184 promise: &RootedPromise,
185 ) {
186 match response {
187 BluetoothResponse::ReadValue(result) => {
189 let value = ByteString::new(result);
194 *self.value.safe_borrow_mut(cx.no_gc()) = Some(value.clone());
195
196 promise.resolve_native(cx, &value);
198 },
199 BluetoothResponse::WriteValue(result) => {
201 *self.value.safe_borrow_mut(cx.no_gc()) = Some(ByteString::new(result));
206
207 promise.resolve_native(cx, &());
210 },
211 _ => promise.reject_error(cx, Error::Type(c"Something went wrong...".to_owned())),
212 }
213 }
214}