11use crate :: config:: Config ;
22use crate :: osc_query:: { OscAccess , OscQueryService } ;
3- use anyhow:: { bail, Context , Result } ;
3+ use anyhow:: { anyhow , bail, Context , Result } ;
44use async_osc:: { prelude:: OscMessageExt , OscMessage , OscType } ;
55use debounced:: debounced;
6- use log:: { debug, info, warn} ;
6+ use log:: { debug, error , info, warn} ;
77use serde:: { Deserialize , Serialize } ;
88use std:: path:: PathBuf ;
99use std:: sync:: Arc ;
@@ -12,6 +12,7 @@ use tokio::fs::{metadata, File};
1212use tokio:: io:: { AsyncReadExt , AsyncWriteExt } ;
1313use tokio:: sync:: broadcast:: error:: RecvError ;
1414use tokio:: sync:: { broadcast, mpsc, oneshot} ;
15+ use tokio:: task:: JoinSet ;
1516use tokio:: time:: sleep;
1617use tokio:: { select, spawn} ;
1718use tokio_graceful_shutdown:: { errors:: CancelledByShutdown , FutureExt , SubsystemHandle } ;
@@ -287,24 +288,19 @@ struct ShockBody {
287288 intensity : u8 ,
288289}
289290
290- async fn send_shock (
291- config : & Arc < Config > ,
292- intensity : f32 ,
293- duration : u8 ,
294- activity_tx : & mpsc:: Sender < u8 > ,
295- ) {
291+ async fn send_shock ( config : Arc < Config > , code : String , intensity : f32 , duration : u8 ) -> Result < ( ) > {
296292 let intensity = 1 + ( 99. * intensity) as u8 ;
297293 let duration = duration. clamp ( 1 , 15 ) ;
298294
299295 info ! (
300- "Sending shock with intensity {} and duration {}" ,
301- intensity, duration
296+ "Sending shock to {} with intensity {} and duration {}" ,
297+ code , intensity, duration
302298 ) ;
303299
304300 let body = ShockBody {
305301 username : config. pishock . username . clone ( ) ,
306302 api_key : config. pishock . api_key . clone ( ) ,
307- code : config . pishock . code . clone ( ) ,
303+ code,
308304 name : "OSC Manager - PiShock Plugin" . to_string ( ) ,
309305 op : 0 ,
310306 duration,
@@ -324,22 +320,69 @@ async fn send_shock(
324320
325321 match status {
326322 Ok ( status) => match status. as_str ( ) {
327- "Not Authorized." => warn ! ( "Invalid credentials" ) ,
328- "Operation Succeeded." => {
329- debug ! ( "Shock succeeded" ) ;
330- let _ = activity_tx. send ( duration) . await ;
331- }
332- _ => warn ! ( "Unknown response: {}" , status) ,
323+ "Not Authorized." => Err ( anyhow ! ( "Invalid credentials" ) ) ,
324+ "Operation Succeeded." => Ok ( ( ) ) ,
325+ "Operation Attempted." => Ok ( ( ) ) ,
326+ _ => Err ( anyhow ! ( "Unknown response: {}" , status) ) ,
333327 } ,
334- Err ( _) => {
335- warn ! ( "Failed to parse response" ) ;
336- }
328+ Err ( _) => Err ( anyhow ! ( "Failed to parse response" ) ) ,
337329 }
338330 }
339- Err ( _) => {
340- warn ! ( "Failed to contact pishock API" ) ;
331+ Err ( _) => Err ( anyhow ! ( "Failed to contact pishock API" ) ) ,
332+ }
333+ }
334+
335+ async fn send_shocks (
336+ config : & Arc < Config > ,
337+ intensity : f32 ,
338+ duration : u8 ,
339+ activity_tx : & mpsc:: Sender < u8 > ,
340+ ) {
341+ let codes = if let Some ( codes) = config. pishock . codes . clone ( ) {
342+ codes
343+ } else if let Some ( code) = config. pishock . code . clone ( ) {
344+ vec ! [ code]
345+ } else {
346+ warn ! ( "Neither single nor multiple codes configured" ) ;
347+ return ;
348+ } ;
349+
350+ if codes. is_empty ( ) {
351+ warn ! ( "No codes configured" ) ;
352+ return ;
353+ }
354+
355+ let mut set = JoinSet :: new ( ) ;
356+
357+ for code in codes {
358+ set. spawn ( send_shock (
359+ config. clone ( ) ,
360+ code. clone ( ) ,
361+ intensity,
362+ duration,
363+ ) ) ;
364+ }
365+
366+ let mut succeeded = false ;
367+
368+ while let Some ( res) = set. join_next ( ) . await {
369+ match res {
370+ Ok ( Ok ( ( ) ) ) => {
371+ debug ! ( "Shock succeeded" ) ;
372+ succeeded = true ;
373+ }
374+ Ok ( Err ( error) ) => {
375+ warn ! ( "{}" , error) ;
376+ }
377+ Err ( error) => {
378+ error ! ( "{}" , error) ;
379+ }
341380 }
342381 }
382+
383+ if succeeded {
384+ let _ = activity_tx. send ( duration) . await ;
385+ }
343386}
344387
345388async fn handle_shock (
@@ -370,7 +413,7 @@ async fn handle_shock(
370413 loop {
371414 let settings = get_settings ( & settings_tx) . await . unwrap ( ) ;
372415
373- send_shock (
416+ send_shocks (
374417 & config,
375418 settings. intensity ,
376419 config. pishock . duration ,
@@ -549,7 +592,7 @@ impl PiShock {
549592 if value >= 0. {
550593 let settings = get_settings ( & settings_tx) . await ?;
551594
552- send_shock (
595+ send_shocks (
553596 & self . config ,
554597 value. clamp ( 0. , settings. intensity_cap ) ,
555598 1 ,
0 commit comments