diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 34c7dfcf3a9..8a61ca418d7 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -36,6 +36,7 @@ use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationD use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType}; use msg::constellation_msg::{self, ConstellationChan, PanicMsg}; use msg::webdriver_msg; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::storage_thread::{StorageThread, StorageThreadMsg}; use net_traits::{self, ResourceThread}; @@ -123,6 +124,9 @@ pub struct Constellation { /// A channel through which messages can be sent to the developer tools. devtools_chan: Option>, + /// A channel through which messages can be sent to the bluetooth thread. + bluetooth_thread: IpcSender, + /// A channel through which messages can be sent to the storage thread. storage_thread: StorageThread, @@ -197,6 +201,8 @@ pub struct InitialConstellationState { pub compositor_proxy: Box, /// A channel to the developer tools, if applicable. pub devtools_chan: Option>, + /// A channel to the bluetooth thread. + pub bluetooth_thread: IpcSender, /// A channel to the image cache thread. pub image_cache_thread: ImageCacheThread, /// A channel to the font cache thread. @@ -338,6 +344,7 @@ impl Constellation panic_receiver: panic_receiver, compositor_proxy: state.compositor_proxy, devtools_chan: state.devtools_chan, + bluetooth_thread: state.bluetooth_thread, resource_thread: state.resource_thread, image_cache_thread: state.image_cache_thread, font_cache_thread: state.font_cache_thread, @@ -424,6 +431,7 @@ impl Constellation scheduler_chan: self.scheduler_chan.clone(), compositor_proxy: self.compositor_proxy.clone_compositor_proxy(), devtools_chan: self.devtools_chan.clone(), + bluetooth_thread: self.bluetooth_thread.clone(), image_cache_thread: self.image_cache_thread.clone(), font_cache_thread: self.font_cache_thread.clone(), resource_thread: self.resource_thread.clone(), @@ -840,6 +848,9 @@ impl Constellation if let Err(e) = self.storage_thread.send(StorageThreadMsg::Exit) { warn!("Exit storage thread failed ({})", e); } + if let Err(e) = self.bluetooth_thread.send(BluetoothMethodMsg::Exit) { + warn!("Exit bluetooth thread failed ({})", e); + } self.font_cache_thread.exit(); self.compositor_proxy.send(ToCompositorMsg::ShutdownComplete); } diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 9facc11829c..ca44fa49faf 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -18,6 +18,7 @@ use msg::constellation_msg::{ConstellationChan, PanicMsg, FrameId, PipelineId, S use msg::constellation_msg::{LoadData, WindowSizeData}; use msg::constellation_msg::{PipelineNamespaceId}; use net_traits::ResourceThread; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::storage_thread::StorageThread; use profile_traits::mem as profile_mem; @@ -92,6 +93,8 @@ pub struct InitialPipelineState { pub compositor_proxy: Box, /// A channel to the developer tools, if applicable. pub devtools_chan: Option>, + /// A channel to the bluetooth thread. + pub bluetooth_thread: IpcSender, /// A channel to the image cache thread. pub image_cache_thread: ImageCacheThread, /// A channel to the font cache thread. @@ -214,6 +217,7 @@ impl Pipeline { constellation_chan: state.constellation_chan, scheduler_chan: state.scheduler_chan, devtools_chan: script_to_devtools_chan, + bluetooth_thread: state.bluetooth_thread, image_cache_thread: state.image_cache_thread, font_cache_thread: state.font_cache_thread.clone(), resource_thread: state.resource_thread, @@ -390,6 +394,7 @@ pub struct UnprivilegedPipelineContent { scheduler_chan: IpcSender, devtools_chan: Option>, script_to_compositor_chan: IpcSender, + bluetooth_thread: IpcSender, image_cache_thread: ImageCacheThread, font_cache_thread: FontCacheThread, resource_thread: ResourceThread, @@ -430,6 +435,7 @@ impl UnprivilegedPipelineContent { layout_to_constellation_chan: self.layout_to_constellation_chan.clone(), scheduler_chan: self.scheduler_chan.clone(), panic_chan: self.panic_chan.clone(), + bluetooth_thread: self.bluetooth_thread.clone(), resource_thread: self.resource_thread, storage_thread: self.storage_thread.clone(), image_cache_thread: self.image_cache_thread.clone(), diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 80437830a24..5d139ea5191 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -17,6 +17,7 @@ plugins = {path = "../plugins"} msg = {path = "../msg"} ipc-channel = {git = "https://github.com/servo/ipc-channel"} webrender_traits = {git = "https://github.com/servo/webrender_traits"} +device = {git = "https://github.com/servo/devices"} cookie = { version = "0.2.4", features = [ "serialize-rustc" ] } flate2 = "0.2.0" hyper = { version = "0.9", features = [ "serde-serialization" ] } diff --git a/components/net/bluetooth_thread.rs b/components/net/bluetooth_thread.rs new file mode 100644 index 00000000000..e2bb015673e --- /dev/null +++ b/components/net/bluetooth_thread.rs @@ -0,0 +1,522 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 device::bluetooth::BluetoothAdapter; +use device::bluetooth::BluetoothDevice; +use device::bluetooth::BluetoothGATTCharacteristic; +use device::bluetooth::BluetoothGATTDescriptor; +use device::bluetooth::BluetoothGATTService; +use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; +use std::borrow::ToOwned; +use std::collections::HashMap; +use std::string::String; +use util::thread::spawn_named; + +macro_rules! send_error( + ($sender:expr, $error:expr) => ( + return $sender.send(BluetoothObjectMsg::Error { error: String::from($error) }).unwrap(); + ); +); + +macro_rules! check_cache( + ($cache:expr, $key:expr) => ( + if $cache.contains_key($key) { + return $cache.get($key); + } + ); +); + +pub trait BluetoothThreadFactory { + fn new() -> Self; +} + +impl BluetoothThreadFactory for IpcSender { + fn new() -> IpcSender { + let (sender, receiver) = ipc::channel().unwrap(); + let adapter = match BluetoothAdapter::init() { + Ok(a) => Some(a), + Err(_) => None, + }; + spawn_named("BluetoothThread".to_owned(), move || { + BluetoothManager::new(receiver, adapter).start(); + }); + sender + } +} + +pub struct BluetoothManager { + receiver: IpcReceiver, + adapter: Option, + service_to_device: HashMap, + characteristic_to_service: HashMap, + descriptor_to_characteristic: HashMap, + cached_devices: HashMap, + cached_services: HashMap, + cached_characteristics: HashMap, + cached_descriptors: HashMap, +} + +impl BluetoothManager { + pub fn new (receiver: IpcReceiver, adapter: Option) -> BluetoothManager { + BluetoothManager { + receiver: receiver, + adapter: adapter, + service_to_device: HashMap::new(), + characteristic_to_service: HashMap::new(), + descriptor_to_characteristic: HashMap::new(), + cached_devices: HashMap::new(), + cached_services: HashMap::new(), + cached_characteristics: HashMap::new(), + cached_descriptors: HashMap::new(), + } + } + + fn start(&mut self) { + loop { + match self.receiver.recv().unwrap() { + BluetoothMethodMsg::RequestDevice(sender) => { + self.request_device(sender) + } + BluetoothMethodMsg::GATTServerConnect(device_id, sender) => { + self.gatt_server_connect(device_id, sender) + } + BluetoothMethodMsg::GATTServerDisconnect(device_id, sender) => { + self.gatt_server_disconnect(device_id, sender) + } + BluetoothMethodMsg::GetPrimaryService(device_id, sender) => { + self.get_primary_service(device_id, sender) + } + BluetoothMethodMsg::GetCharacteristic(service_id, sender) => { + self.get_characteristic(service_id, sender) + } + BluetoothMethodMsg::GetDescriptor(characteristic_id, sender) => { + self.get_descriptor(characteristic_id, sender) + } + BluetoothMethodMsg::ReadValue(id, sender) => { + self.read_value(id, sender) + } + BluetoothMethodMsg::WriteValue(id, value, sender) => { + self.write_value(id, value, sender) + } + BluetoothMethodMsg::Exit => { + break + } + } + } + } + + // Adapter + + fn get_adapter(&mut self) -> Option { + if self.adapter.is_none() + || self.adapter.clone().unwrap().get_address().is_err() { + self.adapter = BluetoothAdapter::init().ok(); + } + self.adapter.clone() + } + + // Device + + fn get_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec { + let devices = adapter.get_devices().unwrap_or(vec!()); + for device in &devices { + self.cached_devices.insert(device.get_address().unwrap_or("".to_owned()), device.clone()); + } + devices + } + + fn get_device(&mut self, adapter: &mut BluetoothAdapter, device_id: &str) -> Option<&BluetoothDevice> { + check_cache!(self.cached_devices, device_id); + // Update cache + self.get_devices(adapter); + check_cache!(self.cached_devices, device_id); + None + } + + // Service + + fn get_gatt_services(&mut self, adapter: &mut BluetoothAdapter, device_id: &str) -> Vec { + let services = match self.get_device(adapter, device_id) { + Some(d) => d.get_gatt_services().unwrap_or(vec!()), + None => vec!(), + }; + for service in &services { + self.cached_services.insert(service.get_object_path(), service.clone()); + self.service_to_device.insert(service.get_object_path(), device_id.to_owned()); + } + services + } + + fn get_gatt_service(&mut self, + adapter: &mut BluetoothAdapter, + service_id: &str) + -> Option<&BluetoothGATTService> { + check_cache!(self.cached_services, service_id); + let device_id = match self.service_to_device.get_mut(service_id) { + Some(d) => d.clone(), + None => return None, + }; + // Update cache + self.get_gatt_services(adapter, &device_id); + check_cache!(self.cached_services, service_id); + None + } + + #[allow(dead_code)] + fn get_gatt_service_by_uuid(&mut self, + adapter: &mut BluetoothAdapter, + device_id: &str, + service_uuid: &str) + -> Option { + for service in self.cached_services.values() { + if service.get_uuid().unwrap_or("".to_owned()) == service_uuid { + return Some(service.clone()); + } + } + // Update cache + let services = self.get_gatt_services(adapter, device_id); + for service in services { + if service.get_uuid().unwrap_or("".to_owned()) == service_uuid { + return Some(service.clone()); + } + } + None + } + + // Characteristic + + fn get_gatt_characteristics(&mut self, + adapter: &mut BluetoothAdapter, + service_id: &str) + -> Vec { + let characteristics = match self.get_gatt_service(adapter, service_id) { + Some(s) => s.get_gatt_characteristics().unwrap_or(vec!()), + None => vec!(), + }; + + for characteristic in &characteristics { + self.cached_characteristics.insert(characteristic.get_object_path(), characteristic.clone()); + self.characteristic_to_service.insert(characteristic.get_object_path(), service_id.to_owned()); + } + characteristics + } + + fn get_gatt_characteristic(&mut self, + adapter: &mut BluetoothAdapter, + characteristic_id: &str) + -> Option<&BluetoothGATTCharacteristic> { + check_cache!(self.cached_characteristics, characteristic_id); + let service_id = match self.characteristic_to_service.get_mut(characteristic_id) { + Some(s) => s.clone(), + None => return None, + }; + // Update cache + self.get_gatt_characteristics(adapter, &service_id); + check_cache!(self.cached_characteristics, characteristic_id); + None + } + + #[allow(dead_code)] + fn get_gatt_characteristic_by_uuid(&mut self, + adapter: &mut BluetoothAdapter, + service_id: &str, + characteristic_uuid: &str) + -> Option { + for characteristic in self.cached_characteristics.values() { + if characteristic.get_uuid().unwrap_or("".to_owned()) == characteristic_uuid { + return Some(characteristic.clone()); + } + } + // Update cache + let characteristics = self.get_gatt_characteristics(adapter, service_id); + for characteristic in characteristics { + if characteristic.get_uuid().unwrap_or("".to_owned()) == characteristic_uuid { + return Some(characteristic.clone()); + } + } + None + } + + fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> [bool; 9] { + let mut props = [false; 9]; + let flags = characteristic.get_flags().unwrap_or(vec!()); + for flag in flags { + match flag.as_ref() { + "broadcast" => props[0] = true, + "read" => props[1] = true, + "write_without_response" => props[2] = true, + "write" => props[3] = true, + "notify" => props[4] = true, + "indicate" => props[5] = true, + "authenticated_signed_writes" => props[6] = true, + "reliable_write" => props[7] = true, + "writable_auxiliaries" => props[8] = true, + _ => (), + } + } + props + } + + // Descriptor + + fn get_gatt_descriptors(&mut self, + adapter: &mut BluetoothAdapter, + characteristic_id: &str) + -> Vec { + let descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) { + Some(c) => c.get_gatt_descriptors().unwrap_or(vec!()), + None => vec!(), + }; + + for descriptor in &descriptors { + self.cached_descriptors.insert(descriptor.get_object_path(), descriptor.clone()); + self.descriptor_to_characteristic.insert(descriptor.get_object_path(), characteristic_id.to_owned()); + } + descriptors + } + + fn get_gatt_descriptor(&mut self, + adapter: &mut BluetoothAdapter, + descriptor_id: &str) + -> Option<&BluetoothGATTDescriptor> { + check_cache!(self.cached_descriptors, descriptor_id); + let characteristic_id = match self.descriptor_to_characteristic.get_mut(descriptor_id) { + Some(c) => c.clone(), + None => return None, + }; + // Update cache + self.get_gatt_descriptors(adapter, &characteristic_id); + check_cache!(self.cached_descriptors, descriptor_id); + None + } + + #[allow(dead_code)] + fn get_gatt_descriptor_by_uuid(&mut self, + adapter: &mut BluetoothAdapter, + characteristic_id: &str, + descriptor_uuid: &str) + -> Option { + for descriptor in self.cached_descriptors.values() { + if descriptor.get_uuid().unwrap_or("".to_owned()) == descriptor_uuid { + return Some(descriptor.clone()); + } + } + // Update cache + let descriptors = self.get_gatt_descriptors(adapter, characteristic_id); + for descriptor in descriptors { + if descriptor.get_uuid().unwrap_or("".to_owned()) == descriptor_uuid { + return Some(descriptor.clone()); + } + } + None + } + + // Methods + + fn request_device(&mut self, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + let devices = self.get_devices(&mut adapter); + if devices.is_empty() { + send_error!(sender, "No device found"); + } + + //TODO select the proper device + let device = &devices[0]; + + let message = BluetoothObjectMsg::BluetoothDevice { + id: device.get_address().unwrap_or("".to_owned()), + name: device.get_name().ok(), + device_class: device.get_class().ok(), + vendor_id_source: device.get_vendor_id_source().ok(), + vendor_id: device.get_vendor_id().ok(), + product_id: device.get_product_id().ok(), + product_version: device.get_device_id().ok(), + appearance: device.get_appearance().ok(), + tx_power: match device.get_tx_power() { + Ok(p) => Some(p as i8), + Err(_) => None, + }, + rssi: match device.get_rssi() { + Ok(p) => Some(p as i8), + Err(_) => None, + } + }; + sender.send(message).unwrap(); + } + + pub fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + + let connected = match self.get_device(&mut adapter, &device_id) { + Some(d) => { + if d.is_connected().unwrap_or(false) { + true + } else { + !d.connect().is_err() + } + } + None => send_error!(sender, "No device found"), + }; + + let message = BluetoothObjectMsg::BluetoothServer { + connected: connected + }; + sender.send(message).unwrap(); + } + + pub fn gatt_server_disconnect(&mut self, device_id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + + let connected = match self.get_device(&mut adapter, &device_id) { + Some(d) => { + if d.is_connected().unwrap_or(false) { + d.disconnect().is_err() + } else { + false + } + } + None => send_error!(sender, "No device found"), + }; + + let message = BluetoothObjectMsg::BluetoothServer { + connected: connected + }; + sender.send(message).unwrap(); + } + + pub fn get_primary_service(&mut self, device_id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + + let services = self.get_gatt_services(&mut adapter, &device_id); + if services.is_empty() { + send_error!(sender, "No service found"); + } + + for service in services { + if service.is_primary().unwrap_or(false) { + let message = BluetoothObjectMsg::BluetoothService { + uuid: service.get_uuid().unwrap_or("".to_owned()), + is_primary: true, + instance_id: service.get_object_path() + }; + sender.send(message).unwrap(); + return; + } + } + + send_error!(sender, "No primary service found"); + } + + pub fn get_characteristic(&mut self, service_id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + + let characteristics = self.get_gatt_characteristics(&mut adapter, &service_id); + if characteristics.is_empty() { + send_error!(sender, "No characteristic found"); + } + + let characteristic = &characteristics[0]; + let properties = self.get_characteristic_properties(&characteristic); + let message = BluetoothObjectMsg::BluetoothCharacteristic { + uuid: characteristic.get_uuid().unwrap_or("".to_owned()), + instance_id: characteristic.get_object_path(), + broadcast: properties[0], + read: properties[1], + write_without_response: properties[2], + write: properties[3], + notify: properties[4], + indicate: properties[5], + authenticated_signed_writes: properties[6], + reliable_write: properties[7], + writable_auxiliaries: properties[8] + }; + sender.send(message).unwrap(); + } + + pub fn get_descriptor(&mut self, characteristic_id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + + let descriptors = self.get_gatt_descriptors(&mut adapter, &characteristic_id); + if descriptors.is_empty() { + send_error!(sender, "No descriptor found"); + } + + let descriptor = &descriptors[0]; + let message = BluetoothObjectMsg::BluetoothDescriptor { + uuid: descriptor.get_uuid().unwrap_or("".to_owned()), + instance_id: descriptor.get_object_path(), + }; + sender.send(message).unwrap(); + } + + pub fn read_value(&mut self, id: String, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + let mut value = match self.get_gatt_characteristic(&mut adapter, &id) { + Some(c) => Some(c.read_value().unwrap_or(vec!())), + None => None, + }; + if value.is_none() { + value = match self.get_gatt_descriptor(&mut adapter, &id) { + Some(d) => Some(d.read_value().unwrap_or(vec!())), + None => None, + }; + } + + let message = match value { + Some(v) => BluetoothObjectMsg::BluetoothReadValue { value: v }, + None => send_error!(sender, "No characteristic or descriptor found with that id"), + }; + + sender.send(message).unwrap(); + } + + pub fn write_value(&mut self, id: String, value: Vec, sender: IpcSender) { + let mut adapter = match self.get_adapter() { + Some(a) => a, + None => send_error!(sender, "No adapter found"), + }; + let mut result = match self.get_gatt_characteristic(&mut adapter, &id) { + Some(c) => Some(c.write_value(value.clone())), + None => None, + }; + if result.is_none() { + result = match self.get_gatt_descriptor(&mut adapter, &id) { + Some(d) => Some(d.write_value(value.clone())), + None => None, + }; + } + + let message = match result { + Some(v) => match v { + Ok(_) => BluetoothObjectMsg::BluetoothWriteValue, + Err(e) => send_error!(sender, e.to_string()), + }, + None => send_error!(sender, "No characteristic or descriptor found with that id"), + }; + + sender.send(message).unwrap(); + } +} diff --git a/components/net/lib.rs b/components/net/lib.rs index 97b978f1725..0f6c508fc0a 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -13,6 +13,7 @@ extern crate brotli; extern crate cookie as cookie_rs; +extern crate device; extern crate devtools_traits; extern crate flate2; extern crate hyper; @@ -39,6 +40,7 @@ extern crate webrender_traits; extern crate websocket; pub mod about_loader; +pub mod bluetooth_thread; pub mod chrome_loader; pub mod cookie; pub mod cookie_storage; diff --git a/components/net_traits/bluetooth_thread.rs b/components/net_traits/bluetooth_thread.rs new file mode 100644 index 00000000000..86bdffc1fff --- /dev/null +++ b/components/net_traits/bluetooth_thread.rs @@ -0,0 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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 ipc_channel::ipc::IpcSender; + +#[derive(Deserialize, Serialize)] +pub enum BluetoothMethodMsg { + RequestDevice(IpcSender), + GATTServerConnect(String, IpcSender), + GATTServerDisconnect(String, IpcSender), + GetPrimaryService(String, IpcSender), + GetCharacteristic(String, IpcSender), + GetDescriptor(String, IpcSender), + ReadValue(String, IpcSender), + WriteValue(String, Vec, IpcSender), + Exit, +} + +#[derive(Deserialize, Serialize)] +pub enum BluetoothObjectMsg { + BluetoothDevice { + // Bluetooth Device properties + id: String, + name: Option, + device_class: Option, + vendor_id_source: Option, + vendor_id: Option, + product_id: Option, + product_version: Option, + // Advertisiong Data properties + appearance: Option, + tx_power: Option, + rssi: Option + }, + BluetoothServer { + connected: bool + }, + BluetoothService { + uuid: String, + is_primary: bool, + instance_id: String + }, + BluetoothCharacteristic { + // Characteristic + uuid: String, + instance_id: String, + // Characteristic properties + broadcast: bool, + read: bool, + write_without_response: bool, + write: bool, + notify: bool, + indicate: bool, + authenticated_signed_writes: bool, + reliable_write: bool, + writable_auxiliaries: bool + }, + BluetoothDescriptor { + uuid: String, + instance_id: String + }, + BluetoothReadValue { + value: Vec + }, + BluetoothWriteValue, + Error { + error: String + }, +} diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index f4b7a85e7c5..45895f63711 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -40,6 +40,7 @@ use std::thread; use url::Url; use websocket::header; +pub mod bluetooth_thread; pub mod hosts; pub mod image_cache_thread; pub mod net_error_list; diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs index 58d506dec45..36ac2a1f7e4 100644 --- a/components/script/dom/bluetooth.rs +++ b/components/script/dom/bluetooth.rs @@ -4,10 +4,15 @@ use dom::bindings::codegen::Bindings::BluetoothBinding; use dom::bindings::codegen::Bindings::BluetoothBinding::BluetoothMethods; +use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::VendorIDSource; use dom::bindings::global::GlobalRef; use dom::bindings::js::Root; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; +use dom::bluetoothadvertisingdata::BluetoothAdvertisingData; use dom::bluetoothdevice::BluetoothDevice; +use ipc_channel::ipc::{self, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; +use util::str::DOMString; // https://webbluetoothcg.github.io/web-bluetooth/#bluetooth #[dom_struct] @@ -27,13 +32,67 @@ impl Bluetooth { global, BluetoothBinding::Wrap) } + + fn get_bluetooth_thread(&self) -> IpcSender { + let global_root = self.global(); + let global_ref = global_root.r(); + global_ref.as_window().bluetooth_thread() + } } impl BluetoothMethods for Bluetooth { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice fn RequestDevice(&self) -> Option> { - //UNIMPLEMENTED - None + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send(BluetoothMethodMsg::RequestDevice(sender)).unwrap(); + let device = receiver.recv().unwrap(); + match device { + BluetoothObjectMsg::BluetoothDevice { + id, + name, + device_class, + vendor_id_source, + vendor_id, + product_id, + product_version, + appearance, + tx_power, + rssi, + } => { + let ad_data = &BluetoothAdvertisingData::new(self.global().r(), + appearance, + tx_power, + rssi); + let vendor_id_source = match vendor_id_source { + Some(vid) => match vid.as_ref() { + "bluetooth" => Some(VendorIDSource::Bluetooth), + "usb" => Some(VendorIDSource::Usb), + _ => Some(VendorIDSource::Unknown), + }, + None => None, + }; + let name = match name { + Some(n) => Some(DOMString::from(n)), + None => None, + }; + Some(BluetoothDevice::new(self.global().r(), + DOMString::from(id), + name, + ad_data, + device_class, + vendor_id_source, + vendor_id, + product_id, + product_version)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + } } } diff --git a/components/script/dom/bluetoothremotegattcharacteristic.rs b/components/script/dom/bluetoothremotegattcharacteristic.rs index 4b05b347242..3ce8749979a 100644 --- a/components/script/dom/bluetoothremotegattcharacteristic.rs +++ b/components/script/dom/bluetoothremotegattcharacteristic.rs @@ -2,16 +2,24 @@ * 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 dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: BluetoothRemoteGATTCharacteristicMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; +use dom::bindings::error::Error::Network; +use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::ByteString; use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; +use ipc_channel::ipc::{self, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; use util::str::DOMString; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic @@ -21,34 +29,49 @@ pub struct BluetoothRemoteGATTCharacteristic { service: MutHeap>, uuid: DOMString, properties: MutHeap>, - value: Option, + value: DOMRefCell>, + instanceID: String, } impl BluetoothRemoteGATTCharacteristic { pub fn new_inherited(service: &BluetoothRemoteGATTService, uuid: DOMString, - properties: &BluetoothCharacteristicProperties) + properties: &BluetoothCharacteristicProperties, + instanceID: String) -> BluetoothRemoteGATTCharacteristic { BluetoothRemoteGATTCharacteristic { reflector_: Reflector::new(), service: MutHeap::new(service), uuid: uuid, properties: MutHeap::new(properties), - value: None, + value: DOMRefCell::new(None), + instanceID: instanceID, } } pub fn new(global: GlobalRef, service: &BluetoothRemoteGATTService, uuid: DOMString, - properties: &BluetoothCharacteristicProperties) + properties: &BluetoothCharacteristicProperties, + instanceID: String) -> Root { reflect_dom_object(box BluetoothRemoteGATTCharacteristic::new_inherited(service, uuid, - properties), + properties, + instanceID), global, BluetoothRemoteGATTCharacteristicBinding::Wrap) } + + fn get_bluetooth_thread(&self) -> IpcSender { + let global_root = self.global(); + let global_ref = global_root.r(); + global_ref.as_window().bluetooth_thread() + } + + pub fn get_instance_id(&self) -> String { + self.instanceID.clone() + } } impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic { @@ -70,18 +93,78 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor fn GetDescriptor(&self) -> Option> { - //UNIMPLEMENTED - None + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GetDescriptor(self.get_instance_id(), sender)).unwrap(); + let descriptor = receiver.recv().unwrap(); + match descriptor { + BluetoothObjectMsg::BluetoothDescriptor { + uuid, + instance_id + } => { + Some(BluetoothRemoteGATTDescriptor::new(self.global().r(), + &self, + DOMString::from(uuid), + instance_id)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + } } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value fn GetValue(&self) -> Option { - self.value.clone() + self.value.borrow().clone() } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue - fn ReadValue(&self) -> ByteString { - //UNIMPLEMENTED - ByteString::new(vec!()) + fn ReadValue(&self) -> Fallible { + let (sender, receiver) = ipc::channel().unwrap(); + if !self.Service().Device().Gatt().Connected() { + Err(Network) + } + else { + self.get_bluetooth_thread().send( + BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap(); + let result = receiver.recv().unwrap(); + let value = match result { + BluetoothObjectMsg::BluetoothReadValue { + value + } => { + Some(ByteString::new(value)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + }; + *self.value.borrow_mut() = value; + Ok(self.GetValue().unwrap()) + } + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue + fn WriteValue(&self, value: Vec) { + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap(); + let result = receiver.recv().unwrap(); + match result { + BluetoothObjectMsg::BluetoothWriteValue => (), + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + }, + _ => unreachable!() + }; } } diff --git a/components/script/dom/bluetoothremotegattdescriptor.rs b/components/script/dom/bluetoothremotegattdescriptor.rs index 5812a2ea832..7b55e1d962e 100644 --- a/components/script/dom/bluetoothremotegattdescriptor.rs +++ b/components/script/dom/bluetoothremotegattdescriptor.rs @@ -2,13 +2,23 @@ * 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 dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding:: + BluetoothRemoteGATTCharacteristicMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; +use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; +use dom::bindings::error::Error::Network; +use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::str::ByteString; use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; +use ipc_channel::ipc::{self, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; use util::str::DOMString; // http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor @@ -17,30 +27,45 @@ pub struct BluetoothRemoteGATTDescriptor { reflector_: Reflector, characteristic: MutHeap>, uuid: DOMString, - value: Option, + value: DOMRefCell>, + instanceID: String, } impl BluetoothRemoteGATTDescriptor { pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic, - uuid: DOMString) + uuid: DOMString, + instanceID: String) -> BluetoothRemoteGATTDescriptor { BluetoothRemoteGATTDescriptor { reflector_: Reflector::new(), characteristic: MutHeap::new(characteristic), uuid: uuid, - value: None, + value: DOMRefCell::new(None), + instanceID: instanceID, } } pub fn new(global: GlobalRef, characteristic: &BluetoothRemoteGATTCharacteristic, - uuid: DOMString) + uuid: DOMString, + instanceID: String) -> Root{ reflect_dom_object(box BluetoothRemoteGATTDescriptor::new_inherited(characteristic, - uuid), + uuid, + instanceID), global, BluetoothRemoteGATTDescriptorBinding::Wrap) } + + fn get_bluetooth_thread(&self) -> IpcSender { + let global_root = self.global(); + let global_ref = global_root.r(); + global_ref.as_window().bluetooth_thread() + } + + pub fn get_instance_id(&self) -> String { + self.instanceID.clone() + } } impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { @@ -57,12 +82,52 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value fn GetValue(&self) -> Option { - self.value.clone() + self.value.borrow().clone() } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue - fn ReadValue(&self) -> ByteString { - //UNIMPLEMENTED - ByteString::new(vec!()) + fn ReadValue(&self) -> Fallible { + let (sender, receiver) = ipc::channel().unwrap(); + if !self.Characteristic().Service().Device().Gatt().Connected() { + Err(Network) + } + else { + self.get_bluetooth_thread().send( + BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap(); + let result = receiver.recv().unwrap(); + let value = match result { + BluetoothObjectMsg::BluetoothReadValue { + value + } => { + Some(ByteString::new(value)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + }; + *self.value.borrow_mut() = value; + Ok(self.GetValue().unwrap()) + } + } + + // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue + fn WriteValue(&self, value: Vec) { + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap(); + let result = receiver.recv().unwrap(); + match result { + BluetoothObjectMsg::BluetoothWriteValue => (), + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + }, + _ => unreachable!() + }; } } diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs index 7441344fe2f..2eec908d4c5 100644 --- a/components/script/dom/bluetoothremotegattserver.rs +++ b/components/script/dom/bluetoothremotegattserver.rs @@ -2,14 +2,18 @@ * 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 dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothremotegattservice::BluetoothRemoteGATTService; +use ipc_channel::ipc::{self, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; use std::cell::Cell; +use util::str::DOMString; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver #[dom_struct] @@ -20,21 +24,25 @@ pub struct BluetoothRemoteGATTServer { } impl BluetoothRemoteGATTServer { - pub fn new_inherited(device: &BluetoothDevice, is_connected: bool) -> BluetoothRemoteGATTServer { + pub fn new_inherited(device: &BluetoothDevice) -> BluetoothRemoteGATTServer { BluetoothRemoteGATTServer { reflector_: Reflector::new(), device: MutHeap::new(device), - connected: Cell::new(is_connected), + connected: Cell::new(false), } } - pub fn new(global: GlobalRef, device: &BluetoothDevice, connected: bool) -> Root { - reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited( - device, - connected), + pub fn new(global: GlobalRef, device: &BluetoothDevice) -> Root { + reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited(device), global, BluetoothRemoteGATTServerBinding::Wrap) } + + fn get_bluetooth_thread(&self) -> IpcSender { + let global_root = self.global(); + let global_ref = global_root.r(); + global_ref.as_window().bluetooth_thread() + } } impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { @@ -51,20 +59,72 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect fn Connect(&self) -> Root { - if !self.connected.get() { - self.connected.set(true); + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap(); + let server = receiver.recv().unwrap(); + match server { + BluetoothObjectMsg::BluetoothServer { + connected + } => { + self.connected.set(connected); + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + }, + _ => unreachable!() } Root::from_ref(self) } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect fn Disconnect(&self) { - self.connected.set(false); + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap(); + let server = receiver.recv().unwrap(); + match server { + BluetoothObjectMsg::BluetoothServer { + connected + } => { + self.connected.set(connected); + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + }, + _ => unreachable!() + } } // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice fn GetPrimaryService(&self) -> Option> { - //UNIMPLEMENTED - None + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GetPrimaryService(String::from(self.Device().Id()), sender)).unwrap(); + let service = receiver.recv().unwrap(); + match service { + BluetoothObjectMsg::BluetoothService { + uuid, + is_primary, + instance_id + } => { + Some(BluetoothRemoteGATTService::new(self.global().r(), + &self.device.get(), + DOMString::from(uuid), + is_primary, + instance_id)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + } } } diff --git a/components/script/dom/bluetoothremotegattservice.rs b/components/script/dom/bluetoothremotegattservice.rs index af2cd70ce7c..433bf8ef9d8 100644 --- a/components/script/dom/bluetoothremotegattservice.rs +++ b/components/script/dom/bluetoothremotegattservice.rs @@ -6,9 +6,12 @@ use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding; use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods; use dom::bindings::global::GlobalRef; use dom::bindings::js::{JS, MutHeap, Root}; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; +use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties; use dom::bluetoothdevice::BluetoothDevice; use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic; +use ipc_channel::ipc::{self, IpcSender}; +use net_traits::bluetooth_thread::{BluetoothMethodMsg, BluetoothObjectMsg}; use util::str::DOMString; // https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice @@ -18,32 +21,47 @@ pub struct BluetoothRemoteGATTService { device: MutHeap>, uuid: DOMString, isPrimary: bool, + instanceID: String, } impl BluetoothRemoteGATTService { pub fn new_inherited(device: &BluetoothDevice, uuid: DOMString, - isPrimary: bool) + isPrimary: bool, + instanceID: String) -> BluetoothRemoteGATTService { BluetoothRemoteGATTService { reflector_: Reflector::new(), device: MutHeap::new(device), uuid: uuid, isPrimary: isPrimary, + instanceID: instanceID, } } pub fn new(global: GlobalRef, device: &BluetoothDevice, uuid: DOMString, - isPrimary: bool) + isPrimary: bool, + instanceID: String) -> Root { reflect_dom_object(box BluetoothRemoteGATTService::new_inherited(device, uuid, - isPrimary), + isPrimary, + instanceID), global, BluetoothRemoteGATTServiceBinding::Wrap) } + + fn get_bluetooth_thread(&self) -> IpcSender { + let global_root = self.global(); + let global_ref = global_root.r(); + global_ref.as_window().bluetooth_thread() + } + + pub fn get_instance_id(&self) -> String { + self.instanceID.clone() + } } impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { @@ -64,7 +82,47 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService { // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic fn GetCharacteristic(&self) -> Option> { - // UNIMPLEMENTED - None + let (sender, receiver) = ipc::channel().unwrap(); + self.get_bluetooth_thread().send( + BluetoothMethodMsg::GetCharacteristic(self.get_instance_id(), sender)).unwrap(); + let characteristic = receiver.recv().unwrap(); + match characteristic { + BluetoothObjectMsg::BluetoothCharacteristic { + uuid, + instance_id, + broadcast, + read, + write_without_response, + write, + notify, + indicate, + authenticated_signed_writes, + reliable_write, + writable_auxiliaries, + } => { + let properties = &BluetoothCharacteristicProperties::new(self.global().r(), + broadcast, + read, + write_without_response, + write, + notify, + indicate, + authenticated_signed_writes, + reliable_write, + writable_auxiliaries); + Some(BluetoothRemoteGATTCharacteristic::new(self.global().r(), + &self, + DOMString::from(uuid), + properties, + instance_id)) + }, + BluetoothObjectMsg::Error { + error + } => { + println!("{}", error); + None + }, + _ => unreachable!() + } } } diff --git a/components/script/dom/webidls/BluetoothDevice.webidl b/components/script/dom/webidls/BluetoothDevice.webidl index 3a32dc38179..e8851e6240c 100644 --- a/components/script/dom/webidls/BluetoothDevice.webidl +++ b/components/script/dom/webidls/BluetoothDevice.webidl @@ -7,7 +7,8 @@ // Allocation authorities for Vendor IDs: enum VendorIDSource { "bluetooth", - "usb" + "usb", + "unknown" }; [Pref="dom.bluetooth.enabled"] diff --git a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl index e6ba9c89d2a..b3a1e691351 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTCharacteristic.webidl @@ -14,8 +14,10 @@ interface BluetoothRemoteGATTCharacteristic { //Promise getDescriptor(BluetoothDescriptorUUID descriptor); //Promise> //getDescriptors(optional BluetoothDescriptorUUID descriptor); - //Promise readValue(); + [Throws] ByteString readValue(); + //Promise readValue(); + void writeValue(sequence value); //Promise writeValue(BufferSource value); //Promise startNotifications(); //Promise stopNotifications(); diff --git a/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl b/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl index c7abe9e4859..77becb830bf 100644 --- a/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl +++ b/components/script/dom/webidls/BluetoothRemoteGATTDescriptor.webidl @@ -9,8 +9,9 @@ interface BluetoothRemoteGATTDescriptor { readonly attribute BluetoothRemoteGATTCharacteristic characteristic; readonly attribute DOMString uuid; readonly attribute ByteString? value; - + [Throws] ByteString readValue(); //Promise readValue(); + void writeValue(sequence value); //Promise writeValue(BufferSource value); }; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 94b6d2c7fb3..9c75b92184e 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -47,6 +47,7 @@ use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId} use msg::constellation_msg::{WindowSizeData, WindowSizeType}; use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult}; use net_traits::ResourceThread; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; use net_traits::storage_thread::{StorageThread, StorageType}; use num_traits::ToPrimitive; @@ -212,6 +213,10 @@ pub struct Window { #[ignore_heap_size_of = "channels are hard"] resource_thread: Arc, + /// A handle for communicating messages to the bluetooth thread. + #[ignore_heap_size_of = "channels are hard"] + bluetooth_thread: IpcSender, + /// A handle for communicating messages to the storage thread. #[ignore_heap_size_of = "channels are hard"] storage_thread: StorageThread, @@ -334,6 +339,10 @@ impl Window { &*self.page } + pub fn bluetooth_thread(&self) -> IpcSender { + self.bluetooth_thread.clone() + } + pub fn storage_thread(&self) -> StorageThread { self.storage_thread.clone() } @@ -1401,6 +1410,7 @@ impl Window { compositor: IpcSender, image_cache_thread: ImageCacheThread, resource_thread: Arc, + bluetooth_thread: IpcSender, storage_thread: StorageThread, mem_profiler_chan: mem::ProfilerChan, devtools_chan: Option>, @@ -1456,6 +1466,7 @@ impl Window { dom_static: GlobalStaticData::new(), js_runtime: DOMRefCell::new(Some(runtime.clone())), resource_thread: resource_thread, + bluetooth_thread: bluetooth_thread, storage_thread: storage_thread, constellation_chan: constellation_chan, page_clip_rect: Cell::new(MAX_RECT), diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 4768273c16e..7070a29c2c4 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -64,6 +64,7 @@ use msg::constellation_msg::{PipelineId, PipelineNamespace}; use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType}; use msg::webdriver_msg::WebDriverScriptCommand; use net_traits::LoadData as NetLoadData; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use net_traits::storage_thread::StorageThread; use net_traits::{AsyncResponseTarget, ControlMsg, LoadConsumer, LoadContext, Metadata, ResourceThread}; @@ -310,6 +311,8 @@ pub struct ScriptThread { /// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if /// there are many iframes. resource_thread: Arc, + /// A handle to the bluetooth thread. + bluetooth_thread: IpcSender, /// A handle to the storage thread. storage_thread: StorageThread, @@ -540,6 +543,7 @@ impl ScriptThread { image_cache_port: image_cache_port, resource_thread: Arc::new(state.resource_thread), + bluetooth_thread: state.bluetooth_thread, storage_thread: state.storage_thread, port: port, @@ -1482,6 +1486,7 @@ impl ScriptThread { self.compositor.borrow_mut().clone(), self.image_cache_thread.clone(), self.resource_thread.clone(), + self.bluetooth_thread.clone(), self.storage_thread.clone(), self.mem_profiler_chan.clone(), self.devtools_chan.clone(), diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 2d4469ef80d..a001159acfb 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -46,6 +46,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{PipelineNamespaceId, SubpageId}; use msg::webdriver_msg::WebDriverScriptCommand; use net_traits::ResourceThread; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::response::HttpsState; use net_traits::storage_thread::StorageThread; @@ -320,6 +321,8 @@ pub struct InitialScriptState { pub scheduler_chan: IpcSender, /// A channel to the resource manager thread. pub resource_thread: ResourceThread, + /// A channel to the bluetooth thread. + pub bluetooth_thread: IpcSender, /// A channel to the storage thread. pub storage_thread: StorageThread, /// A channel to the image cache thread. diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index adba235f7f4..a3a64440eb3 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -167,6 +167,15 @@ name = "block" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blurz" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dbus 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "brotli" version = "0.3.20" @@ -414,6 +423,15 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dbus" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "debug_unreachable" version = "0.1.1" @@ -430,6 +448,14 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "device" +version = "0.0.1" +source = "git+https://github.com/dati91/devices?branch=device-api#dccc5111e46124cef596cef10ce9056362892e59" +dependencies = [ + "blurz 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "devtools" version = "0.0.1" @@ -1307,6 +1333,7 @@ version = "0.0.1" dependencies = [ "brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)", "cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "device 0.0.1 (git+https://github.com/dati91/devices?branch=device-api)", "devtools_traits 0.0.1", "flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 42e6706500c..c8355affa58 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -71,9 +71,11 @@ use compositing::{CompositorProxy, CompositorThread, Constellation}; use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc::{self, IpcSender}; +use net::bluetooth_thread::BluetoothThreadFactory; use net::image_cache_thread::new_image_cache_thread; use net::resource_thread::new_resource_thread; use net::storage_thread::StorageThreadFactory; +use net_traits::bluetooth_thread::BluetoothMethodMsg; use net_traits::storage_thread::StorageThread; use profile::mem as profile_mem; use profile::time as profile_time; @@ -208,6 +210,7 @@ fn create_constellation(opts: opts::Opts, devtools_chan: Option>, supports_clipboard: bool, webrender_api_sender: Option) -> Sender { + let bluetooth_thread: IpcSender = BluetoothThreadFactory::new(); let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone()); let image_cache_thread = new_image_cache_thread(resource_thread.clone(), webrender_api_sender.as_ref().map(|wr| wr.create_api())); @@ -218,6 +221,7 @@ fn create_constellation(opts: opts::Opts, let initial_state = InitialConstellationState { compositor_proxy: compositor_proxy, devtools_chan: devtools_chan, + bluetooth_thread: bluetooth_thread, image_cache_thread: image_cache_thread, font_cache_thread: font_cache_thread, resource_thread: resource_thread,