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::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// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
25#[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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device>
75    fn Device(&self) -> DomRoot<BluetoothDevice> {
76        DomRoot::from_ref(&self.device)
77    }
78
79    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary>
80    fn IsPrimary(&self) -> bool {
81        self.is_primary
82    }
83
84    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid>
85    fn Uuid(&self) -> DOMString {
86        self.uuid.clone().root()
87    }
88
89    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic>
90    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics>
109    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice>
128    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices>
147    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    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
166    event_handler!(serviceadded, GetOnserviceadded, SetOnserviceadded);
167
168    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onservicechanged
169    event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
170
171    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceremoved
172    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            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
185            // Step 7.
186            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            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
202            // Step 7.
203            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}