@@ -11,6 +11,8 @@ use serialization::xml::serialize;
11
11
use state:: { SharedState , State } ;
12
12
use task:: Task ;
13
13
14
+ use crate :: cli;
15
+
14
16
pub mod events;
15
17
pub mod generator;
16
18
pub mod namespaces;
@@ -66,6 +68,22 @@ impl Invocation {
66
68
payload,
67
69
}
68
70
}
71
+
72
+ pub fn as_function_call_string ( & self ) -> String {
73
+ let mut parts = vec ! [ ] ;
74
+
75
+ if let Some ( payload) = & self . payload {
76
+ parts. push ( payload. to_owned ( ) ) ;
77
+ }
78
+
79
+ if let Some ( attributes) = & self . attributes {
80
+ for ( name, value) in attributes {
81
+ parts. push ( format ! ( "{}={}" , name, value) )
82
+ }
83
+ }
84
+
85
+ return format ! ( "{}({})" , & self . action, parts. join( ", " ) ) ;
86
+ }
69
87
}
70
88
71
89
pub struct Agent {
@@ -362,22 +380,52 @@ impl Agent {
362
380
Duration :: from_secs ( 60 * 60 * 24 * 30 )
363
381
} ;
364
382
365
- // execute with timeout
366
- let start = std:: time:: Instant :: now ( ) ;
367
- let ret = tokio:: time:: timeout (
368
- timeout,
369
- action. run (
370
- self . state . clone ( ) ,
371
- inv. attributes . to_owned ( ) ,
372
- inv. payload . to_owned ( ) ,
373
- ) ,
374
- )
375
- . await ;
376
-
377
- if ret. is_err ( ) {
378
- self . on_timed_out_action ( inv, & start) . await ;
379
- } else {
380
- self . on_executed_action ( inv, ret. unwrap ( ) , & start) . await ;
383
+ let mut execute = true ;
384
+
385
+ if action. requires_user_confirmation ( ) {
386
+ log:: warn!( "user confirmation required" ) ;
387
+
388
+ let start = std:: time:: Instant :: now ( ) ;
389
+ let mut inp = "nope" . to_string ( ) ;
390
+ while inp != "" && inp != "n" && inp != "y" {
391
+ inp = cli:: get_user_input ( & format ! (
392
+ "{} [Yn] " ,
393
+ inv. as_function_call_string( )
394
+ ) )
395
+ . to_ascii_lowercase ( ) ;
396
+ }
397
+
398
+ if inp == "n" {
399
+ log:: warn!( "invocation rejected by user" ) ;
400
+ self . on_executed_action (
401
+ inv. clone ( ) ,
402
+ Err ( anyhow ! ( "rejected by user" . to_owned( ) ) ) ,
403
+ & start,
404
+ )
405
+ . await ;
406
+
407
+ execute = false ;
408
+ }
409
+ }
410
+
411
+ if execute {
412
+ // execute with timeout
413
+ let start = std:: time:: Instant :: now ( ) ;
414
+ let ret = tokio:: time:: timeout (
415
+ timeout,
416
+ action. run (
417
+ self . state . clone ( ) ,
418
+ inv. attributes . to_owned ( ) ,
419
+ inv. payload . to_owned ( ) ,
420
+ ) ,
421
+ )
422
+ . await ;
423
+
424
+ if ret. is_err ( ) {
425
+ self . on_timed_out_action ( inv, & start) . await ;
426
+ } else {
427
+ self . on_executed_action ( inv, ret. unwrap ( ) , & start) . await ;
428
+ }
381
429
}
382
430
}
383
431
}
0 commit comments