servo: Merge #13909 - Webbluetooth Async behaviour (from dati91:promise-queue); r=jdm

<!-- Please describe your changes on the following line: -->

Note: depends on https://github.com/servo/servo/pull/13612

The current WBT communication is synchronous. With this, it should work properly (except the disconnect function, which will need some more work, because the current implementation differ from the spec).

<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [X] There are tests for these changes

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

Source-Repo: https://github.com/servo/servo
Source-Revision: 1153ca9841f458daf373471f3c65295abd872271
This commit is contained in:
Attila Dusnoki 2016-11-08 09:05:12 -06:00
Родитель 7d3399c8b2
Коммит 2190c013f5
19 изменённых файлов: 806 добавлений и 729 удалений

Просмотреть файл

@ -15,10 +15,9 @@ extern crate uuid;
pub mod test;
use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothCharacteristicsMsg};
use bluetooth_traits::{BluetoothDescriptorMsg, BluetoothDescriptorsMsg};
use bluetooth_traits::{BluetoothDeviceMsg, BluetoothError, BluetoothMethodMsg};
use bluetooth_traits::{BluetoothResult, BluetoothServiceMsg, BluetoothServicesMsg};
use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothDescriptorMsg, BluetoothServiceMsg};
use bluetooth_traits::{BluetoothDeviceMsg, BluetoothRequest, BluetoothResponse};
use bluetooth_traits::{BluetoothError, BluetoothResponseResult, BluetoothResult};
use bluetooth_traits::blacklist::{uuid_is_blacklisted, Blacklist};
use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions};
use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic};
@ -85,8 +84,8 @@ pub trait BluetoothThreadFactory {
fn new() -> Self;
}
impl BluetoothThreadFactory for IpcSender<BluetoothMethodMsg> {
fn new() -> IpcSender<BluetoothMethodMsg> {
impl BluetoothThreadFactory for IpcSender<BluetoothRequest> {
fn new() -> IpcSender<BluetoothRequest> {
let (sender, receiver) = ipc::channel().unwrap();
let adapter = BluetoothAdapter::init().ok();
spawn_named("BluetoothThread".to_owned(), move || {
@ -167,7 +166,7 @@ fn is_mock_adapter(adapter: &BluetoothAdapter) -> bool {
}
pub struct BluetoothManager {
receiver: IpcReceiver<BluetoothMethodMsg>,
receiver: IpcReceiver<BluetoothRequest>,
adapter: Option<BluetoothAdapter>,
address_to_id: HashMap<String, String>,
service_to_device: HashMap<String, String>,
@ -181,7 +180,7 @@ pub struct BluetoothManager {
}
impl BluetoothManager {
pub fn new(receiver: IpcReceiver<BluetoothMethodMsg>, adapter: Option<BluetoothAdapter>) -> BluetoothManager {
pub fn new(receiver: IpcReceiver<BluetoothRequest>, adapter: Option<BluetoothAdapter>) -> BluetoothManager {
BluetoothManager {
receiver: receiver,
adapter: adapter,
@ -200,49 +199,49 @@ impl BluetoothManager {
fn start(&mut self) {
while let Ok(msg) = self.receiver.recv() {
match msg {
BluetoothMethodMsg::RequestDevice(options, sender) => {
BluetoothRequest::RequestDevice(options, sender) => {
self.request_device(options, sender)
},
BluetoothMethodMsg::GATTServerConnect(device_id, sender) => {
BluetoothRequest::GATTServerConnect(device_id, sender) => {
self.gatt_server_connect(device_id, sender)
},
BluetoothMethodMsg::GATTServerDisconnect(device_id, sender) => {
BluetoothRequest::GATTServerDisconnect(device_id, sender) => {
self.gatt_server_disconnect(device_id, sender)
},
BluetoothMethodMsg::GetPrimaryService(device_id, uuid, sender) => {
BluetoothRequest::GetPrimaryService(device_id, uuid, sender) => {
self.get_primary_service(device_id, uuid, sender)
},
BluetoothMethodMsg::GetPrimaryServices(device_id, uuid, sender) => {
BluetoothRequest::GetPrimaryServices(device_id, uuid, sender) => {
self.get_primary_services(device_id, uuid, sender)
},
BluetoothMethodMsg::GetIncludedService(service_id, uuid, sender) => {
BluetoothRequest::GetIncludedService(service_id, uuid, sender) => {
self.get_included_service(service_id, uuid, sender)
},
BluetoothMethodMsg::GetIncludedServices(service_id, uuid, sender) => {
BluetoothRequest::GetIncludedServices(service_id, uuid, sender) => {
self.get_included_services(service_id, uuid, sender)
},
BluetoothMethodMsg::GetCharacteristic(service_id, uuid, sender) => {
BluetoothRequest::GetCharacteristic(service_id, uuid, sender) => {
self.get_characteristic(service_id, uuid, sender)
},
BluetoothMethodMsg::GetCharacteristics(service_id, uuid, sender) => {
BluetoothRequest::GetCharacteristics(service_id, uuid, sender) => {
self.get_characteristics(service_id, uuid, sender)
},
BluetoothMethodMsg::GetDescriptor(characteristic_id, uuid, sender) => {
BluetoothRequest::GetDescriptor(characteristic_id, uuid, sender) => {
self.get_descriptor(characteristic_id, uuid, sender)
},
BluetoothMethodMsg::GetDescriptors(characteristic_id, uuid, sender) => {
BluetoothRequest::GetDescriptors(characteristic_id, uuid, sender) => {
self.get_descriptors(characteristic_id, uuid, sender)
},
BluetoothMethodMsg::ReadValue(id, sender) => {
BluetoothRequest::ReadValue(id, sender) => {
self.read_value(id, sender)
},
BluetoothMethodMsg::WriteValue(id, value, sender) => {
BluetoothRequest::WriteValue(id, value, sender) => {
self.write_value(id, value, sender)
},
BluetoothMethodMsg::Test(data_set_name, sender) => {
BluetoothRequest::Test(data_set_name, sender) => {
self.test(data_set_name, sender)
}
BluetoothMethodMsg::Exit => {
BluetoothRequest::Exit => {
break
},
}
@ -527,7 +526,7 @@ impl BluetoothManager {
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
fn request_device(&mut self,
options: RequestDeviceoptions,
sender: IpcSender<BluetoothResult<BluetoothDeviceMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
let mut adapter = get_adapter_or_return_error!(self, sender);
if let Ok(ref session) = adapter.create_discovery_session() {
if session.start_discovery().is_ok() {
@ -561,31 +560,30 @@ impl BluetoothManager {
}
self.allowed_services.insert(device_id.clone(), services);
if let Some(device) = self.get_device(&mut adapter, &device_id) {
let message = Ok(BluetoothDeviceMsg {
id: device_id,
name: device.get_name().ok(),
appearance: device.get_appearance().ok(),
tx_power: device.get_tx_power().ok().map(|p| p as i8),
rssi: device.get_rssi().ok().map(|p| p as i8),
});
return drop(sender.send(message));
let message = BluetoothDeviceMsg {
id: device_id,
name: device.get_name().ok(),
appearance: device.get_appearance().ok(),
tx_power: device.get_tx_power().ok().map(|p| p as i8),
rssi: device.get_rssi().ok().map(|p| p as i8),
};
return drop(sender.send(Ok(BluetoothResponse::RequestDevice(message))));
}
}
return drop(sender.send(Err(BluetoothError::NotFound)));
}
fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender<BluetoothResult<bool>>) {
fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender<BluetoothResponseResult>) {
let mut adapter = get_adapter_or_return_error!(self, sender);
match self.get_device(&mut adapter, &device_id) {
Some(d) => {
if d.is_connected().unwrap_or(false) {
return drop(sender.send(Ok(true)));
return drop(sender.send(Ok(BluetoothResponse::GATTServerConnect(true))));
}
let _ = d.connect();
for _ in 0..MAXIMUM_TRANSACTION_TIME {
match d.is_connected().unwrap_or(false) {
true => return drop(sender.send(Ok(true))),
true => return drop(sender.send(Ok(BluetoothResponse::GATTServerConnect(true)))),
false => {
if is_mock_adapter(&adapter) {
break;
@ -624,7 +622,7 @@ impl BluetoothManager {
fn get_primary_service(&mut self,
device_id: String,
uuid: String,
sender: IpcSender<BluetoothResult<BluetoothServiceMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_devices.contains_key(&device_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -639,11 +637,15 @@ impl BluetoothManager {
for service in services {
if service.is_primary().unwrap_or(false) {
if let Ok(uuid) = service.get_uuid() {
return drop(sender.send(Ok(BluetoothServiceMsg {
uuid: uuid,
is_primary: true,
instance_id: service.get_id(),
})));
return drop(sender.send(
Ok(BluetoothResponse::GetPrimaryService(
BluetoothServiceMsg {
uuid: uuid,
is_primary: true,
instance_id: service.get_id(),
}
))
));
}
}
}
@ -653,7 +655,7 @@ impl BluetoothManager {
fn get_primary_services(&mut self,
device_id: String,
uuid: Option<String>,
sender: IpcSender<BluetoothResult<BluetoothServicesMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_devices.contains_key(&device_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -674,11 +676,13 @@ impl BluetoothManager {
for service in services {
if service.is_primary().unwrap_or(false) {
if let Ok(uuid) = service.get_uuid() {
services_vec.push(BluetoothServiceMsg {
uuid: uuid,
is_primary: true,
instance_id: service.get_id(),
});
services_vec.push(
BluetoothServiceMsg {
uuid: uuid,
is_primary: true,
instance_id: service.get_id(),
}
);
}
}
}
@ -690,20 +694,17 @@ impl BluetoothManager {
return drop(sender.send(Err(BluetoothError::NotFound)));
}
let _ = sender.send(Ok(services_vec));
return drop(sender.send(Ok(BluetoothResponse::GetPrimaryServices(services_vec))));
}
fn get_included_service(&mut self,
service_id: String,
uuid: String,
sender: IpcSender<BluetoothResult<BluetoothServiceMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_services.contains_key(&service_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
let mut adapter = match self.get_or_create_adapter() {
Some(a) => a,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
};
let mut adapter = get_adapter_or_return_error!(self, sender);
let device = match self.device_from_service_id(&service_id) {
Some(device) => device,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
@ -716,11 +717,15 @@ impl BluetoothManager {
for service in services {
if let Ok(service_uuid) = service.get_uuid() {
if uuid == service_uuid {
return drop(sender.send(Ok(BluetoothServiceMsg {
uuid: uuid,
is_primary: service.is_primary().unwrap_or(false),
instance_id: service.get_id(),
})));
return drop(sender.send(
Ok(BluetoothResponse::GetIncludedService(
BluetoothServiceMsg {
uuid: uuid,
is_primary: service.is_primary().unwrap_or(false),
instance_id: service.get_id(),
}
))
));
}
}
}
@ -730,14 +735,11 @@ impl BluetoothManager {
fn get_included_services(&mut self,
service_id: String,
uuid: Option<String>,
sender: IpcSender<BluetoothResult<BluetoothServicesMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_services.contains_key(&service_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
let mut adapter = match self.get_or_create_adapter() {
Some(a) => a,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
};
let mut adapter = get_adapter_or_return_error!(self, sender);
let device = match self.device_from_service_id(&service_id) {
Some(device) => device,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
@ -750,11 +752,13 @@ impl BluetoothManager {
let mut services_vec = vec!();
for service in services {
if let Ok(service_uuid) = service.get_uuid() {
services_vec.push(BluetoothServiceMsg {
uuid: service_uuid,
is_primary: service.is_primary().unwrap_or(false),
instance_id: service.get_id(),
});
services_vec.push(
BluetoothServiceMsg {
uuid: service_uuid,
is_primary: service.is_primary().unwrap_or(false),
instance_id: service.get_id(),
}
);
}
}
if let Some(uuid) = uuid {
@ -765,13 +769,13 @@ impl BluetoothManager {
return drop(sender.send(Err(BluetoothError::NotFound)));
}
let _ = sender.send(Ok(services_vec));
return drop(sender.send(Ok(BluetoothResponse::GetIncludedServices(services_vec))));
}
fn get_characteristic(&mut self,
service_id: String,
uuid: String,
sender: IpcSender<BluetoothResult<BluetoothCharacteristicMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_services.contains_key(&service_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -783,20 +787,20 @@ impl BluetoothManager {
for characteristic in characteristics {
if let Ok(uuid) = characteristic.get_uuid() {
let properties = self.get_characteristic_properties(&characteristic);
let message = Ok(BluetoothCharacteristicMsg {
uuid: uuid,
instance_id: characteristic.get_id(),
broadcast: properties.contains(BROADCAST),
read: properties.contains(READ),
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
write: properties.contains(WRITE),
notify: properties.contains(NOTIFY),
indicate: properties.contains(INDICATE),
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
reliable_write: properties.contains(RELIABLE_WRITE),
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
});
return drop(sender.send(message));
let message = BluetoothCharacteristicMsg {
uuid: uuid,
instance_id: characteristic.get_id(),
broadcast: properties.contains(BROADCAST),
read: properties.contains(READ),
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
write: properties.contains(WRITE),
notify: properties.contains(NOTIFY),
indicate: properties.contains(INDICATE),
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
reliable_write: properties.contains(RELIABLE_WRITE),
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
};
return drop(sender.send(Ok(BluetoothResponse::GetCharacteristic(message))));
}
}
return drop(sender.send(Err(BluetoothError::NotFound)));
@ -805,7 +809,7 @@ impl BluetoothManager {
fn get_characteristics(&mut self,
service_id: String,
uuid: Option<String>,
sender: IpcSender<BluetoothResult<BluetoothCharacteristicsMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_services.contains_key(&service_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -822,19 +826,20 @@ impl BluetoothManager {
if let Ok(uuid) = characteristic.get_uuid() {
let properties = self.get_characteristic_properties(&characteristic);
characteristics_vec.push(
BluetoothCharacteristicMsg {
uuid: uuid,
instance_id: characteristic.get_id(),
broadcast: properties.contains(BROADCAST),
read: properties.contains(READ),
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
write: properties.contains(WRITE),
notify: properties.contains(NOTIFY),
indicate: properties.contains(INDICATE),
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
reliable_write: properties.contains(RELIABLE_WRITE),
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
});
BluetoothCharacteristicMsg {
uuid: uuid,
instance_id: characteristic.get_id(),
broadcast: properties.contains(BROADCAST),
read: properties.contains(READ),
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
write: properties.contains(WRITE),
notify: properties.contains(NOTIFY),
indicate: properties.contains(INDICATE),
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
reliable_write: properties.contains(RELIABLE_WRITE),
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
}
);
}
}
characteristics_vec.retain(|c| !uuid_is_blacklisted(&c.uuid, Blacklist::All));
@ -842,13 +847,13 @@ impl BluetoothManager {
return drop(sender.send(Err(BluetoothError::NotFound)));
}
let _ = sender.send(Ok(characteristics_vec));
return drop(sender.send(Ok(BluetoothResponse::GetCharacteristics(characteristics_vec))));
}
fn get_descriptor(&mut self,
characteristic_id: String,
uuid: String,
sender: IpcSender<BluetoothResult<BluetoothDescriptorMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_characteristics.contains_key(&characteristic_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -859,10 +864,14 @@ impl BluetoothManager {
}
for descriptor in descriptors {
if let Ok(uuid) = descriptor.get_uuid() {
return drop(sender.send(Ok(BluetoothDescriptorMsg {
uuid: uuid,
instance_id: descriptor.get_id(),
})));
return drop(sender.send(
Ok(BluetoothResponse::GetDescriptor(
BluetoothDescriptorMsg {
uuid: uuid,
instance_id: descriptor.get_id(),
}
))
));
}
}
return drop(sender.send(Err(BluetoothError::NotFound)));
@ -871,7 +880,7 @@ impl BluetoothManager {
fn get_descriptors(&mut self,
characteristic_id: String,
uuid: Option<String>,
sender: IpcSender<BluetoothResult<BluetoothDescriptorsMsg>>) {
sender: IpcSender<BluetoothResponseResult>) {
if !self.cached_characteristics.contains_key(&characteristic_id) {
return drop(sender.send(Err(BluetoothError::InvalidState)));
}
@ -886,20 +895,22 @@ impl BluetoothManager {
let mut descriptors_vec = vec!();
for descriptor in descriptors {
if let Ok(uuid) = descriptor.get_uuid() {
descriptors_vec.push(BluetoothDescriptorMsg {
uuid: uuid,
instance_id: descriptor.get_id(),
});
descriptors_vec.push(
BluetoothDescriptorMsg {
uuid: uuid,
instance_id: descriptor.get_id(),
}
);
}
}
descriptors_vec.retain(|d| !uuid_is_blacklisted(&d.uuid, Blacklist::All));
if descriptors_vec.is_empty() {
return drop(sender.send(Err(BluetoothError::NotFound)));
}
let _ = sender.send(Ok(descriptors_vec));
return drop(sender.send(Ok(BluetoothResponse::GetDescriptors(descriptors_vec))));
}
fn read_value(&mut self, id: String, sender: IpcSender<BluetoothResult<Vec<u8>>>) {
fn read_value(&mut self, id: String, sender: IpcSender<BluetoothResponseResult>) {
let mut adapter = get_adapter_or_return_error!(self, sender);
let mut value = self.get_gatt_characteristic(&mut adapter, &id)
.map(|c| c.read_value().unwrap_or(vec![]));
@ -907,10 +918,13 @@ impl BluetoothManager {
value = self.get_gatt_descriptor(&mut adapter, &id)
.map(|d| d.read_value().unwrap_or(vec![]));
}
let _ = sender.send(value.ok_or(BluetoothError::InvalidState));
match value {
Some(v) => return drop(sender.send(Ok(BluetoothResponse::ReadValue(v)))),
None => return drop(sender.send(Err(BluetoothError::InvalidState))),
}
}
fn write_value(&mut self, id: String, value: Vec<u8>, sender: IpcSender<BluetoothResult<bool>>) {
fn write_value(&mut self, id: String, value: Vec<u8>, sender: IpcSender<BluetoothResponseResult>) {
let mut adapter = get_adapter_or_return_error!(self, sender);
let mut result = self.get_gatt_characteristic(&mut adapter, &id)
.map(|c| c.write_value(value.clone()));
@ -918,13 +932,12 @@ impl BluetoothManager {
result = self.get_gatt_descriptor(&mut adapter, &id)
.map(|d| d.write_value(value.clone()));
}
let message = match result {
match result {
Some(v) => match v {
Ok(_) => Ok(true),
Ok(_) => return drop(sender.send(Ok(BluetoothResponse::WriteValue(value)))),
Err(_) => return drop(sender.send(Err(BluetoothError::NotSupported))),
},
None => return drop(sender.send(Err(BluetoothError::InvalidState))),
};
let _ = sender.send(message);
}
}
}

Просмотреть файл

@ -75,21 +75,43 @@ pub type BluetoothDescriptorsMsg = Vec<BluetoothDescriptorMsg>;
pub type BluetoothResult<T> = Result<T, BluetoothError>;
pub type BluetoothResponseResult = Result<BluetoothResponse, BluetoothError>;
#[derive(Deserialize, Serialize)]
pub enum BluetoothMethodMsg {
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResult<BluetoothDeviceMsg>>),
GATTServerConnect(String, IpcSender<BluetoothResult<bool>>),
pub enum BluetoothRequest {
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResponseResult>),
GATTServerConnect(String, IpcSender<BluetoothResponseResult>),
GATTServerDisconnect(String, IpcSender<BluetoothResult<bool>>),
GetPrimaryService(String, String, IpcSender<BluetoothResult<BluetoothServiceMsg>>),
GetPrimaryServices(String, Option<String>, IpcSender<BluetoothResult<BluetoothServicesMsg>>),
GetIncludedService(String, String, IpcSender<BluetoothResult<BluetoothServiceMsg>>),
GetIncludedServices(String, Option<String>, IpcSender<BluetoothResult<BluetoothServicesMsg>>),
GetCharacteristic(String, String, IpcSender<BluetoothResult<BluetoothCharacteristicMsg>>),
GetCharacteristics(String, Option<String>, IpcSender<BluetoothResult<BluetoothCharacteristicsMsg>>),
GetDescriptor(String, String, IpcSender<BluetoothResult<BluetoothDescriptorMsg>>),
GetDescriptors(String, Option<String>, IpcSender<BluetoothResult<BluetoothDescriptorsMsg>>),
ReadValue(String, IpcSender<BluetoothResult<Vec<u8>>>),
WriteValue(String, Vec<u8>, IpcSender<BluetoothResult<bool>>),
GetPrimaryService(String, String, IpcSender<BluetoothResponseResult>),
GetPrimaryServices(String, Option<String>, IpcSender<BluetoothResponseResult>),
GetIncludedService(String, String, IpcSender<BluetoothResponseResult>),
GetIncludedServices(String, Option<String>, IpcSender<BluetoothResponseResult>),
GetCharacteristic(String, String, IpcSender<BluetoothResponseResult>),
GetCharacteristics(String, Option<String>, IpcSender<BluetoothResponseResult>),
GetDescriptor(String, String, IpcSender<BluetoothResponseResult>),
GetDescriptors(String, Option<String>, IpcSender<BluetoothResponseResult>),
ReadValue(String, IpcSender<BluetoothResponseResult>),
WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
Test(String, IpcSender<BluetoothResult<()>>),
Exit,
}
#[derive(Deserialize, Serialize)]
pub enum BluetoothResponse {
RequestDevice(BluetoothDeviceMsg),
GATTServerConnect(bool),
GetPrimaryService(BluetoothServiceMsg),
GetPrimaryServices(BluetoothServicesMsg),
GetIncludedService(BluetoothServiceMsg),
GetIncludedServices(BluetoothServicesMsg),
GetCharacteristic(BluetoothCharacteristicMsg),
GetCharacteristics(BluetoothCharacteristicsMsg),
GetDescriptor(BluetoothDescriptorMsg),
GetDescriptors(BluetoothDescriptorsMsg),
ReadValue(Vec<u8>),
WriteValue(Vec<u8>),
}
pub trait BluetoothResponseListener {
fn response(&mut self, response: BluetoothResponseResult);
}

Просмотреть файл

@ -10,7 +10,7 @@
//! `LayoutThread`, and `PaintThread`.
use backtrace::Backtrace;
use bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use canvas::canvas_paint_thread::CanvasPaintThread;
use canvas::webgl_paint_thread::WebGLPaintThread;
use canvas_traits::CanvasMsg;
@ -121,7 +121,7 @@ pub struct Constellation<Message, LTF, STF> {
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
/// A channel through which messages can be sent to the bluetooth thread.
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
bluetooth_thread: IpcSender<BluetoothRequest>,
/// Sender to Service Worker Manager thread
swmanager_chan: Option<IpcSender<ServiceWorkerMsg>>,
@ -199,7 +199,7 @@ pub struct InitialConstellationState {
/// A channel to the developer tools, if applicable.
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
/// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
pub bluetooth_thread: IpcSender<BluetoothRequest>,
/// A channel to the image cache thread.
pub image_cache_thread: ImageCacheThread,
/// A channel to the font cache thread.
@ -1095,7 +1095,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
debug!("Exiting bluetooth thread.");
if let Err(e) = self.bluetooth_thread.send(BluetoothMethodMsg::Exit) {
if let Err(e) = self.bluetooth_thread.send(BluetoothRequest::Exit) {
warn!("Exit bluetooth thread failed ({})", e);
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use compositing::CompositionPipeline;
use compositing::CompositorProxy;
use compositing::compositor_thread::Msg as CompositorMsg;
@ -94,7 +94,7 @@ pub struct InitialPipelineState {
/// A channel to the developer tools, if applicable.
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
/// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
pub bluetooth_thread: IpcSender<BluetoothRequest>,
/// A channel to the service worker manager thread
pub swmanager_thread: IpcSender<SWManagerMsg>,
/// A channel to the image cache thread.
@ -384,7 +384,7 @@ pub struct UnprivilegedPipelineContent {
layout_to_constellation_chan: IpcSender<LayoutMsg>,
scheduler_chan: IpcSender<TimerEventRequest>,
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
bluetooth_thread: IpcSender<BluetoothRequest>,
swmanager_thread: IpcSender<SWManagerMsg>,
image_cache_thread: ImageCacheThread,
font_cache_thread: FontCacheThread,

Просмотреть файл

@ -10,6 +10,7 @@ name = "net_traits"
path = "lib.rs"
[dependencies]
bluetooth_traits = {path = "../bluetooth_traits"}
util = {path = "../util"}
msg = {path = "../msg"}
ipc-channel = "0.5"

Просмотреть файл

@ -9,6 +9,7 @@
#![deny(unsafe_code)]
extern crate bluetooth_traits;
extern crate cookie as cookie_rs;
extern crate heapsize;
#[macro_use] extern crate heapsize_derive;
@ -32,6 +33,7 @@ extern crate uuid;
extern crate webrender_traits;
extern crate websocket;
use bluetooth_traits::{BluetoothResponseListener, BluetoothResponseResult};
use cookie_rs::Cookie;
use filemanager_thread::FileManagerThreadMsg;
use heapsize::HeapSizeOf;
@ -291,6 +293,13 @@ impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
}
}
impl<T: BluetoothResponseListener> Action<T> for BluetoothResponseResult {
/// Execute the default action on a provided listener.
fn process(self, listener: &mut T) {
listener.response(self)
}
}
/// A wrapper for a network load that can either be channel or event-based.
#[derive(Deserialize, Serialize)]
pub enum LoadConsumer {

Просмотреть файл

@ -2,7 +2,8 @@
* 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::{BluetoothError, BluetoothMethodMsg};
use bluetooth_traits::{BluetoothError, BluetoothRequest};
use bluetooth_traits::{BluetoothResponse, BluetoothResponseListener, BluetoothResponseResult};
use bluetooth_traits::blacklist::{Blacklist, uuid_is_blacklisted};
use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence};
use bluetooth_traits::scanfilter::{RequestDeviceoptions, ServiceUUIDSequence};
@ -13,6 +14,7 @@ use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions;
use dom::bindings::error::Error::{self, NotFound, Security, Type};
use dom::bindings::error::Fallible;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
@ -24,9 +26,12 @@ use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
use js::conversions::ToJSValConvertible;
use ipc_channel::router::ROUTER;
use js::jsapi::{JSAutoCompartment, JSContext};
use network_listener::{NetworkListener, PreInvoke};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
const FILTER_EMPTY_ERROR: &'static str = "'filters' member, if present, must be nonempty to find any devices.";
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
@ -43,6 +48,33 @@ const SERVICE_ERROR: &'static str = "'services', if present, must contain at lea
const OPTIONS_ERROR: &'static str = "Fields of 'options' conflict with each other.
Either 'acceptAllDevices' member must be true, or 'filters' member must be set to a value.";
struct BluetoothContext<T: AsyncBluetoothListener + Reflectable> {
promise: Option<TrustedPromise>,
receiver: Trusted<T>,
}
pub trait AsyncBluetoothListener {
fn handle_response(&self, result: BluetoothResponse, cx: *mut JSContext, promise: &Rc<Promise>);
}
impl<Listener: AsyncBluetoothListener + Reflectable> PreInvoke for BluetoothContext<Listener> {}
impl<Listener: AsyncBluetoothListener + Reflectable> BluetoothResponseListener for BluetoothContext<Listener> {
#[allow(unrooted_must_root)]
fn response(&mut self, response: BluetoothResponseResult) {
let promise = self.promise.take().expect("bt promise is missing").root();
let promise_cx = promise.global().get_cx();
// JSAutoCompartment needs to be manually made.
// Otherwise, Servo will crash.
let _ac = JSAutoCompartment::new(promise_cx, promise.reflector().get_jsobject().get());
match response {
Ok(response) => self.receiver.root().handle_response(response, promise_cx, &promise),
Err(error) => promise.reject_error(promise_cx, Error::from(error)),
}
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
#[dom_struct]
pub struct Bluetooth {
@ -83,75 +115,55 @@ impl Bluetooth {
&self.descriptor_instance_map
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
fn request_device(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> {
// Step 1.
// TODO(#4282): Reject promise.
if (option.filters.is_some() && option.acceptAllDevices) ||
(option.filters.is_none() && !option.acceptAllDevices) {
return Err(Type(OPTIONS_ERROR.to_owned()));
}
// Step 2.
if !option.acceptAllDevices {
return self.request_bluetooth_devices(&option.filters, &option.optionalServices);
}
self.request_bluetooth_devices(&None, &option.optionalServices)
// TODO(#4282): Step 3-5: Reject and resolve promise.
}
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
fn request_bluetooth_devices(&self,
p: &Rc<Promise>,
filters: &Option<Vec<BluetoothRequestDeviceFilter>>,
optional_services: &Option<Vec<BluetoothServiceUUID>>)
-> Fallible<Root<BluetoothDevice>> {
optional_services: &Option<Vec<BluetoothServiceUUID>>) {
// TODO: Step 1: Triggered by user activation.
// Step 2.
let option = try!(convert_request_device_options(filters, optional_services));
let option = match convert_request_device_options(filters, optional_services) {
Ok(o) => o,
Err(e) => {
p.reject_error(p.global().get_cx(), e);
return;
}
};
// TODO: Step 3-5: Implement the permission API.
// Note: Steps 6-8 are implemented in
// components/net/bluetooth_thread.rs in request_device function.
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(BluetoothMethodMsg::RequestDevice(option, sender)).unwrap();
let device = receiver.recv().unwrap();
// TODO: Step 9-10: Implement the permission API.
// Step 11: This step is optional.
// Step 12-13.
match device {
Ok(device) => {
let mut device_instance_map = self.device_instance_map.borrow_mut();
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
return Ok(existing_device.get());
}
let ad_data = BluetoothAdvertisingData::new(&self.global(),
device.appearance,
device.tx_power,
device.rssi);
let bt_device = BluetoothDevice::new(&self.global(),
DOMString::from(device.id.clone()),
device.name.map(DOMString::from),
&ad_data,
&self);
device_instance_map.insert(device.id, MutHeap::new(&bt_device));
Ok(bt_device)
},
Err(error) => {
Err(Error::from(error))
},
}
let sender = response_async(p, self);
self.get_bluetooth_thread().send(BluetoothRequest::RequestDevice(option, sender)).unwrap();
}
}
pub fn response_async<T: AsyncBluetoothListener + Reflectable + 'static>(
promise: &Rc<Promise>,
receiver: &T) -> IpcSender<BluetoothResponseResult> {
let (action_sender, action_receiver) = ipc::channel().unwrap();
let chan = receiver.global().networking_task_source();
let context = Arc::new(Mutex::new(BluetoothContext {
promise: Some(TrustedPromise::new(promise.clone())),
receiver: Trusted::new(receiver),
}));
let listener = NetworkListener {
context: context,
script_chan: chan,
wrapper: None,
};
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
listener.notify_response(message.to().unwrap());
});
action_sender
}
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
fn convert_request_device_options(filters: &Option<Vec<BluetoothRequestDeviceFilter>>,
optional_services: &Option<Vec<BluetoothServiceUUID>>)
@ -300,18 +312,6 @@ fn canonicalize_filter(filter: &BluetoothRequestDeviceFilter) -> Fallible<Blueto
service_data_uuid))
}
#[allow(unrooted_must_root)]
pub fn result_to_promise<T: ToJSValConvertible>(global: &GlobalScope,
bluetooth_result: Fallible<T>)
-> Rc<Promise> {
let p = Promise::new(global);
match bluetooth_result {
Ok(v) => p.resolve_native(p.global().get_cx(), &v),
Err(e) => p.reject_error(p.global().get_cx(), e),
}
p
}
impl From<BluetoothError> for Error {
fn from(error: BluetoothError) -> Self {
match error {
@ -329,6 +329,45 @@ impl BluetoothMethods for Bluetooth {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
fn RequestDevice(&self, option: &RequestDeviceOptions) -> Rc<Promise> {
result_to_promise(&self.global(), self.request_device(option))
let p = Promise::new(&self.global());
// Step 1.
if (option.filters.is_some() && option.acceptAllDevices) ||
(option.filters.is_none() && !option.acceptAllDevices) {
p.reject_error(p.global().get_cx(), Error::Type(OPTIONS_ERROR.to_owned()));
return p;
}
// Step 2.
if !option.acceptAllDevices {
self.request_bluetooth_devices(&p, &option.filters, &option.optionalServices);
} else {
self.request_bluetooth_devices(&p, &None, &option.optionalServices);
}
// TODO(#4282): Step 3-5: Reject and resolve promise.
return p;
}
}
impl AsyncBluetoothListener for Bluetooth {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
BluetoothResponse::RequestDevice(device) => {
let mut device_instance_map = self.device_instance_map.borrow_mut();
if let Some(existing_device) = device_instance_map.get(&device.id.clone()) {
return promise.resolve_native(promise_cx, &existing_device.get());
}
let ad_data = BluetoothAdvertisingData::new(&self.global(),
device.appearance,
device.tx_power,
device.rssi);
let bt_device = BluetoothDevice::new(&self.global(),
DOMString::from(device.id.clone()),
device.name.map(DOMString::from),
&ad_data,
&self);
device_instance_map.insert(device.id, MutHeap::new(&bt_device));
promise.resolve_native(promise_cx, &bt_device);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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::BluetoothMethodMsg;
use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
use bluetooth_traits::blacklist::{Blacklist, uuid_is_blacklisted};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BluetoothCharacteristicPropertiesBinding::
@ -13,19 +13,19 @@ 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::{ErrorResult, Fallible};
use dom::bindings::error::Error::{self, InvalidModification, Network, NotSupported, Security};
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString};
use dom::bluetooth::result_to_promise;
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use std::rc::Rc;
// Maximum length of an attribute value.
@ -73,150 +73,13 @@ impl BluetoothRemoteGATTCharacteristic {
BluetoothRemoteGATTCharacteristicBinding::Wrap)
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
fn get_instance_id(&self) -> String {
self.instance_id.clone()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
fn get_descriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> {
let uuid = try!(BluetoothUUID::descriptor(descriptor)).to_string();
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
if !self.Service().Device().Gatt().Connected() {
return Err(Network)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetDescriptor(self.get_instance_id(), uuid, sender)).unwrap();
let descriptor = receiver.recv().unwrap();
match descriptor {
Ok(descriptor) => {
let context = self.service.get().get_device().get_context();
let mut descriptor_map = context.get_descriptor_map().borrow_mut();
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
return Ok(existing_descriptor.get());
}
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&self.global(),
self,
DOMString::from(descriptor.uuid),
descriptor.instance_id.clone());
descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor));
Ok(bt_descriptor)
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
fn get_descriptors(&self,
descriptor: Option<BluetoothDescriptorUUID>)
-> Fallible<Vec<Root<BluetoothRemoteGATTDescriptor>>> {
let mut uuid: Option<String> = None;
if let Some(d) = descriptor {
uuid = Some(try!(BluetoothUUID::descriptor(d)).to_string());
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
}
};
if !self.Service().Device().Gatt().Connected() {
return Err(Network)
}
let mut descriptors = vec!();
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetDescriptors(self.get_instance_id(), uuid, sender)).unwrap();
let descriptors_vec = receiver.recv().unwrap();
match descriptors_vec {
Ok(descriptor_vec) => {
let context = self.service.get().get_device().get_context();
let mut descriptor_map = context.get_descriptor_map().borrow_mut();
for descriptor in descriptor_vec {
let bt_descriptor = match descriptor_map.get(&descriptor.instance_id) {
Some(existing_descriptor) => existing_descriptor.get(),
None => {
BluetoothRemoteGATTDescriptor::new(&self.global(),
self,
DOMString::from(descriptor.uuid),
descriptor.instance_id.clone())
},
};
if !descriptor_map.contains_key(&descriptor.instance_id) {
descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor));
}
descriptors.push(bt_descriptor);
}
Ok(descriptors)
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
fn read_value(&self) -> Fallible<ByteString> {
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
return Err(Security)
}
let (sender, receiver) = ipc::channel().unwrap();
if !self.Service().Device().Gatt().Connected() {
return Err(Network)
}
if !self.Properties().Read() {
return Err(NotSupported)
}
self.get_bluetooth_thread().send(
BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
let result = receiver.recv().unwrap();
let value = match result {
Ok(val) => {
ByteString::new(val)
},
Err(error) => {
return Err(Error::from(error))
},
};
*self.value.borrow_mut() = Some(value.clone());
Ok(value)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
fn write_value(&self, value: Vec<u8>) -> ErrorResult {
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
return Err(Security)
}
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
return Err(InvalidModification)
}
if !self.Service().Device().Gatt().Connected() {
return Err(Network)
}
if !(self.Properties().Write() ||
self.Properties().WriteWithoutResponse() ||
self.Properties().AuthenticatedSignedWrites()) {
return Err(NotSupported)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::WriteValue(self.get_instance_id(), value.clone(), sender)).unwrap();
let result = receiver.recv().unwrap();
match result {
Ok(_) => Ok(*self.value.borrow_mut() = Some(ByteString::new(value))),
Err(error) => {
Err(Error::from(error))
},
}
}
}
impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic {
@ -238,7 +101,27 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Rc<Promise> {
result_to_promise(&self.global(), self.get_descriptor(descriptor))
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let uuid = match BluetoothUUID::descriptor(descriptor) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetDescriptor(self.get_instance_id(), uuid, sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
@ -246,7 +129,32 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
fn GetDescriptors(&self,
descriptor: Option<BluetoothDescriptorUUID>)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_descriptors(descriptor))
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(d) = descriptor {
uuid = match BluetoothUUID::descriptor(d) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetDescriptors(self.get_instance_id(), uuid, sender)).unwrap();
return p;
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
@ -257,12 +165,105 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
fn ReadValue(&self) -> Rc<Promise> {
result_to_promise(&self.global(), self.read_value())
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
p.reject_error(p_cx, Security);
return p;
}
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
if !self.Properties().Read() {
p.reject_error(p_cx, NotSupported);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
result_to_promise(&self.global(), self.write_value(value))
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
p.reject_error(p_cx, Security);
return p;
}
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
p.reject_error(p_cx, InvalidModification);
return p;
}
if !self.Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
if !(self.Properties().Write() ||
self.Properties().WriteWithoutResponse() ||
self.Properties().AuthenticatedSignedWrites()) {
p.reject_error(p_cx, NotSupported);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
return p;
}
}
impl AsyncBluetoothListener for BluetoothRemoteGATTCharacteristic {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
BluetoothResponse::GetDescriptor(descriptor) => {
let context = self.service.get().get_device().get_context();
let mut descriptor_map = context.get_descriptor_map().borrow_mut();
if let Some(existing_descriptor) = descriptor_map.get(&descriptor.instance_id) {
return promise.resolve_native(promise_cx, &existing_descriptor.get());
}
let bt_descriptor = BluetoothRemoteGATTDescriptor::new(&self.global(),
self,
DOMString::from(descriptor.uuid),
descriptor.instance_id.clone());
descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor));
promise.resolve_native(promise_cx, &bt_descriptor);
},
BluetoothResponse::GetDescriptors(descriptors_vec) => {
let mut descriptors = vec!();
let context = self.service.get().get_device().get_context();
let mut descriptor_map = context.get_descriptor_map().borrow_mut();
for descriptor in descriptors_vec {
let bt_descriptor = match descriptor_map.get(&descriptor.instance_id) {
Some(existing_descriptor) => existing_descriptor.get(),
None => {
BluetoothRemoteGATTDescriptor::new(&self.global(),
self,
DOMString::from(descriptor.uuid),
descriptor.instance_id.clone())
},
};
if !descriptor_map.contains_key(&descriptor.instance_id) {
descriptor_map.insert(descriptor.instance_id, MutHeap::new(&bt_descriptor));
}
descriptors.push(bt_descriptor);
}
promise.resolve_native(promise_cx, &descriptors);
},
BluetoothResponse::ReadValue(result) => {
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
promise.resolve_native(promise_cx, &value);
},
BluetoothResponse::WriteValue(result) => {
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
promise.resolve_native(promise_cx, &value);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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::BluetoothMethodMsg;
use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
use bluetooth_traits::blacklist::{Blacklist, uuid_is_blacklisted};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
@ -12,16 +12,16 @@ 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::{ErrorResult, Fallible};
use dom::bindings::error::Error::{self, InvalidModification, Network, Security};
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::{ByteString, DOMString};
use dom::bluetooth::result_to_promise;
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothremotegattcharacteristic::{BluetoothRemoteGATTCharacteristic, MAXIMUM_ATTRIBUTE_LENGTH};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use std::rc::Rc;
// http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor
@ -60,60 +60,13 @@ impl BluetoothRemoteGATTDescriptor {
BluetoothRemoteGATTDescriptorBinding::Wrap)
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
fn get_instance_id(&self) -> String {
self.instance_id.clone()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
fn read_value(&self) -> Fallible<ByteString> {
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
return Err(Security)
}
let (sender, receiver) = ipc::channel().unwrap();
if !self.Characteristic().Service().Device().Gatt().Connected() {
return Err(Network)
}
self.get_bluetooth_thread().send(
BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
let result = receiver.recv().unwrap();
let value = match result {
Ok(val) => {
ByteString::new(val)
},
Err(error) => {
return Err(Error::from(error))
},
};
*self.value.borrow_mut() = Some(value.clone());
Ok(value)
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
fn write_value(&self, value: Vec<u8>) -> ErrorResult {
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
return Err(Security)
}
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
return Err(InvalidModification)
}
if !self.Characteristic().Service().Device().Gatt().Connected() {
return Err(Network)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::WriteValue(self.get_instance_id(), value.clone(), sender)).unwrap();
let result = receiver.recv().unwrap();
match result {
Ok(_) => Ok(*self.value.borrow_mut() = Some(ByteString::new(value))),
Err(error) => {
Err(Error::from(error))
},
}
}
}
impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
@ -135,12 +88,60 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
fn ReadValue(&self) -> Rc<Promise> {
result_to_promise(&self.global(), self.read_value())
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
p.reject_error(p_cx, Security);
return p;
}
if !self.Characteristic().Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::ReadValue(self.get_instance_id(), sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
fn WriteValue(&self, value: Vec<u8>) -> Rc<Promise> {
result_to_promise(&self.global(), self.write_value(value))
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
p.reject_error(p_cx, Security);
return p;
}
if value.len() > MAXIMUM_ATTRIBUTE_LENGTH {
p.reject_error(p_cx, InvalidModification);
return p;
}
if !self.Characteristic().Service().Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::WriteValue(self.get_instance_id(), value, sender)).unwrap();
return p;
}
}
impl AsyncBluetoothListener for BluetoothRemoteGATTDescriptor {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
BluetoothResponse::ReadValue(result) => {
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
promise.resolve_native(promise_cx, &value);
},
BluetoothResponse::WriteValue(result) => {
let value = ByteString::new(result);
*self.value.borrow_mut() = Some(value.clone());
promise.resolve_native(promise_cx, &value);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
}
}

Просмотреть файл

@ -2,23 +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 bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
use bluetooth_traits::blacklist::{Blacklist, uuid_is_blacklisted};
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::error::{ErrorResult, Fallible};
use dom::bindings::error::Error::{self, Network, Security};
use dom::bindings::error::ErrorResult;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetooth::result_to_promise;
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothdevice::BluetoothDevice;
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::JSContext;
use std::cell::Cell;
use std::rc::Rc;
@ -45,109 +46,9 @@ impl BluetoothRemoteGATTServer {
BluetoothRemoteGATTServerBinding::Wrap)
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
fn connect(&self) -> Fallible<Root<BluetoothRemoteGATTServer>> {
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 {
Ok(connected) => {
self.connected.set(connected);
Ok(Root::from_ref(self))
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
fn get_primary_service(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> {
let uuid = try!(BluetoothUUID::service(service)).to_string();
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
if !self.Device().Gatt().Connected() {
return Err(Network)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetPrimaryService(String::from(self.Device().Id()), uuid, sender)).unwrap();
let service = receiver.recv().unwrap();
match service {
Ok(service) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
if let Some(existing_service) = service_map.get(&service.instance_id) {
return Ok(existing_service.get());
}
let bt_service = BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone());
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
Ok(bt_service)
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
fn get_primary_services(&self,
service: Option<BluetoothServiceUUID>)
-> Fallible<Vec<Root<BluetoothRemoteGATTService>>> {
let mut uuid: Option<String> = None;
if let Some(s) = service {
uuid = Some(try!(BluetoothUUID::service(s)).to_string());
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
}
};
if !self.Device().Gatt().Connected() {
return Err(Network)
}
let mut services = vec!();
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetPrimaryServices(String::from(self.Device().Id()), uuid, sender)).unwrap();
let services_vec = receiver.recv().unwrap();
match services_vec {
Ok(service_vec) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
for service in service_vec {
let bt_service = match service_map.get(&service.instance_id) {
Some(existing_service) => existing_service.get(),
None => {
BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone())
},
};
if !service_map.contains_key(&service.instance_id) {
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
}
services.push(bt_service);
}
Ok(services)
},
Err(error) => {
Err(Error::from(error))
},
}
}
}
impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
@ -164,14 +65,18 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
fn Connect(&self) -> Rc<Promise> {
result_to_promise(&self.global(), self.connect())
let p = Promise::new(&self.global());
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap();
return p;
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
fn Disconnect(&self) -> ErrorResult {
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap();
BluetoothRequest::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap();
let server = receiver.recv().unwrap();
match server {
Ok(connected) => {
@ -187,14 +92,105 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Rc<Promise> {
result_to_promise(&self.global(), self.get_primary_service(service))
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let uuid = match BluetoothUUID::service(service) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetPrimaryService(String::from(self.Device().Id()), uuid, sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
fn GetPrimaryServices(&self,
service: Option<BluetoothServiceUUID>)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_primary_services(service))
fn GetPrimaryServices(&self, service: Option<BluetoothServiceUUID>) -> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(s) = service {
uuid = match BluetoothUUID::service(s) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetPrimaryServices(String::from(self.Device().Id()), uuid, sender)).unwrap();
return p;
}
}
impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
BluetoothResponse::GATTServerConnect(connected) => {
self.connected.set(connected);
promise.resolve_native(promise_cx, self);
},
BluetoothResponse::GetPrimaryService(service) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
if let Some(existing_service) = service_map.get(&service.instance_id) {
promise.resolve_native(promise_cx, &existing_service.get());
}
let bt_service = BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone());
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
promise.resolve_native(promise_cx, &bt_service);
},
BluetoothResponse::GetPrimaryServices(services_vec) => {
let mut services = vec!();
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
for service in services_vec {
let bt_service = match service_map.get(&service.instance_id) {
Some(existing_service) => existing_service.get(),
None => {
BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone())
},
};
if !service_map.contains_key(&service.instance_id) {
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
}
services.push(bt_service);
}
promise.resolve_native(promise_cx, &services);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
}
}

Просмотреть файл

@ -2,25 +2,25 @@
* 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::BluetoothMethodMsg;
use bluetooth_traits::{BluetoothRequest, BluetoothResponse};
use bluetooth_traits::blacklist::{Blacklist, uuid_is_blacklisted};
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding;
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
use dom::bindings::error::Error::{self, Network, Security};
use dom::bindings::error::Fallible;
use dom::bindings::js::{JS, MutHeap, Root};
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bluetooth::result_to_promise;
use dom::bluetooth::{AsyncBluetoothListener, response_async};
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
use dom::bluetoothdevice::BluetoothDevice;
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothServiceUUID, BluetoothUUID};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use std::rc::Rc;
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
@ -66,87 +66,192 @@ impl BluetoothRemoteGATTService {
self.device.get()
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
fn get_instance_id(&self) -> String {
self.instance_id.clone()
}
}
impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device
fn Device(&self) -> Root<BluetoothDevice> {
self.device.get()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary
fn IsPrimary(&self) -> bool {
self.is_primary
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid
fn Uuid(&self) -> DOMString {
self.uuid.clone()
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
fn get_characteristic(&self,
characteristic: BluetoothCharacteristicUUID)
-> Fallible<Root<BluetoothRemoteGATTCharacteristic>> {
let uuid = try!(BluetoothUUID::characteristic(characteristic)).to_string();
fn GetCharacteristic(&self,
characteristic: BluetoothCharacteristicUUID)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let uuid = match BluetoothUUID::characteristic(characteristic) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
p.reject_error(p_cx, Security);
return p;
}
if !self.Device().Gatt().Connected() {
return Err(Network)
p.reject_error(p_cx, Network);
return p;
}
let (sender, receiver) = ipc::channel().unwrap();
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetCharacteristic(self.get_instance_id(), uuid, sender)).unwrap();
let characteristic = receiver.recv().unwrap();
match characteristic {
Ok(characteristic) => {
BluetoothRequest::GetCharacteristic(self.get_instance_id(), uuid, sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
fn GetCharacteristics(&self,
characteristic: Option<BluetoothCharacteristicUUID>)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(c) = characteristic {
uuid = match BluetoothUUID::characteristic(c) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetCharacteristics(self.get_instance_id(), uuid, sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
fn GetIncludedService(&self,
service: BluetoothServiceUUID)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let uuid = match BluetoothUUID::service(service) {
Ok(uuid) => uuid.to_string(),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetIncludedService(self.get_instance_id(),
uuid,
sender)).unwrap();
return p;
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
fn GetIncludedServices(&self,
service: Option<BluetoothServiceUUID>)
-> Rc<Promise> {
let p = Promise::new(&self.global());
let p_cx = p.global().get_cx();
let mut uuid: Option<String> = None;
if let Some(s) = service {
uuid = match BluetoothUUID::service(s) {
Ok(uuid) => Some(uuid.to_string()),
Err(e) => {
p.reject_error(p_cx, e);
return p;
}
};
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
p.reject_error(p_cx, Security);
return p;
}
}
};
if !self.Device().Gatt().Connected() {
p.reject_error(p_cx, Network);
return p;
}
let sender = response_async(&p, self);
self.get_bluetooth_thread().send(
BluetoothRequest::GetIncludedServices(self.get_instance_id(),
uuid,
sender)).unwrap();
return p;
}
}
impl AsyncBluetoothListener for BluetoothRemoteGATTService {
fn handle_response(&self, response: BluetoothResponse, promise_cx: *mut JSContext, promise: &Rc<Promise>) {
match response {
BluetoothResponse::GetCharacteristic(characteristic) => {
let context = self.device.get().get_context();
let mut characteristic_map = context.get_characteristic_map().borrow_mut();
if let Some(existing_characteristic) = characteristic_map.get(&characteristic.instance_id) {
return Ok(existing_characteristic.get());
return promise.resolve_native(promise_cx, &existing_characteristic.get());
}
let global = self.global();
let properties = BluetoothCharacteristicProperties::new(&global,
characteristic.broadcast,
characteristic.read,
characteristic.write_without_response,
characteristic.write,
characteristic.notify,
characteristic.indicate,
characteristic.authenticated_signed_writes,
characteristic.reliable_write,
characteristic.writable_auxiliaries);
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&global,
let properties =
BluetoothCharacteristicProperties::new(&self.global(),
characteristic.broadcast,
characteristic.read,
characteristic.write_without_response,
characteristic.write,
characteristic.notify,
characteristic.indicate,
characteristic.authenticated_signed_writes,
characteristic.reliable_write,
characteristic.writable_auxiliaries);
let bt_characteristic = BluetoothRemoteGATTCharacteristic::new(&self.global(),
self,
DOMString::from(characteristic.uuid),
&properties,
characteristic.instance_id.clone());
characteristic_map.insert(characteristic.instance_id, MutHeap::new(&bt_characteristic));
Ok(bt_characteristic)
promise.resolve_native(promise_cx, &bt_characteristic);
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
fn get_characteristics(&self,
characteristic: Option<BluetoothCharacteristicUUID>)
-> Fallible<Vec<Root<BluetoothRemoteGATTCharacteristic>>> {
let mut uuid: Option<String> = None;
if let Some(c) = characteristic {
uuid = Some(try!(BluetoothUUID::characteristic(c)).to_string());
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
}
};
if !self.Device().Gatt().Connected() {
return Err(Network)
}
let mut characteristics = vec!();
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetCharacteristics(self.get_instance_id(), uuid, sender)).unwrap();
let characteristics_vec = receiver.recv().unwrap();
match characteristics_vec {
Ok(characteristic_vec) => {
BluetoothResponse::GetCharacteristics(characteristics_vec) => {
let mut characteristics = vec!();
let context = self.device.get().get_context();
let mut characteristic_map = context.get_characteristic_map().borrow_mut();
for characteristic in characteristic_vec {
for characteristic in characteristics_vec {
let bt_characteristic = match characteristic_map.get(&characteristic.instance_id) {
Some(existing_characteristic) => existing_characteristic.get(),
None => {
@ -174,149 +279,29 @@ impl BluetoothRemoteGATTService {
}
characteristics.push(bt_characteristic);
}
Ok(characteristics)
promise.resolve_native(promise_cx, &characteristics);
},
Err(error) => {
Err(Error::from(error))
BluetoothResponse::GetIncludedService(service) => {
let s =
BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id);
promise.resolve_native(promise_cx, &s);
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
fn get_included_service(&self,
service: BluetoothServiceUUID)
-> Fallible<Root<BluetoothRemoteGATTService>> {
let uuid = try!(BluetoothUUID::service(service)).to_string();
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
if !self.Device().Gatt().Connected() {
return Err(Network)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetIncludedService(self.get_instance_id(),
uuid,
sender)).unwrap();
let service = receiver.recv().unwrap();
match service {
Ok(service) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
if let Some(existing_service) = service_map.get(&service.instance_id) {
return Ok(existing_service.get());
}
let bt_service = BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone());
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
Ok(bt_service)
},
Err(error) => {
Err(Error::from(error))
},
}
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
fn get_included_services(&self,
service: Option<BluetoothServiceUUID>)
-> Fallible<Vec<Root<BluetoothRemoteGATTService>>> {
let mut uuid: Option<String> = None;
if let Some(s) = service {
uuid = Some(try!(BluetoothUUID::service(s)).to_string());
if let Some(ref uuid) = uuid {
if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
return Err(Security)
}
}
};
if !self.Device().Gatt().Connected() {
return Err(Network)
}
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(
BluetoothMethodMsg::GetIncludedServices(self.get_instance_id(),
uuid,
sender)).unwrap();
let services_vec = receiver.recv().unwrap();
let mut services = vec!();
match services_vec {
Ok(service_vec) => {
let context = self.device.get().get_context();
let mut service_map = context.get_service_map().borrow_mut();
for service in service_vec {
let bt_service = match service_map.get(&service.instance_id) {
Some(existing_service) => existing_service.get(),
None => {
BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id.clone())
},
};
if !service_map.contains_key(&service.instance_id) {
service_map.insert(service.instance_id, MutHeap::new(&bt_service));
}
services.push(bt_service);
}
Ok(services)
},
Err(error) => {
Err(Error::from(error))
BluetoothResponse::GetIncludedServices(services_vec) => {
let s: Vec<Root<BluetoothRemoteGATTService>> =
services_vec.into_iter()
.map(|service| BluetoothRemoteGATTService::new(&self.global(),
&self.device.get(),
DOMString::from(service.uuid),
service.is_primary,
service.instance_id))
.collect();
promise.resolve_native(promise_cx, &s);
},
_ => promise.reject_error(promise_cx, Error::Type("Something went wrong...".to_owned())),
}
}
}
impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-device
fn Device(&self) -> Root<BluetoothDevice> {
self.device.get()
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-isprimary
fn IsPrimary(&self) -> bool {
self.is_primary
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-uuid
fn Uuid(&self) -> DOMString {
self.uuid.clone()
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
fn GetCharacteristic(&self,
characteristic: BluetoothCharacteristicUUID)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_characteristic(characteristic))
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
fn GetCharacteristics(&self,
characteristic: Option<BluetoothCharacteristicUUID>)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_characteristics(characteristic))
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservice
fn GetIncludedService(&self,
service: BluetoothServiceUUID)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_included_service(service))
}
#[allow(unrooted_must_root)]
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getincludedservices
fn GetIncludedServices(&self,
service: Option<BluetoothServiceUUID>)
-> Rc<Promise> {
result_to_promise(&self.global(), self.get_included_services(service))
}
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use dom::bindings::codegen::Bindings::TestRunnerBinding;
use dom::bindings::codegen::Bindings::TestRunnerBinding::TestRunnerMethods;
use dom::bindings::error::{Error, ErrorResult};
@ -31,7 +31,7 @@ impl TestRunner {
TestRunnerBinding::Wrap)
}
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
}
@ -40,7 +40,7 @@ impl TestRunnerMethods for TestRunner {
// https://webbluetoothcg.github.io/web-bluetooth/tests#setBluetoothMockDataSet
fn SetBluetoothMockDataSet(&self, dataSetName: DOMString) -> ErrorResult {
let (sender, receiver) = ipc::channel().unwrap();
self.get_bluetooth_thread().send(BluetoothMethodMsg::Test(String::from(dataSetName), sender)).unwrap();
self.get_bluetooth_thread().send(BluetoothRequest::Test(String::from(dataSetName), sender)).unwrap();
match receiver.recv().unwrap().into() {
Ok(()) => {
Ok(())

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use app_units::Au;
use bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use cssparser::Parser;
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use dom::bindings::callback::ExceptionHandling;
@ -203,7 +203,7 @@ pub struct Window {
/// A handle for communicating messages to the bluetooth thread.
#[ignore_heap_size_of = "channels are hard"]
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
bluetooth_thread: IpcSender<BluetoothRequest>,
/// Pending scroll to fragment event, if any
fragment_name: DOMRefCell<Option<String>>,
@ -304,7 +304,7 @@ impl Window {
self.browsing_context.get().unwrap()
}
pub fn bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
pub fn bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.bluetooth_thread.clone()
}
@ -1521,7 +1521,7 @@ impl Window {
image_cache_chan: ImageCacheChan,
image_cache_thread: ImageCacheThread,
resource_threads: ResourceThreads,
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
bluetooth_thread: IpcSender<BluetoothRequest>,
mem_profiler_chan: mem::ProfilerChan,
time_profiler_chan: ProfilerChan,
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,

Просмотреть файл

@ -2,6 +2,7 @@
* 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::{BluetoothResponseListener, BluetoothResponseResult};
use net_traits::{Action, FetchResponseListener, FetchResponseMsg};
use script_runtime::{CommonScriptMsg, ScriptChan};
use script_runtime::ScriptThreadEventCategory::NetworkEvent;
@ -40,6 +41,13 @@ impl<Listener: FetchResponseListener + PreInvoke + Send + 'static> NetworkListen
}
}
// helps type inference
impl<Listener: BluetoothResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
pub fn notify_response(&self, action: BluetoothResponseResult) {
self.notify(action);
}
}
/// A gating mechanism that runs before invoking the runnable on the target thread.
/// If the `should_invoke` method returns false, the runnable is discarded without
/// being invoked.

Просмотреть файл

@ -17,7 +17,7 @@
//! a page runs its course and the script thread returns to processing events in the main event
//! loop.
use bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use devtools;
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
@ -343,7 +343,7 @@ pub struct ScriptThread {
/// there are many iframes.
resource_threads: ResourceThreads,
/// A handle to the bluetooth thread.
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
bluetooth_thread: IpcSender<BluetoothRequest>,
/// The port on which the script thread receives messages (load URL, exit, etc.)
port: Receiver<MainThreadScriptMsg>,

Просмотреть файл

@ -38,7 +38,7 @@ extern crate url;
mod script_msg;
pub mod webdriver_msg;
use bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use euclid::Size2D;
use euclid::length::Length;
@ -445,7 +445,7 @@ pub struct InitialScriptState {
/// A channel to the resource manager thread.
pub resource_threads: ResourceThreads,
/// A channel to the bluetooth thread.
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
pub bluetooth_thread: IpcSender<BluetoothRequest>,
/// A channel to the image cache thread.
pub image_cache_thread: ImageCacheThread,
/// A channel to the time profiler thread.

1
servo/components/servo/Cargo.lock сгенерированный
Просмотреть файл

@ -1571,6 +1571,7 @@ dependencies = [
name = "net_traits"
version = "0.0.1"
dependencies = [
"bluetooth_traits 0.0.1",
"cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",

Просмотреть файл

@ -64,7 +64,7 @@ fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }
use bluetooth::BluetoothThreadFactory;
use bluetooth_traits::BluetoothMethodMsg;
use bluetooth_traits::BluetoothRequest;
use compositing::{CompositorProxy, IOCompositor};
use compositing::compositor_thread::InitialCompositorState;
use compositing::windowing::WindowEvent;
@ -247,7 +247,7 @@ fn create_constellation(opts: opts::Opts,
supports_clipboard: bool,
webrender_api_sender: webrender_traits::RenderApiSender)
-> (Sender<ConstellationMsg>, SWManagerSenders) {
let bluetooth_thread: IpcSender<BluetoothMethodMsg> = BluetoothThreadFactory::new();
let bluetooth_thread: IpcSender<BluetoothRequest> = BluetoothThreadFactory::new();
let (public_resource_threads, private_resource_threads) =
new_resource_threads(opts.user_agent,

1
servo/ports/cef/Cargo.lock сгенерированный
Просмотреть файл

@ -1447,6 +1447,7 @@ dependencies = [
name = "net_traits"
version = "0.0.1"
dependencies = [
"bluetooth_traits 0.0.1",
"cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",