@@ -8,6 +8,7 @@ use rquickjs::Ctx;
8
8
use rquickjs:: Module ;
9
9
use std:: collections:: HashMap ;
10
10
use std:: path:: Path ;
11
+ use std:: sync:: atomic:: AtomicUsize ;
11
12
use std:: time:: Duration ;
12
13
use tokio:: sync:: mpsc;
13
14
use tokio:: sync:: oneshot;
@@ -19,11 +20,19 @@ pub struct JsRuntime {
19
20
execution_timeout : Duration ,
20
21
}
21
22
23
+ static TIME_CREDITS : AtomicUsize = AtomicUsize :: new ( 1000 ) ;
24
+
22
25
impl JsRuntime {
23
26
pub async fn try_new ( ) -> Result < Self , LoadError > {
24
27
let runtime = rquickjs:: AsyncRuntime :: new ( ) ?;
25
28
runtime. set_memory_limit ( 16 * 1024 * 1024 ) . await ;
26
29
runtime. set_max_stack_size ( 256 * 1024 ) . await ;
30
+ runtime
31
+ . set_interrupt_handler ( Some ( Box :: new ( || {
32
+ let credits = TIME_CREDITS . fetch_sub ( 1 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
33
+ credits == 0
34
+ } ) ) )
35
+ . await ;
27
36
let context = rquickjs:: AsyncContext :: full ( & runtime) . await ?;
28
37
let worker = JsWorker :: spawn ( context) . await ;
29
38
let execution_timeout = Duration :: from_secs ( 5 ) ;
@@ -65,6 +74,7 @@ impl JsRuntime {
65
74
let ( sender, receiver) = oneshot:: channel ( ) ;
66
75
let source = source. into ( ) ;
67
76
let imports = vec ! [ "onMessage" , "onConfigUpdate" , "onInterval" ] ;
77
+ TIME_CREDITS . store ( 100000 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
68
78
self . send (
69
79
receiver,
70
80
JsRequest :: LoadModule {
@@ -84,6 +94,7 @@ impl JsRuntime {
84
94
args : Vec < JsonValue > ,
85
95
) -> Result < JsonValue , LoadError > {
86
96
let ( sender, receiver) = oneshot:: channel ( ) ;
97
+ TIME_CREDITS . store ( 1000 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
87
98
self . send (
88
99
receiver,
89
100
JsRequest :: CallFunction {
0 commit comments