Files
CGH0S7 6675986579
Some checks failed
Rust / Clippy (push) Has been cancelled
Rust / Test (nightly) (push) Has been cancelled
Rust / Test (stable) (push) Has been cancelled
first commit
2026-01-04 16:50:19 +08:00

90 lines
2.5 KiB
Rust

use std::time::Duration;
use anyhow::Result;
use bluer::{Address, Device, Session};
use bluer::rfcomm::{ProfileHandle, Role, ReqError, Stream, Profile};
use futures::StreamExt;
use maestro::pwrpc::Error;
use maestro::pwrpc::client::Client;
use maestro::pwrpc::types::RpcPacket;
pub async fn run_client<S, E>(mut client: Client<S>) -> Result<()>
where
S: futures::Sink<RpcPacket>,
S: futures::Stream<Item = Result<RpcPacket, E>> + Unpin,
Error: From<E>,
Error: From<S::Error>,
{
tokio::select! {
res = client.run() => {
res?;
},
sig = tokio::signal::ctrl_c() => {
sig?;
tracing::trace!("client termination requested");
},
}
client.terminate().await?;
Ok(())
}
pub async fn connect_maestro_rfcomm(session: &Session, dev: &Device) -> Result<Stream> {
let maestro_profile = Profile {
uuid: maestro::UUID,
role: Some(Role::Client),
require_authentication: Some(false),
require_authorization: Some(false),
auto_connect: Some(false),
..Default::default()
};
tracing::debug!("registering maestro profile");
let mut handle = session.register_profile(maestro_profile).await?;
tracing::debug!("connecting to maestro profile");
let stream = tokio::try_join!(
try_connect_profile(dev),
handle_requests_for_profile(&mut handle, dev.address()),
)?.1;
Ok(stream)
}
async fn try_connect_profile(dev: &Device) -> Result<()> {
const RETRY_TIMEOUT: Duration = Duration::from_secs(1);
const MAX_TRIES: u32 = 3;
let mut i = 0;
while let Err(err) = dev.connect_profile(&maestro::UUID).await {
if i >= MAX_TRIES { return Err(err.into()) }
i += 1;
tracing::warn!(error=?err, "connecting to profile failed, trying again ({}/{})", i, MAX_TRIES);
tokio::time::sleep(RETRY_TIMEOUT).await;
}
tracing::debug!(address=%dev.address(), "maestro profile connected");
Ok(())
}
async fn handle_requests_for_profile(handle: &mut ProfileHandle, address: Address) -> Result<Stream> {
while let Some(req) = handle.next().await {
tracing::debug!(address=%req.device(), "received new profile connection request");
if req.device() == address {
tracing::debug!(address=%req.device(), "accepting profile connection request");
return Ok(req.accept()?);
} else {
req.reject(ReqError::Rejected);
}
}
anyhow::bail!("profile terminated without requests")
}