refactor state refresh mechanism.

This commit is contained in:
Vixalie 2025-02-26 06:38:13 +08:00
parent 4f5420b658
commit d9a4f92c04
4 changed files with 90 additions and 52 deletions

View File

@ -27,7 +27,7 @@ pub async fn handle_bluetooth_events(
while let Some(event) = event_stream.next().await {
match event {
btleplug::api::CentralEvent::DeviceDiscovered(_id) => {
app.emit("app_state_updated", ()).unwrap();
app.emit("peripheral_found", ()).unwrap();
}
btleplug::api::CentralEvent::DeviceConnected(_id) => {
let state = app_state.write().await;
@ -36,7 +36,7 @@ pub async fn handle_bluetooth_events(
for peripheral in peripherals {
if peripheral.id() == _id {
state.set_connected_peripheral(peripheral).await;
app.emit("app_state_updated", ()).unwrap();
app.emit("peripheral_connected", ()).unwrap();
break;
}
}
@ -45,14 +45,14 @@ pub async fn handle_bluetooth_events(
btleplug::api::CentralEvent::DeviceDisconnected(_id) => {
let state = app_state.write().await;
state.clear_connected_peripheral().await;
app.emit("app_state_updated", ()).unwrap();
app.emit("peripheral_disconnected", ()).unwrap();
}
_ => {}
}
}
}))
} else {
app.emit("app_state_updated", ()).unwrap();
app.emit("central_state_updated", ()).unwrap();
Err(errors::AppError::BluetoothNotReady)
}
}
@ -91,8 +91,8 @@ pub async fn start_scan(
.start_scan(ScanFilter::default())
.await
.map_err(|_| errors::AppError::UnableToStartScan)?;
app_handle.emit("app_state_updated", ()).unwrap();
state.set_scanning(true).await;
app_handle.emit("scanning_started", ()).unwrap();
Ok(())
} else {
Err(errors::AppError::NoAvailableBluetoothAdapter)
@ -110,8 +110,8 @@ pub async fn stop_scan(
.stop_scan()
.await
.map_err(|_| errors::AppError::UnableToStopScan)?;
app_handle.emit("app_state_updated", ()).unwrap();
state.set_scanning(false).await;
app_handle.emit("scanning_stopped", ()).unwrap();
Ok(())
} else {
Err(errors::AppError::NoAvailableBluetoothAdapter)

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use btleplug::api::{Central as _, Peripheral as _};
use state::{ApplicationState, CentralState, ChannelState, PeripheralItem};
use state::{CentralState, ChannelState, PeripheralItem};
use tauri::{async_runtime::RwLock, AppHandle, Emitter, State};
use crate::{bluetooth, errors, state::AppState};
@ -23,28 +23,81 @@ pub async fn activate_central_adapter(
let handle =
bluetooth::handle_bluetooth_events(Arc::clone(&app), Arc::clone(&app_state)).await?;
{
let state = app_state.write().await; // Changed from lock() to write()
let state = app_state.write().await;
state.set_central_event_handler(handle).await;
}
app.emit("app_state_updated", ()).unwrap();
app.emit("central_state_updated", ()).unwrap();
Ok(())
}
#[tauri::command]
pub async fn refresh_application_state(
pub async fn central_device_state(
app_state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<ApplicationState, errors::AppError> {
) -> Result<CentralState, errors::AppError> {
let state = app_state.read().await;
let mut peripherals: Vec<PeripheralItem> = vec![];
let mut connected_peripheral = None;
let central = state.get_central_adapter().await;
let central_state = if let Some(central) = central {
if let Some(central) = central {
let central_device_state = central
.adapter_state()
.await
.map_err(|_| errors::AppError::BluetoothNotReady)?;
Ok(CentralState {
is_ready: central_device_state == btleplug::api::CentralState::PoweredOn,
is_scanning: *state.scanning.lock().await,
connected: state
.connected_peripheral
.lock()
.await
.clone()
.map(|p| p.id()),
})
} else {
Ok(CentralState::default())
}
}
#[tauri::command]
pub async fn connected_peripheral_state(
app_state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<Option<PeripheralItem>, errors::AppError> {
let state = app_state.read().await;
let connected_peripheral = state.connected_peripheral.lock().await.clone();
if let Some(peripheral) = connected_peripheral {
let properties = peripheral
.properties()
.await
.map_err(|_| errors::AppError::UnableToRetrievePeripheralProperties)?;
if let Some(properties) = properties {
let represent = properties
.local_name
.unwrap_or_else(|| properties.address.to_string());
Ok(Some(PeripheralItem {
id: peripheral.id(),
address: properties.address.to_string(),
represent,
is_connected: peripheral
.is_connected()
.await
.map_err(|_| errors::AppError::UnableToRetrievePeripheralProperties)?,
rssi: properties.rssi,
battery: properties.tx_power_level,
}))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
#[tauri::command]
pub async fn found_peripherals(
app_state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<Vec<PeripheralItem>, errors::AppError> {
let state = app_state.read().await;
let central = state.get_central_adapter().await;
let mut peripherals: Vec<PeripheralItem> = vec![];
if let Some(central) = central {
let found_peripherals = central
.peripherals()
.await
@ -69,38 +122,25 @@ pub async fn refresh_application_state(
rssi: properties.rssi,
battery: properties.tx_power_level,
};
if peripheral
.is_connected()
.await
.map_err(|_| errors::AppError::UnableToRetrievePeripheralState)?
{
connected_peripheral = Some(item.clone());
}
peripherals.push(item);
}
}
}
Ok(peripherals)
}
CentralState {
is_ready: central_device_state == btleplug::api::CentralState::PoweredOn,
is_scanning: *state.scanning.lock().await,
connected: state
.connected_peripheral
.lock()
.await
.clone()
.map(|p| p.id()),
}
} else {
CentralState::default()
};
#[tauri::command]
pub async fn channel_a_state(
_app_state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<ChannelState, errors::AppError> {
Ok(ChannelState::default())
}
Ok(ApplicationState {
central: central_state,
peripherals,
connected_peripheral,
channel_a: ChannelState::default(),
channel_b: ChannelState::default(),
})
#[tauri::command]
pub async fn channel_b_state(
_app_state: State<'_, Arc<RwLock<AppState>>>,
) -> Result<ChannelState, errors::AppError> {
Ok(ChannelState::default())
}
#[tauri::command]

View File

@ -4,6 +4,7 @@ use serde::Serialize;
use crate::playlist::PlayMode;
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CentralState {
pub is_ready: bool,
pub is_scanning: bool,
@ -11,6 +12,7 @@ pub struct CentralState {
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PeripheralItem {
pub id: PeripheralId,
pub address: String,
@ -21,6 +23,7 @@ pub struct PeripheralItem {
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ChannelState {
pub is_playing: bool,
pub strength: u32,
@ -30,12 +33,3 @@ pub struct ChannelState {
pub boost_limit: u32,
pub play_mode: PlayMode,
}
#[derive(Debug, Clone, Serialize)]
pub struct ApplicationState {
pub central: CentralState,
pub peripherals: Vec<PeripheralItem>,
pub connected_peripheral: Option<PeripheralItem>,
pub channel_a: ChannelState,
pub channel_b: ChannelState,
}

View File

@ -53,7 +53,11 @@ pub fn run() {
Ok(())
})
.invoke_handler(generate_handler![
cmd::refresh_application_state,
cmd::central_device_state,
cmd::connected_peripheral_state,
cmd::found_peripherals,
cmd::channel_a_state,
cmd::channel_b_state,
cmd::activate_central_adapter,
cmd::start_scan_devices,
cmd::stop_scan_devices