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 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// 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 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    /// <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 js::context::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                    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            // https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
204            // Step 7.
205            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}