@@ -6,63 +6,106 @@ use futures_lite::StreamExt;
66use napi:: { bindgen_prelude:: * , threadsafe_function:: ThreadsafeFunction , threadsafe_function:: ThreadsafeFunctionCallMode } ;
77use napi_derive:: napi;
88use nusb:: { hotplug:: HotplugEvent , MaybeFuture } ;
9+ use std:: sync:: Arc ;
10+ use tokio:: sync:: { watch, RwLock } ;
911use webusb_device:: UsbDevice ;
1012
13+ struct Callbacks {
14+ attach : Option < ThreadsafeFunction < UsbDevice , ( ) , UsbDevice , napi:: Status , false > > ,
15+ detach : Option < ThreadsafeFunction < String , ( ) , String , napi:: Status , false > > ,
16+ }
17+
1118#[ napi]
1219pub struct Emitter {
13- attachCallback : Option < ThreadsafeFunction < UsbDevice , ( ) , UsbDevice , napi :: Status , false > > ,
14- detachCallback : Option < ThreadsafeFunction < String , ( ) , String , napi :: Status , false > > ,
20+ callbacks : Arc < RwLock < Callbacks > > ,
21+ listeners_tx : watch :: Sender < bool > ,
1522}
1623
1724#[ napi]
1825impl Emitter {
1926 #[ napi( constructor) ]
2027 pub fn new ( ) -> Self {
28+ let callbacks = Arc :: new ( RwLock :: new ( Callbacks { attach : None , detach : None } ) ) ;
29+ let ( listeners_tx, _listeners_rx) = watch:: channel ( false ) ;
2130 Self {
22- attachCallback : None ,
23- detachCallback : None ,
31+ callbacks ,
32+ listeners_tx ,
2433 }
2534 }
2635
2736 #[ napi]
28- pub async unsafe fn start ( & self ) {
29- let mut watch = nusb:: watch_devices ( ) . unwrap ( ) ;
30- while let Some ( event) = watch. next ( ) . await {
31- match event {
32- HotplugEvent :: Connected ( info) => {
33- if let Some ( callback) = & self . attachCallback {
34- let device = UsbDevice :: new ( info) ;
35- callback. call ( device, ThreadsafeFunctionCallMode :: NonBlocking ) ;
36- }
37+ pub async fn init ( & self ) {
38+ let callbacks = self . callbacks . clone ( ) ;
39+ let mut listeners_rx = self . listeners_tx . subscribe ( ) ;
40+
41+ tokio:: spawn ( async move {
42+ loop {
43+ while !* listeners_rx. borrow ( ) {
44+ // Wait for an event to be attached
3745 }
38- HotplugEvent :: Disconnected ( id) => {
39- if let Some ( callback) = & self . detachCallback {
40- let handle = format ! ( "{:?}" , id) ;
41- callback. call ( handle, ThreadsafeFunctionCallMode :: NonBlocking ) ;
46+
47+ let mut watch_stream = nusb:: watch_devices ( ) . unwrap ( ) ;
48+ loop {
49+ tokio:: select! {
50+ _ = listeners_rx. changed( ) => {
51+ if !* listeners_rx. borrow( ) {
52+ // No listeners attached, stop watching for device events
53+ break ;
54+ }
55+ }
56+ ev = watch_stream. next( ) => {
57+ match ev {
58+ Some ( HotplugEvent :: Connected ( info) ) => {
59+ let guard = callbacks. read( ) . await ;
60+ if let Some ( cb) = guard. attach. as_ref( ) {
61+ cb. call( UsbDevice :: new( info) , ThreadsafeFunctionCallMode :: NonBlocking ) ;
62+ }
63+ }
64+ Some ( HotplugEvent :: Disconnected ( id) ) => {
65+ let guard = callbacks. read( ) . await ;
66+ if let Some ( cb) = guard. detach. as_ref( ) {
67+ cb. call( format!( "{:?}" , id) , ThreadsafeFunctionCallMode :: NonBlocking ) ;
68+ }
69+ }
70+ None => break ,
71+ }
72+ }
4273 }
4374 }
4475 }
45- }
76+ } ) ;
4677 }
4778
4879 #[ napi]
49- pub fn addAttach ( & mut self , callback : ThreadsafeFunction < UsbDevice , ( ) , UsbDevice , napi:: Status , false > ) {
50- self . attachCallback = Some ( callback) ;
80+ pub async unsafe fn addAttach ( & mut self , callback : ThreadsafeFunction < UsbDevice , ( ) , UsbDevice , napi:: Status , false > ) {
81+ { self . callbacks . write ( ) . await . attach = Some ( callback) ; }
82+ self . publishState ( ) . await ;
5183 }
5284
5385 #[ napi]
54- pub fn removeAttach ( & mut self , _callback : ThreadsafeFunction < UsbDevice , ( ) , UsbDevice , napi:: Status , false > ) {
55- self . attachCallback = None ;
86+ pub async unsafe fn removeAttach ( & mut self ) {
87+ { self . callbacks . write ( ) . await . attach = None ; }
88+ self . publishState ( ) . await ;
5689 }
5790
5891 #[ napi]
59- pub fn addDetach ( & mut self , callback : ThreadsafeFunction < String , ( ) , String , napi:: Status , false > ) {
60- self . detachCallback = Some ( callback) ;
92+ pub async unsafe fn addDetach ( & mut self , callback : ThreadsafeFunction < String , ( ) , String , napi:: Status , false > ) {
93+ { self . callbacks . write ( ) . await . detach = Some ( callback) ; }
94+ self . publishState ( ) . await ;
6195 }
6296
6397 #[ napi]
64- pub fn removeDetach ( & mut self , _callback : ThreadsafeFunction < String , ( ) , String , napi:: Status , false > ) {
65- self . detachCallback = None ;
98+ pub async unsafe fn removeDetach ( & mut self ) {
99+ { self . callbacks . write ( ) . await . detach = None ; }
100+ self . publishState ( ) . await ;
101+ }
102+
103+ async fn publishState ( & self ) {
104+ let listeners = {
105+ let cb = self . callbacks . read ( ) . await ;
106+ cb. attach . is_some ( ) || cb. detach . is_some ( )
107+ } ;
108+ let _ = self . listeners_tx . send ( listeners) ;
66109 }
67110}
68111
0 commit comments