1use std::rc::Rc;
6
7use bluetooth_traits::{BluetoothResponse, GATTType};
8use dom_struct::dom_struct;
9use js::realm::CurrentRealm;
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::reflector::reflect_dom_object_with_cx;
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::Promise;
23use crate::script_runtime::CanGc;
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 js::context::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 js::context::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 promise.resolve_native(
190 &device.get_or_create_characteristic(cx, &characteristics_vec[0], self),
191 CanGc::from_cx(cx),
192 );
193 return;
194 }
195 let mut characteristics = vec![];
196 for characteristic in characteristics_vec {
197 let bt_characteristic =
198 device.get_or_create_characteristic(cx, &characteristic, self);
199 characteristics.push(bt_characteristic);
200 }
201 promise.resolve_native(&characteristics, CanGc::from_cx(cx));
202 },
203 BluetoothResponse::GetIncludedServices(services_vec, single) => {
206 let gatt_server = device.get_gatt(cx);
207 if single {
208 return promise.resolve_native(
209 &device.get_or_create_service(cx, &services_vec[0], &gatt_server),
210 CanGc::from_cx(cx),
211 );
212 }
213 let mut services = vec![];
214 for service in services_vec {
215 let bt_service = device.get_or_create_service(cx, &service, &gatt_server);
216 services.push(bt_service);
217 }
218 promise.resolve_native(&services, CanGc::from_cx(cx));
219 },
220 _ => promise.reject_error(
221 Error::Type(c"Something went wrong...".to_owned()),
222 CanGc::from_cx(cx),
223 ),
224 }
225 }
226}