1use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::realm::CurrentRealm;
10use script_bindings::reflector::reflect_dom_object_with_cx;
11use servo_bluetooth_traits::{BluetoothResponse, GATTType};
12
13use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
14use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::{Dom, DomRoot};
17use crate::dom::bindings::str::DOMString;
18use crate::dom::bluetooth::{AsyncBluetoothListener, get_gatt_children};
19use crate::dom::bluetoothdevice::BluetoothDevice;
20use crate::dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID};
21use crate::dom::eventtarget::EventTarget;
22use crate::dom::globalscope::GlobalScope;
23use crate::dom::promise::Promise;
24
25#[dom_struct]
27pub(crate) struct BluetoothRemoteGATTService {
28 eventtarget: EventTarget,
29 device: Dom<BluetoothDevice>,
30 uuid: DOMString,
31 is_primary: bool,
32 instance_id: String,
33}
34
35impl BluetoothRemoteGATTService {
36 pub(crate) fn new_inherited(
37 device: &BluetoothDevice,
38 uuid: DOMString,
39 is_primary: bool,
40 instance_id: String,
41 ) -> BluetoothRemoteGATTService {
42 BluetoothRemoteGATTService {
43 eventtarget: EventTarget::new_inherited(),
44 device: Dom::from_ref(device),
45 uuid,
46 is_primary,
47 instance_id,
48 }
49 }
50
51 #[expect(non_snake_case)]
52 pub(crate) fn new(
53 cx: &mut JSContext,
54 global: &GlobalScope,
55 device: &BluetoothDevice,
56 uuid: DOMString,
57 isPrimary: bool,
58 instanceID: String,
59 ) -> DomRoot<BluetoothRemoteGATTService> {
60 reflect_dom_object_with_cx(
61 Box::new(BluetoothRemoteGATTService::new_inherited(
62 device, uuid, isPrimary, instanceID,
63 )),
64 global,
65 cx,
66 )
67 }
68
69 fn get_instance_id(&self) -> String {
70 self.instance_id.clone()
71 }
72}
73
74impl BluetoothRemoteGATTServiceMethods<crate::DomTypeHolder> for BluetoothRemoteGATTService {
75 fn Device(&self) -> DomRoot<BluetoothDevice> {
77 DomRoot::from_ref(&self.device)
78 }
79
80 fn IsPrimary(&self) -> bool {
82 self.is_primary
83 }
84
85 fn Uuid(&self) -> DOMString {
87 self.uuid.clone()
88 }
89
90 fn GetCharacteristic(
92 &self,
93 cx: &mut CurrentRealm,
94 characteristic: BluetoothCharacteristicUUID,
95 ) -> Rc<Promise> {
96 let is_connected = self.Device().get_gatt(cx).Connected();
97 get_gatt_children(
98 cx,
99 self,
100 true,
101 BluetoothUUID::characteristic,
102 Some(characteristic),
103 self.get_instance_id(),
104 is_connected,
105 GATTType::Characteristic,
106 )
107 }
108
109 fn GetCharacteristics(
111 &self,
112 cx: &mut CurrentRealm,
113 characteristic: Option<BluetoothCharacteristicUUID>,
114 ) -> Rc<Promise> {
115 let is_connected = self.Device().get_gatt(cx).Connected();
116 get_gatt_children(
117 cx,
118 self,
119 false,
120 BluetoothUUID::characteristic,
121 characteristic,
122 self.get_instance_id(),
123 is_connected,
124 GATTType::Characteristic,
125 )
126 }
127
128 fn GetIncludedService(
130 &self,
131 cx: &mut CurrentRealm,
132 service: BluetoothServiceUUID,
133 ) -> Rc<Promise> {
134 let is_connected = self.Device().get_gatt(cx).Connected();
135 get_gatt_children(
136 cx,
137 self,
138 false,
139 BluetoothUUID::service,
140 Some(service),
141 self.get_instance_id(),
142 is_connected,
143 GATTType::IncludedService,
144 )
145 }
146
147 fn GetIncludedServices(
149 &self,
150 cx: &mut CurrentRealm,
151 service: Option<BluetoothServiceUUID>,
152 ) -> Rc<Promise> {
153 let is_connected = self.Device().get_gatt(cx).Connected();
154 get_gatt_children(
155 cx,
156 self,
157 false,
158 BluetoothUUID::service,
159 service,
160 self.get_instance_id(),
161 is_connected,
162 GATTType::IncludedService,
163 )
164 }
165
166 event_handler!(serviceadded, GetOnserviceadded, SetOnserviceadded);
168
169 event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
171
172 event_handler!(serviceremoved, GetOnserviceremoved, SetOnserviceremoved);
174}
175
176impl AsyncBluetoothListener for BluetoothRemoteGATTService {
177 fn handle_response(
178 &self,
179 cx: &mut JSContext,
180 response: BluetoothResponse,
181 promise: &Rc<Promise>,
182 ) {
183 let device = self.Device();
184 match response {
185 BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
188 if single {
189 let characteristic =
190 device.get_or_create_characteristic(cx, &characteristics_vec[0], self);
191 promise.resolve_native_with_cx(cx, &characteristic);
192 return;
193 }
194 let mut characteristics = vec![];
195 for characteristic in characteristics_vec {
196 let bt_characteristic =
197 device.get_or_create_characteristic(cx, &characteristic, self);
198 characteristics.push(bt_characteristic);
199 }
200 promise.resolve_native_with_cx(cx, &characteristics);
201 },
202 BluetoothResponse::GetIncludedServices(services_vec, single) => {
205 let gatt_server = device.get_gatt(cx);
206 if single {
207 let characteristic =
208 device.get_or_create_service(cx, &services_vec[0], &gatt_server);
209 return promise.resolve_native_with_cx(cx, &characteristic);
210 }
211 let mut services = vec![];
212 for service in services_vec {
213 let bt_service = device.get_or_create_service(cx, &service, &gatt_server);
214 services.push(bt_service);
215 }
216 promise.resolve_native_with_cx(cx, &services);
217 },
218 _ => {
219 promise.reject_error_with_cx(cx, Error::Type(c"Something went wrong...".to_owned()))
220 },
221 }
222 }
223}