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