diff options
Diffstat (limited to 'components/script/dom/bluetoothdevice.rs')
-rw-r--r-- | components/script/dom/bluetoothdevice.rs | 156 |
1 files changed, 132 insertions, 24 deletions
diff --git a/components/script/dom/bluetoothdevice.rs b/components/script/dom/bluetoothdevice.rs index b257b82f343..d56970c0d98 100644 --- a/components/script/dom/bluetoothdevice.rs +++ b/components/script/dom/bluetoothdevice.rs @@ -2,17 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothServiceMsg}; +use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg}; +use bluetooth_traits::{BluetoothRequest, BluetoothResponse, BluetoothServiceMsg}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding; use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; -use dom::bindings::js::{JS, Root, MutHeap, MutNullableHeap}; +use dom::bindings::error::Error; +use dom::bindings::error::ErrorResult; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{MutJS, MutNullableJS, Root}; use dom::bindings::reflector::{DomObject, reflect_dom_object}; use dom::bindings::str::DOMString; -use dom::bluetooth::Bluetooth; -use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; +use dom::bluetooth::{AsyncBluetoothListener, Bluetooth, response_async}; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; @@ -20,8 +23,12 @@ use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; +use dom::promise::Promise; +use ipc_channel::ipc::{self, IpcSender}; +use js::jsapi::JSContext; +use std::cell::Cell; use std::collections::HashMap; - +use std::rc::Rc; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothdevice #[dom_struct] @@ -29,47 +36,48 @@ pub struct BluetoothDevice { eventtarget: EventTarget, id: DOMString, name: Option<DOMString>, - ad_data: MutHeap<JS<BluetoothAdvertisingData>>, - gatt: MutNullableHeap<JS<BluetoothRemoteGATTServer>>, - context: MutHeap<JS<Bluetooth>>, - attribute_instance_map: (DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTService>>>>, - DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTCharacteristic>>>>, - DOMRefCell<HashMap<String, MutHeap<JS<BluetoothRemoteGATTDescriptor>>>>), + gatt: MutNullableJS<BluetoothRemoteGATTServer>, + context: MutJS<Bluetooth>, + attribute_instance_map: (DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTService>>>, + DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTCharacteristic>>>, + DOMRefCell<HashMap<String, MutJS<BluetoothRemoteGATTDescriptor>>>), + watching_advertisements: Cell<bool>, } impl BluetoothDevice { pub fn new_inherited(id: DOMString, name: Option<DOMString>, - ad_data: &BluetoothAdvertisingData, context: &Bluetooth) -> BluetoothDevice { BluetoothDevice { eventtarget: EventTarget::new_inherited(), id: id, name: name, - ad_data: MutHeap::new(ad_data), gatt: Default::default(), - context: MutHeap::new(context), + context: MutJS::new(context), attribute_instance_map: (DOMRefCell::new(HashMap::new()), DOMRefCell::new(HashMap::new()), DOMRefCell::new(HashMap::new())), + watching_advertisements: Cell::new(false), } } pub fn new(global: &GlobalScope, id: DOMString, name: Option<DOMString>, - adData: &BluetoothAdvertisingData, context: &Bluetooth) -> Root<BluetoothDevice> { reflect_dom_object(box BluetoothDevice::new_inherited(id, name, - adData, context), global, BluetoothDeviceBinding::Wrap) } + fn get_context(&self) -> Root<Bluetooth> { + self.context.get() + } + pub fn get_or_create_service(&self, service: &BluetoothServiceMsg, server: &BluetoothRemoteGATTServer) @@ -84,7 +92,7 @@ impl BluetoothDevice { DOMString::from(service.uuid.clone()), service.is_primary, service.instance_id.clone()); - service_map.insert(service.instance_id.clone(), MutHeap::new(&bt_service)); + service_map.insert(service.instance_id.clone(), MutJS::new(&bt_service)); return bt_service; } @@ -113,10 +121,17 @@ impl BluetoothDevice { DOMString::from(characteristic.uuid.clone()), &properties, characteristic.instance_id.clone()); - characteristic_map.insert(characteristic.instance_id.clone(), MutHeap::new(&bt_characteristic)); + characteristic_map.insert(characteristic.instance_id.clone(), MutJS::new(&bt_characteristic)); return bt_characteristic; } + pub fn is_represented_device_null(&self) -> bool { + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothRequest::IsRepresentedDeviceNull(self.Id().to_string(), sender)).unwrap(); + receiver.recv().unwrap() + } + pub fn get_or_create_descriptor(&self, descriptor: &BluetoothDescriptorMsg, characteristic: &BluetoothRemoteGATTCharacteristic) @@ -130,9 +145,67 @@ impl BluetoothDevice { characteristic, DOMString::from(descriptor.uuid.clone()), descriptor.instance_id.clone()); - descriptor_map.insert(descriptor.instance_id.clone(), MutHeap::new(&bt_descriptor)); + descriptor_map.insert(descriptor.instance_id.clone(), MutJS::new(&bt_descriptor)); return bt_descriptor; } + + fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> { + self.global().as_window().bluetooth_thread() + } + + // https://webbluetoothcg.github.io/web-bluetooth/#clean-up-the-disconnected-device + #[allow(unrooted_must_root)] + pub fn clean_up_disconnected_device(&self) { + // Step 1. + self.Gatt().set_connected(false); + + // TODO: Step 2: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer. + + // Step 3: We don't need `context`, we get the attributeInstanceMap from the device. + // https://github.com/WebBluetoothCG/web-bluetooth/issues/330 + + // Step 4. + let mut service_map = self.attribute_instance_map.0.borrow_mut(); + let service_ids = service_map.drain().map(|(id, _)| id).collect(); + + let mut characteristic_map = self.attribute_instance_map.1.borrow_mut(); + let characteristic_ids = characteristic_map.drain().map(|(id, _)| id).collect(); + + let mut descriptor_map = self.attribute_instance_map.2.borrow_mut(); + let descriptor_ids = descriptor_map.drain().map(|(id, _)| id).collect(); + + // Step 5, 6.4, 7. + // TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic. + let _ = self.get_bluetooth_thread().send( + BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids)); + + // Step 8. + self.upcast::<EventTarget>().fire_bubbling_event(atom!("gattserverdisconnected")); + } + + // https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection + #[allow(unrooted_must_root)] + pub fn garbage_collect_the_connection(&self) -> ErrorResult { + // Step 1: TODO: Check if other systems using this device. + + // Step 2. + let context = self.get_context(); + for (id, device) in context.get_device_map().borrow().iter() { + // Step 2.1 - 2.2. + if id == &self.Id().to_string() { + if device.get().Gatt().Connected() { + return Ok(()); + } + // TODO: Step 2.3: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer. + } + } + + // Step 3. + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothRequest::GATTServerDisconnect(String::from(self.Id()), sender)).unwrap(); + receiver.recv().unwrap().map_err(Error::from) + } } impl BluetoothDeviceMethods for BluetoothDevice { @@ -146,11 +219,6 @@ impl BluetoothDeviceMethods for BluetoothDevice { self.name.clone() } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-addata - fn AdData(&self) -> Root<BluetoothAdvertisingData> { - self.ad_data.get() - } - // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt fn Gatt(&self) -> Root<BluetoothRemoteGATTServer> { // TODO: Step 1 - 2: Implement the Permission API. @@ -159,6 +227,46 @@ impl BluetoothDeviceMethods for BluetoothDevice { }) } + #[allow(unrooted_must_root)] + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchadvertisements + fn WatchAdvertisements(&self) -> Rc<Promise> { + let p = Promise::new(&self.global()); + let sender = response_async(&p, self); + // TODO: Step 1. + // Note: Steps 2 - 3 are implemented in components/bluetooth/lib.rs in watch_advertisements function + // and in handle_response function. + self.get_bluetooth_thread().send( + BluetoothRequest::WatchAdvertisements(String::from(self.Id()), sender)).unwrap(); + return p; + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements + fn UnwatchAdvertisements(&self) -> () { + // Step 1. + self.watching_advertisements.set(false) + // TODO: Step 2. + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-watchingadvertisements + fn WatchingAdvertisements(&self) -> bool { + self.watching_advertisements.get() + } + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdeviceeventhandlers-ongattserverdisconnected event_handler!(gattserverdisconnected, GetOngattserverdisconnected, SetOngattserverdisconnected); } + +impl AsyncBluetoothListener for BluetoothDevice { + fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) { + match response { + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-unwatchadvertisements + BluetoothResponse::WatchAdvertisements(_result) => { + // Step 3.1. + self.watching_advertisements.set(true); + // Step 3.2. + promise.resolve_native(promise_cx, &()); + }, + _ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())), + } + } +} |