script/dom/bluetooth/
bluetoothremotegattserver.rs1use std::cell::Cell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use js::realm::CurrentRealm;
10use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
11use servo_base::generic_channel::GenericSender;
12use servo_bluetooth_traits::{BluetoothRequest, BluetoothResponse, GATTType};
13
14use crate::dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
15use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
16use crate::dom::bindings::error::{Error, ErrorResult};
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::{Dom, DomRoot};
19use crate::dom::bluetooth::{AsyncBluetoothListener, get_gatt_children, response_async};
20use crate::dom::bluetoothdevice::BluetoothDevice;
21use crate::dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
22use crate::dom::globalscope::GlobalScope;
23use crate::dom::promise::Promise;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
28pub(crate) struct BluetoothRemoteGATTServer {
29 reflector_: Reflector,
30 device: Dom<BluetoothDevice>,
31 connected: Cell<bool>,
32}
33
34impl BluetoothRemoteGATTServer {
35 pub(crate) fn new_inherited(device: &BluetoothDevice) -> BluetoothRemoteGATTServer {
36 BluetoothRemoteGATTServer {
37 reflector_: Reflector::new(),
38 device: Dom::from_ref(device),
39 connected: Cell::new(false),
40 }
41 }
42
43 pub(crate) fn new(
44 cx: &mut js::context::JSContext,
45 global: &GlobalScope,
46 device: &BluetoothDevice,
47 ) -> DomRoot<BluetoothRemoteGATTServer> {
48 reflect_dom_object_with_cx(
49 Box::new(BluetoothRemoteGATTServer::new_inherited(device)),
50 global,
51 cx,
52 )
53 }
54
55 fn get_bluetooth_thread(&self) -> GenericSender<BluetoothRequest> {
56 self.global().as_window().bluetooth_thread()
57 }
58
59 pub(crate) fn set_connected(&self, connected: bool) {
60 self.connected.set(connected);
61 }
62}
63
64impl BluetoothRemoteGATTServerMethods<crate::DomTypeHolder> for BluetoothRemoteGATTServer {
65 fn Device(&self) -> DomRoot<BluetoothDevice> {
67 DomRoot::from_ref(&self.device)
68 }
69
70 fn Connected(&self) -> bool {
72 self.connected.get()
73 }
74
75 fn Connect(&self, cx: &mut CurrentRealm) -> Rc<Promise> {
77 let p = Promise::new_in_realm(cx);
79 let sender = response_async(&p, self);
80
81 self.get_bluetooth_thread()
90 .send(BluetoothRequest::GATTServerConnect(
91 String::from(self.Device().Id()),
92 sender,
93 ))
94 .unwrap();
95 p
97 }
98
99 fn Disconnect(&self, cx: &mut js::context::JSContext) -> ErrorResult {
101 if !self.Connected() {
105 return Ok(());
106 }
107
108 self.Device().clean_up_disconnected_device(cx);
110
111 self.Device().garbage_collect_the_connection(cx)
113 }
114
115 fn GetPrimaryService(
117 &self,
118 cx: &mut CurrentRealm,
119 service: BluetoothServiceUUID,
120 ) -> Rc<Promise> {
121 let is_connected = self.Device().get_gatt(cx).Connected();
122 get_gatt_children(
124 cx,
125 self,
126 true,
127 BluetoothUUID::service,
128 Some(service),
129 String::from(self.Device().Id()),
130 is_connected,
131 GATTType::PrimaryService,
132 )
133 }
134
135 fn GetPrimaryServices(
137 &self,
138 cx: &mut CurrentRealm,
139 service: Option<BluetoothServiceUUID>,
140 ) -> Rc<Promise> {
141 get_gatt_children(
143 cx,
144 self,
145 false,
146 BluetoothUUID::service,
147 service,
148 String::from(self.Device().Id()),
149 self.Connected(),
150 GATTType::PrimaryService,
151 )
152 }
153}
154
155impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
156 fn handle_response(
157 &self,
158 cx: &mut js::context::JSContext,
159 response: BluetoothResponse,
160 promise: &Rc<Promise>,
161 ) {
162 match response {
163 BluetoothResponse::GATTServerConnect(connected) => {
165 if self.Device().is_represented_device_null() {
167 if let Err(e) = self.Device().garbage_collect_the_connection(cx) {
168 return promise.reject_error(e, CanGc::from_cx(cx));
169 }
170 return promise.reject_error(Error::Network(None), CanGc::from_cx(cx));
171 }
172
173 self.connected.set(connected);
175
176 promise.resolve_native(self, CanGc::from_cx(cx));
178 },
179 BluetoothResponse::GetPrimaryServices(services_vec, single) => {
182 let device = self.Device();
183 if single {
184 promise.resolve_native(
185 &device.get_or_create_service(cx, &services_vec[0], self),
186 CanGc::from_cx(cx),
187 );
188 return;
189 }
190 let mut services = vec![];
191 for service in services_vec {
192 let bt_service = device.get_or_create_service(cx, &service, self);
193 services.push(bt_service);
194 }
195 promise.resolve_native(&services, CanGc::from_cx(cx));
196 },
197 _ => promise.reject_error(
198 Error::Type(c"Something went wrong...".to_owned()),
199 CanGc::from_cx(cx),
200 ),
201 }
202 }
203}