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