1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.runtime.sandbox;
7 
8 import std.stdio, core.thread;
9 import grimoire;
10 
11 /// Handle a grimoire VM safely.
12 final class GrSandbox {
13     private final class TimeoutThread: Thread {
14         private {
15             __gshared GrSandbox _script;
16         }
17         shared bool isRunning = true;
18         shared bool isTimedout;
19 
20         this(GrSandbox script) {
21             _script = script;
22             super(&run);
23         }
24 
25         void run() {
26             try {
27                 const auto startTime = MonoTime.currTime();
28                 while(isRunning) {
29                     const auto currentCycle = _script._cycle;
30                     sleep(dur!("msecs")(100));
31                     if(currentCycle == _script._cycle && _script._isLoaded) {
32                         isTimedout = true;
33                         isRunning = false;
34                         _script.engine.isRunning = false;
35                     }
36                     const auto deltaTime = MonoTime.currTime() - startTime;
37                     if(deltaTime > dur!"msecs"(1000)) {
38                         isTimedout = true;
39                         isRunning = false;
40                         _script.engine.isRunning = false;
41                     }
42                 }
43             }
44             catch(Exception e) {
45                 writeln("Script timeout error: ", e.msg);
46             }
47         }
48     }
49 
50     private {
51         shared int _cycle;
52         shared bool _isLoaded = false;
53         TimeoutThread _timeout;
54     }
55 
56     GrEngine engine;
57 
58     @property {
59         bool isRunning() { return engine.hasCoroutines && !engine.isPanicking && engine.isRunning; }
60         bool isTimedout() { return _timeout.isTimedout; }
61     }
62 
63     void cleanup() {
64         engine.isRunning = false;
65         _isLoaded = false;
66         if(_timeout) {
67             _timeout.isRunning = false;
68             _timeout = null;
69         }
70     }
71 
72     /*void load(string name) {
73         auto bytecode = grCompileFile(name);
74         engine = new GrEngine;
75         engine.load(bytecode);
76         engine.spawn();
77         _timeout = new TimeoutThread(this);
78         _timeout.start();
79     }*/
80 
81     void run() {
82         _isLoaded = true;
83         if(engine.hasCoroutines)
84             engine.process();
85         _cycle = _cycle + 1;
86         if(!engine.hasCoroutines || engine.isPanicking)
87             _timeout.isRunning = false;
88     }
89 }