github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/goja/main.go (about) 1 package main 2 3 import ( 4 crand "crypto/rand" 5 "encoding/binary" 6 "flag" 7 "fmt" 8 "io" 9 "log" 10 "math/rand" 11 "os" 12 "runtime/debug" 13 "runtime/pprof" 14 "time" 15 16 "github.com/dop251/goja" 17 "github.com/dop251/goja_nodejs/console" 18 "github.com/dop251/goja_nodejs/require" 19 ) 20 21 var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") 22 var timelimit = flag.Int("timelimit", 0, "max time to run (in seconds)") 23 24 func readSource(filename string) ([]byte, error) { 25 if filename == "" || filename == "-" { 26 return io.ReadAll(os.Stdin) 27 } 28 return os.ReadFile(filename) 29 } 30 31 func load(vm *goja.Runtime, call goja.FunctionCall) goja.Value { 32 p := call.Argument(0).String() 33 b, err := readSource(p) 34 if err != nil { 35 panic(vm.ToValue(fmt.Sprintf("Could not read %s: %v", p, err))) 36 } 37 v, err := vm.RunScript(p, string(b)) 38 if err != nil { 39 panic(err) 40 } 41 return v 42 } 43 44 func newRandSource() goja.RandSource { 45 var seed int64 46 if err := binary.Read(crand.Reader, binary.LittleEndian, &seed); err != nil { 47 panic(fmt.Errorf("Could not read random bytes: %v", err)) 48 } 49 return rand.New(rand.NewSource(seed)).Float64 50 } 51 52 func run() error { 53 filename := flag.Arg(0) 54 src, err := readSource(filename) 55 if err != nil { 56 return err 57 } 58 59 if filename == "" || filename == "-" { 60 filename = "<stdin>" 61 } 62 63 vm := goja.New() 64 vm.SetRandSource(newRandSource()) 65 66 new(require.Registry).Enable(vm) 67 console.Enable(vm) 68 69 vm.Set("load", func(call goja.FunctionCall) goja.Value { 70 return load(vm, call) 71 }) 72 73 vm.Set("readFile", func(name string) (string, error) { 74 b, err := os.ReadFile(name) 75 if err != nil { 76 return "", err 77 } 78 return string(b), nil 79 }) 80 81 if *timelimit > 0 { 82 time.AfterFunc(time.Duration(*timelimit)*time.Second, func() { 83 vm.Interrupt("timeout") 84 }) 85 } 86 87 //log.Println("Compiling...") 88 prg, err := goja.Compile(filename, string(src), false) 89 if err != nil { 90 return err 91 } 92 //log.Println("Running...") 93 _, err = vm.RunProgram(prg) 94 //log.Println("Finished.") 95 return err 96 } 97 98 func main() { 99 defer func() { 100 if x := recover(); x != nil { 101 debug.Stack() 102 panic(x) 103 } 104 }() 105 flag.Parse() 106 if *cpuprofile != "" { 107 f, err := os.Create(*cpuprofile) 108 if err != nil { 109 log.Fatal(err) 110 } 111 pprof.StartCPUProfile(f) 112 defer pprof.StopCPUProfile() 113 } 114 115 if err := run(); err != nil { 116 //fmt.Printf("err type: %T\n", err) 117 switch err := err.(type) { 118 case *goja.Exception: 119 fmt.Println(err.String()) 120 case *goja.InterruptedError: 121 fmt.Println(err.String()) 122 default: 123 fmt.Println(err) 124 } 125 os.Exit(64) 126 } 127 }