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 std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::realm::CurrentRealm;
10use script_bindings::reflector::reflect_dom_object_with_cx;
11use servo_bluetooth_traits::{BluetoothResponse, GATTType};
12
13use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
14use crate::dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::{Dom, DomRoot};
17use crate::dom::bindings::str::DOMString;
18use crate::dom::bluetooth::{AsyncBluetoothListener, get_gatt_children};
19use crate::dom::bluetoothdevice::BluetoothDevice;
20use crate::dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID};
21use crate::dom::eventtarget::EventTarget;
22use crate::dom::globalscope::GlobalScope;
23use crate::dom::promise::Promise;
24
25// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
26#[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 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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device>
76    fn Device(&self) -> DomRoot<BluetoothDevice> {
77        DomRoot::from_ref(&self.device)
78    }
79
80    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary>
81    fn IsPrimary(&self) -> bool {
82        self.is_primary
83    }
84
85    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid>
86    fn Uuid(&self) -> DOMString {
87        self.uuid.clone()
88    }
89
90    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic>
91    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics>
110    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice>
129    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    /// <https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices>
148    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    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceadded
167    event_handler!(serviceadded, GetOnserviceadded, SetOnserviceadded);
168
169    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onservicechanged
170    event_handler!(servicechanged, GetOnservicechanged, SetOnservicechanged);
171
172    // https://webbluetoothcg.github.io/web-bluetooth/#dom-serviceeventhandlers-onserviceremoved
173    event_handler!(serviceremoved, GetOnserviceremoved, SetOnserviceremoved);
174}
175
176impl AsyncBluetoothListener for BluetoothRemoteGATTService {
177    fn handle_response(
178        &self,
179        cx: &mut JSContext,
180        response: BluetoothResponse,
181        promise: &Rc<Promise>,
182    ) {
183        let device = self.Device();
184        match response {
185            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
186            // Step 7.
187            BluetoothResponse::GetCharacteristics(characteristics_vec, single) => {
188                if single {
189                    let characteristic =
190                        device.get_or_create_characteristic(cx, &characteristics_vec[0], self);
191                    promise.resolve_native_with_cx(cx, &characteristic);
192                    return;
193                }
194                let mut characteristics = vec![];
195                for characteristic in characteristics_vec {
196                    let bt_characteristic =
197                        device.get_or_create_characteristic(cx, &characteristic, self);
198                    characteristics.push(bt_characteristic);
199                }
200                promise.resolve_native_with_cx(cx, &characteristics);
201            },
202            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
203            // Step 7.
204            BluetoothResponse::GetIncludedServices(services_vec, single) => {
205                let gatt_server = device.get_gatt(cx);
206                if single {
207                    let characteristic =
208                        device.get_or_create_service(cx, &services_vec[0], &gatt_server);
209                    return promise.resolve_native_with_cx(cx, &characteristic);
210                }
211                let mut services = vec![];
212                for service in services_vec {
213                    let bt_service = device.get_or_create_service(cx, &service, &gatt_server);
214                    services.push(bt_service);
215                }
216                promise.resolve_native_with_cx(cx, &services);
217            },
218            _ => {
219                promise.reject_error_with_cx(cx, Error::Type(c"Something went wrong...".to_owned()))
220            },
221        }
222    }
223}