Skip to main content

script/dom/bluetooth/
bluetoothremotegattservice.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
24#[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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device>
74    fn Device(&self) -> DomRoot<BluetoothDevice> {
75        DomRoot::from_ref(&self.device)
76    }
77
78    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary>
79    fn IsPrimary(&self) -> bool {
80        self.is_primary
81    }
82
83    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid>
84    fn Uuid(&self) -> DOMString {
85        self.uuid.clone()
86    }
87
88    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic>
89    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics>
108    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice>
127    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices>
146    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    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
165    event_handler!(serviceadded, GetOnserviceadded, SetOnserviceadded);
166
167    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onservicechanged
168    event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
169
170    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceremoved
171    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            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
184            // Step 7.
185            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            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
201            // Step 7.
202            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}