mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
[fp-rs] Implemented custom error types for Bluetooth library.
This commit is contained in:
@@ -20,11 +20,11 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
futures = { version = "0.3", features = ["executor"] }
|
||||
tracing = "0.1.37"
|
||||
cfg-if = "1.0.0"
|
||||
async-trait = "0.1"
|
||||
thiserror = "1.0.43"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.48", features = [
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::Device;
|
||||
use super::{BluetoothError, Device};
|
||||
|
||||
/// Concrete types implementing this trait are Bluetooth Central devices.
|
||||
/// They provide methods for retrieving nearby connections and device info.
|
||||
@@ -23,14 +23,14 @@ pub trait Adapter: Sized {
|
||||
type Device: Device;
|
||||
|
||||
/// Retrieve the system-default Bluetooth adapter.
|
||||
async fn default() -> Result<Self, anyhow::Error>;
|
||||
async fn default() -> Result<Self, BluetoothError>;
|
||||
|
||||
/// Begin scanning for nearby devices.
|
||||
fn start_scan_devices(&mut self) -> Result<(), anyhow::Error>;
|
||||
fn start_scan_devices(&mut self) -> Result<(), BluetoothError>;
|
||||
|
||||
/// Stop scanning for nearby devices.
|
||||
fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error>;
|
||||
fn stop_scan_devices(&mut self) -> Result<(), BluetoothError>;
|
||||
|
||||
/// Poll next discovered device.
|
||||
async fn next_device(&mut self) -> Result<Self::Device, anyhow::Error>;
|
||||
async fn next_device(&mut self) -> Result<Self::Device, BluetoothError>;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
/// Concrete types implementing this trait represent Bluetooth Peripheral devices.
|
||||
/// They provide methods for retrieving device info and running device actions,
|
||||
/// such as pairing.
|
||||
use super::BluetoothError;
|
||||
|
||||
pub trait Device {
|
||||
/// Retrieve the name advertised by this device.
|
||||
fn name(&self) -> Result<String, anyhow::Error>;
|
||||
fn name(&self) -> Result<String, BluetoothError>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Library error type.
|
||||
#[non_exhaustive]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BluetoothError {
|
||||
/// Indicates that the operation was rejected because the system is not in
|
||||
/// a state required for the operation's execution.
|
||||
/// E.g. The user calls `stop_scan()` or polls the advertisement stream
|
||||
/// before calling `start_scan()`.
|
||||
#[error("failed precondition: {0}")]
|
||||
FailedPrecondition(String),
|
||||
/// Reported when the user calls an operation that is supported by their
|
||||
/// Operating System, but is not supported by their device.
|
||||
/// E.g. a Windows machine with an old BT Classic adapter that
|
||||
/// doesn't support BLE).
|
||||
#[error("bluetooth operation not supported by system: {0}")]
|
||||
NotSupported(String),
|
||||
/// Wrapper around OS-level errors, e.g. `windows::core::Error` for Windows.
|
||||
/// These typically mean something is very wrong with the system (e.g. OOM).
|
||||
#[error("bluetooth system-level error: {0}")]
|
||||
System(String),
|
||||
/// Reported when a bug occurs inside the library. Whenever a seemingly
|
||||
/// impossible error condition arises where you could call `expect()`,
|
||||
/// return this error instead.
|
||||
#[error("internal error: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
/// Module for shared functionality between all Bluetooth platforms.
|
||||
mod adapter;
|
||||
mod device;
|
||||
mod error;
|
||||
|
||||
pub use adapter::*;
|
||||
pub use device::*;
|
||||
pub use error::*;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pub mod common;
|
||||
|
||||
pub use common::{Adapter, Device};
|
||||
pub use common::{Adapter, BluetoothError, Device};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
@@ -30,6 +30,6 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn default_adapter() -> Result<impl Adapter, anyhow::Error> {
|
||||
pub async fn default_adapter() -> Result<impl Adapter, BluetoothError> {
|
||||
BleAdapter::default().await
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::BleDevice;
|
||||
use crate::bluetooth::common::Adapter;
|
||||
use crate::bluetooth::common::{Adapter, BluetoothError};
|
||||
|
||||
/// Concrete type implementing `Adapter`, used for unsupported devices.
|
||||
/// Every method should panic.
|
||||
@@ -25,19 +25,19 @@ pub struct BleAdapter;
|
||||
impl Adapter for BleAdapter {
|
||||
type Device = BleDevice;
|
||||
|
||||
async fn default() -> Result<Self, anyhow::Error> {
|
||||
async fn default() -> Result<Self, BluetoothError> {
|
||||
panic!("Unsupported target platform.");
|
||||
}
|
||||
|
||||
fn start_scan_devices(&mut self) -> Result<(), anyhow::Error> {
|
||||
fn start_scan_devices(&mut self) -> Result<(), BluetoothError> {
|
||||
panic!("Unsupported target platform.");
|
||||
}
|
||||
|
||||
fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error> {
|
||||
fn stop_scan_devices(&mut self) -> Result<(), BluetoothError> {
|
||||
panic!("Unsupported target platform.");
|
||||
}
|
||||
|
||||
async fn next_device(&mut self) -> Result<Self::Device, anyhow::Error> {
|
||||
async fn next_device(&mut self) -> Result<Self::Device, BluetoothError> {
|
||||
panic!("Unsupported target platform.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::bluetooth::common::Device;
|
||||
use crate::bluetooth::common::{BluetoothError, Device};
|
||||
|
||||
/// Concrete type implementing `Device`, used for unsupported devices.
|
||||
/// Every method should panic.
|
||||
pub struct BleDevice;
|
||||
|
||||
impl Device for BleDevice {
|
||||
fn name(&self) -> Result<String, anyhow::Error> {
|
||||
fn name(&self) -> Result<String, BluetoothError> {
|
||||
panic!("Unsupported target platform.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ use windows::{
|
||||
};
|
||||
|
||||
use super::BleDevice;
|
||||
use crate::bluetooth::common::Adapter;
|
||||
use crate::bluetooth::common::{Adapter, BluetoothError};
|
||||
|
||||
/// Concrete type implementing `Adapter`, used for Windows BLE.
|
||||
pub struct BleAdapter {
|
||||
@@ -71,18 +71,18 @@ pub struct BleAdapter {
|
||||
impl Adapter for BleAdapter {
|
||||
type Device = BleDevice;
|
||||
|
||||
async fn default() -> Result<Self, anyhow::Error> {
|
||||
async fn default() -> Result<Self, BluetoothError> {
|
||||
let inner = BluetoothAdapter::GetDefaultAsync()?.await?;
|
||||
|
||||
if !inner.IsLowEnergySupported()? {
|
||||
return Err(anyhow::anyhow!(
|
||||
"This device's Bluetooth Adapter doesn't support Bluetooth LE Transport type."
|
||||
));
|
||||
return Err(BluetoothError::NotSupported(String::from(
|
||||
"LE transport type",
|
||||
)));
|
||||
}
|
||||
if !inner.IsCentralRoleSupported()? {
|
||||
return Err(anyhow::anyhow!(
|
||||
"This device's Bluetooth Adapter doesn't support Bluetooth LE central role."
|
||||
));
|
||||
return Err(BluetoothError::NotSupported(String::from(
|
||||
"central role",
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(BleAdapter {
|
||||
@@ -91,7 +91,7 @@ impl Adapter for BleAdapter {
|
||||
})
|
||||
}
|
||||
|
||||
fn start_scan_devices(&mut self) -> Result<(), anyhow::Error> {
|
||||
fn start_scan_devices(&mut self) -> Result<(), BluetoothError> {
|
||||
let watcher = BluetoothLEAdvertisementWatcher::new()?;
|
||||
match watcher.SetScanningMode(BluetoothLEScanningMode::Active) {
|
||||
Ok(_) => (),
|
||||
@@ -194,23 +194,29 @@ impl Adapter for BleAdapter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_scan_devices(&mut self) -> Result<(), anyhow::Error> {
|
||||
fn stop_scan_devices(&mut self) -> Result<(), BluetoothError> {
|
||||
if let Some(_) = &self.device_stream {
|
||||
self.device_stream.take();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Device scanning hasn't started."))
|
||||
Err(BluetoothError::FailedPrecondition(String::from(
|
||||
"device scanning hasn't started, please call `start_scan()`",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
async fn next_device(&mut self) -> Result<Self::Device, anyhow::Error> {
|
||||
async fn next_device(&mut self) -> Result<Self::Device, BluetoothError> {
|
||||
if let Some(stream) = &mut self.device_stream {
|
||||
stream
|
||||
.next()
|
||||
.await
|
||||
.ok_or(anyhow::anyhow!("Device returned from stream is None."))
|
||||
.ok_or(BluetoothError::Internal(String::from(
|
||||
"device returned from Stream is None",
|
||||
)))
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Device scanning hasn't started."))
|
||||
Err(BluetoothError::FailedPrecondition(String::from(
|
||||
"device scanning hasn't started, please call `start_scan()`",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use windows::Devices::Bluetooth::{
|
||||
BluetoothLEDevice,
|
||||
};
|
||||
|
||||
use crate::bluetooth::common::Device;
|
||||
use crate::bluetooth::common::{BluetoothError, Device};
|
||||
|
||||
/// Concrete type implementing `Device`, used for Windows BLE.
|
||||
pub struct BleDevice {
|
||||
@@ -35,7 +35,7 @@ impl BleDevice {
|
||||
pub(super) async fn from_addr(
|
||||
addr: u64,
|
||||
kind: BluetoothAddressType,
|
||||
) -> Result<Self, anyhow::Error> {
|
||||
) -> Result<Self, BluetoothError> {
|
||||
let inner =
|
||||
BluetoothLEDevice::FromBluetoothAddressWithBluetoothAddressTypeAsync(addr, kind)?
|
||||
.await?;
|
||||
@@ -46,7 +46,7 @@ impl BleDevice {
|
||||
|
||||
#[async_trait]
|
||||
impl Device for BleDevice {
|
||||
fn name(&self) -> Result<String, anyhow::Error> {
|
||||
fn name(&self) -> Result<String, BluetoothError> {
|
||||
Ok(self.inner.Name()?.to_string_lossy())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::bluetooth::common::BluetoothError;
|
||||
|
||||
impl From<windows::core::Error> for BluetoothError {
|
||||
fn from(err: windows::core::Error) -> Self {
|
||||
BluetoothError::System(err.to_string())
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
/// Bluetooth LE module for Windows devices.
|
||||
mod adapter;
|
||||
mod device;
|
||||
mod error;
|
||||
|
||||
pub use adapter::*;
|
||||
pub use device::*;
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use futures::executor;
|
||||
|
||||
mod bluetooth;
|
||||
|
||||
use bluetooth::{Adapter, Device};
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let run = async {
|
||||
let mut adapter = bluetooth::default_adapter().await?;
|
||||
adapter.start_scan_devices()?;
|
||||
|
||||
Reference in New Issue
Block a user