Skip to content

Commit

Permalink
added scanning state handler
Browse files Browse the repository at this point in the history
  • Loading branch information
MnlPhlp committed Nov 24, 2024
1 parent 1b09bac commit ecfa563
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 26 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tauri-plugin-blec"
license = "MIT OR Apache-2.0"
version = "0.1.6"
version = "0.2.0"
authors = ["Manuel Philipp"]
description = "BLE-Client plugin for Tauri"
edition = "2021"
Expand Down
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const COMMANDS: &[&str] = &[
"subscribe",
"subscribe_string",
"unsubscribe",
"scanning_state",
];

fn main() {
Expand Down
3 changes: 2 additions & 1 deletion examples/plugin-blec-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"tauri": "tauri"
},
"dependencies": {
"@mnlphlp/plugin-blec": ">=0.1.1",
"@mnlphlp/plugin-blec": ">=0.3.0",
"@saeris/vue-spinners": "^1.0.8",
"@tauri-apps/api": ">=2.0.0",
"@tauri-apps/plugin-log": "~2",
"@tauri-apps/plugin-shell": ">=2.0.0",
Expand Down
107 changes: 87 additions & 20 deletions examples/plugin-blec-example/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import { BleDevice, getConnectionUpdates, startScan, sendString, readString, unsubscribe, subscribeString, stopScan, connect, disconnect } from '@mnlphlp/plugin-blec'
import { BleDevice, getConnectionUpdates, startScan, sendString, readString, unsubscribe, subscribeString, stopScan, connect, disconnect, getScanningUpdates } from '@mnlphlp/plugin-blec'
import { onMounted, ref } from 'vue';
import BleDev from './components/BleDev.vue'
import { invoke } from '@tauri-apps/api/core';
import { invoke } from '@tauri-apps/api/core'
import { BarLoader } from '@saeris/vue-spinners'
const devices = ref<BleDevice[]>([])
const connected = ref(false)
const scanning = ref(false)
onMounted(async () => {
await getConnectionUpdates((state) => connected.value = state)
await getScanningUpdates((state) => {
console.log('Scanning:', state)
scanning.value = state
})
})
// const SERVICE_UUID = 'A07498CA-AD5B-474E-940D-16F1FBE7E8CD'
Expand Down Expand Up @@ -44,9 +51,19 @@ async function test() {
<template>
<div class="container">
<h1>Welcome to the blec plugin!</h1>
<button :onclick="() => startScan((dev: BleDevice[]) => devices = dev, 10000)" style="margin-bottom: 5px;">Start
Scan</button>
<button :onclick="stopScan" style="margin-bottom: 5px;">Stop Scan</button>

<button v-if="scanning" :onclick="stopScan" style="margin-bottom: 5px;">
Stop Scan
<div class="lds-ring">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</button>
<button v-else :onclick="() => startScan((dev: BleDevice[]) => devices = dev, 10000)" style="margin-bottom: 5px;">
Start Scan
</button>
<div v-if="connected">
<p>Connected</p>
<div class="row">
Expand All @@ -71,7 +88,8 @@ async function test() {
</div>
</div>
<div v-else v-for="device in devices" class="row">
<BleDev :key="device.address" :device="device" :onclick="() => connect(device.address, () => console.log('disconnected'))" />
<BleDev :key="device.address" :device="device"
:onclick="() => connect(device.address, () => console.log('disconnected'))" />
</div>
</div>
</template>
Expand Down Expand Up @@ -182,24 +200,73 @@ button {
margin-right: 5px;
}
@media (prefers-color-scheme: dark) {
:root {
color: #f6f6f6;
background-color: #2f2f2f;
}
:root {
color: #f6f6f6;
background-color: #2f2f2f;
}
a:hover {
color: #24c8db;
}
a:hover {
color: #24c8db;
}
input,
button {
color: #ffffff;
background-color: #0f0f0f98;
}
button:active {
background-color: #0f0f0f69;
}
input,
button {
color: #ffffff;
background-color: #0f0f0f98;
.lds-ring,
.lds-ring div {
box-sizing: border-box;
}
.lds-ring {
display: inline-block;
position: relative;
width: 15px;
height: 15px;
}
.lds-ring div {
box-sizing: border-box;
display: block;
position: absolute;
width: 14px;
height: 14px;
margin: 2px;
border: 2px solid currentColor;
border-radius: 50%;
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
border-color: currentColor transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
animation-delay: -0.15s;
}
@keyframes lds-ring {
0% {
transform: rotate(0deg);
}
button:active {
background-color: #0f0f0f69;
100% {
transform: rotate(360deg);
}
}
</style>
9 changes: 9 additions & 0 deletions guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ export async function getConnectionUpdates(handler: (connected: boolean) => void
await invoke('plugin:blec|connection_state', { update: connection_chan })
}

/**
* Register a handler to receive updates when the scanning state changes
*/
export async function getScanningUpdates(handler: (scanning: boolean) => void) {
let scanning_chan = new Channel<boolean>()
scanning_chan.onmessage = handler
await invoke('plugin:blec|scanning_state', { update: scanning_chan })
}

/**
* Disconnect from the currently connected device
*/
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mnlphlp/plugin-blec",
"version": "0.2.0",
"version": "0.3.0",
"author": "Manuel Philipp",
"description": "JS Bindings for BLE-Client plugin for Tauri",
"license": "(MIT OR Apache-2.0)",
Expand Down
13 changes: 13 additions & 0 deletions permissions/autogenerated/commands/scanning_state.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!

"$schema" = "../../schemas/schema.json"

[[permission]]
identifier = "allow-scanning-state"
description = "Enables the scanning_state command without any pre-configured scope."
commands.allow = ["scanning_state"]

[[permission]]
identifier = "deny-scanning-state"
description = "Denies the scanning_state command without any pre-configured scope."
commands.deny = ["scanning_state"]
27 changes: 27 additions & 0 deletions permissions/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Default permissions for the plugin
- `allow-subscribe`
- `allow-subscribe-string`
- `allow-unsubscribe`
- `allow-scanning-state`

## Permission Table

Expand Down Expand Up @@ -209,6 +210,32 @@ Denies the scan command without any pre-configured scope.
<tr>
<td>

`blec:allow-scanning-state`

</td>
<td>

Enables the scanning_state command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`blec:deny-scanning-state`

</td>
<td>

Denies the scanning_state command without any pre-configured scope.

</td>
</tr>

<tr>
<td>

`blec:allow-send`

</td>
Expand Down
2 changes: 1 addition & 1 deletion permissions/default.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[default]
description = "Default permissions for the plugin"
permissions = ["allow-scan","allow-stop-scan","allow-connect","allow-disconnect","allow-connection-state","allow-send","allow-recv","allow-send-string","allow-recv-string","allow-subscribe","allow-subscribe-string","allow-unsubscribe"]
permissions = ["allow-scan","allow-stop-scan","allow-connect","allow-disconnect","allow-connection-state","allow-send","allow-recv","allow-send-string","allow-recv-string","allow-subscribe","allow-subscribe-string","allow-unsubscribe","allow-scanning-state"]
10 changes: 10 additions & 0 deletions permissions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,16 @@
"type": "string",
"const": "deny-scan"
},
{
"description": "Enables the scanning_state command without any pre-configured scope.",
"type": "string",
"const": "allow-scanning-state"
},
{
"description": "Denies the scanning_state command without any pre-configured scope.",
"type": "string",
"const": "deny-scanning-state"
},
{
"description": "Enables the send command without any pre-configured scope.",
"type": "string",
Expand Down
24 changes: 23 additions & 1 deletion src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ pub(crate) async fn connection_state<R: Runtime>(
Ok(())
}

#[command]
pub(crate) async fn scanning_state<R: Runtime>(
_app: AppHandle<R>,
update: Channel<bool>,
) -> Result<()> {
let handler = get_handler()?;
let (tx, mut rx) = tokio::sync::mpsc::channel(1);
handler.lock().await.set_scanning_update_channel(tx);
update
.send(handler.lock().await.is_scanning())
.expect("failed to send scanning state");
async_runtime::spawn(async move {
while let Some(scanning) = rx.recv().await {
update
.send(scanning)
.expect("failed to send scanning state to the front-end");
}
});
Ok(())
}

#[command]
pub(crate) async fn send<R: Runtime>(
_app: AppHandle<R>,
Expand Down Expand Up @@ -197,6 +218,7 @@ pub fn commands<R: Runtime>() -> impl Fn(tauri::ipc::Invoke<R>) -> bool {
recv_string,
subscribe,
subscribe_string,
unsubscribe
unsubscribe,
scanning_state
]
}
40 changes: 39 additions & 1 deletion src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Handler {
notify_listeners: Arc<Mutex<Vec<Listener>>>,
on_disconnect: Option<Mutex<Box<dyn Fn() + Send>>>,
connection_update_channel: Option<mpsc::Sender<bool>>,
scan_update_channel: Option<mpsc::Sender<bool>>,
scan_task: Option<tokio::task::JoinHandle<()>>,
}

Expand All @@ -60,6 +61,7 @@ impl Handler {
on_disconnect: None,
connection_update_channel: None,
scan_task: None,
scan_update_channel: None,
})
}

Expand All @@ -68,6 +70,33 @@ impl Handler {
self.connected.is_some()
}

/// Returns true if the adapter is scanning
pub fn is_scanning(&self) -> bool {
if let Some(handle) = &self.scan_task {
!handle.is_finished()
} else {
false
}
}

/// Takes a sender that will be used to send changes in the scanning status
/// # Example
/// ```no_run
/// use tauri::async_runtime;
/// use tokio::sync::mpsc;
/// async_runtime::block_on(async {
/// let handler = tauri_plugin_blec::get_handler().unwrap();
/// let (tx, mut rx) = mpsc::channel(1);
/// handler.lock().await.set_scanning_update_channel(tx);
/// while let Some(scanning) = rx.recv().await {
/// println!("Scanning: {scanning}");
/// }
/// });
/// ```
pub fn set_scanning_update_channel(&mut self, tx: mpsc::Sender<bool>) {
self.scan_update_channel = Some(tx);
}

/// Takes a sender that will be used to send changes in the connection status
/// # Example
/// ```no_run
Expand Down Expand Up @@ -224,8 +253,12 @@ impl Handler {
services: vec![],
})
.await?;
if let Some(tx) = &self.scan_update_channel {
tx.send(true).await?;
}
let mut self_devices = self.devices.clone();
let adapter = self.adapter.clone();
let scan_update_channel = self.scan_update_channel.clone();
self.scan_task = Some(tokio::task::spawn(async move {
self_devices.lock().await.clear();
let loops = timeout / 200;
Expand All @@ -246,6 +279,9 @@ impl Handler {
}
}
adapter.stop_scan().await.expect("failed to stop scan");
if let Some(tx) = &scan_update_channel {
tx.send(false).await.expect("failed to send scan update");
}
}));
Ok(())
}
Expand All @@ -257,7 +293,9 @@ impl Handler {
self.adapter.stop_scan().await?;
if let Some(handle) = self.scan_task.take() {
handle.abort();
self.adapter.stop_scan().await?;
}
if let Some(tx) = &self.scan_update_channel {
tx.send(false).await?;
}
Ok(())
}
Expand Down

0 comments on commit ecfa563

Please sign in to comment.