github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/internal/jsre/jsre.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 //包JSRE为JavaScript提供执行环境。 26 package jsre 27 28 import ( 29 crand "crypto/rand" 30 "encoding/binary" 31 "fmt" 32 "io" 33 "io/ioutil" 34 "math/rand" 35 "time" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/ethereum/go-ethereum/internal/jsre/deps" 39 "github.com/robertkrimen/otto" 40 ) 41 42 var ( 43 BigNumber_JS = deps.MustAsset("bignumber.js") 44 Web3_JS = deps.MustAsset("web3.js") 45 ) 46 47 /* 48 JSRE是嵌入OttoJS解释器的通用JS运行时环境。 49 它为 50 -从文件加载代码 51 -运行代码段 52 -需要库 53 -绑定本机go对象 54 **/ 55 56 type JSRE struct { 57 assetPath string 58 output io.Writer 59 evalQueue chan *evalReq 60 stopEventLoop chan bool 61 closed chan struct{} 62 } 63 64 //JSTimer是带有回调函数的单个计时器实例 65 type jsTimer struct { 66 timer *time.Timer 67 duration time.Duration 68 interval bool 69 call otto.FunctionCall 70 } 71 72 //evalReq是一个由runEventLoop处理的序列化VM执行请求。 73 type evalReq struct { 74 fn func(vm *otto.Otto) 75 done chan bool 76 } 77 78 //运行时在使用后必须使用stop()停止,在停止后不能使用。 79 func New(assetPath string, output io.Writer) *JSRE { 80 re := &JSRE{ 81 assetPath: assetPath, 82 output: output, 83 closed: make(chan struct{}), 84 evalQueue: make(chan *evalReq), 85 stopEventLoop: make(chan bool), 86 } 87 go re.runEventLoop() 88 re.Set("loadScript", re.loadScript) 89 re.Set("inspect", re.prettyPrintJS) 90 return re 91 } 92 93 //RandomSource返回一个伪随机值生成器。 94 func randomSource() *rand.Rand { 95 bytes := make([]byte, 8) 96 seed := time.Now().UnixNano() 97 if _, err := crand.Read(bytes); err == nil { 98 seed = int64(binary.LittleEndian.Uint64(bytes)) 99 } 100 101 src := rand.NewSource(seed) 102 return rand.New(src) 103 } 104 105 //此函数从启动的goroutine运行主事件循环 106 //创建JSRE时。在退出之前使用stop()来正确地停止它。 107 //事件循环处理来自evalqueue的VM访问请求 108 //序列化方式,并在适当的时间调用计时器回调函数。 109 110 //导出的函数总是通过事件队列访问VM。你可以 111 //直接调用OttoVM的函数以绕过队列。这些 112 //当且仅当运行的例程 113 //通过RPC调用从JS调用。 114 func (re *JSRE) runEventLoop() { 115 defer close(re.closed) 116 117 vm := otto.New() 118 r := randomSource() 119 vm.SetRandomSource(r.Float64) 120 121 registry := map[*jsTimer]*jsTimer{} 122 ready := make(chan *jsTimer) 123 124 newTimer := func(call otto.FunctionCall, interval bool) (*jsTimer, otto.Value) { 125 delay, _ := call.Argument(1).ToInteger() 126 if 0 >= delay { 127 delay = 1 128 } 129 timer := &jsTimer{ 130 duration: time.Duration(delay) * time.Millisecond, 131 call: call, 132 interval: interval, 133 } 134 registry[timer] = timer 135 136 timer.timer = time.AfterFunc(timer.duration, func() { 137 ready <- timer 138 }) 139 140 value, err := call.Otto.ToValue(timer) 141 if err != nil { 142 panic(err) 143 } 144 return timer, value 145 } 146 147 setTimeout := func(call otto.FunctionCall) otto.Value { 148 _, value := newTimer(call, false) 149 return value 150 } 151 152 setInterval := func(call otto.FunctionCall) otto.Value { 153 _, value := newTimer(call, true) 154 return value 155 } 156 157 clearTimeout := func(call otto.FunctionCall) otto.Value { 158 timer, _ := call.Argument(0).Export() 159 if timer, ok := timer.(*jsTimer); ok { 160 timer.timer.Stop() 161 delete(registry, timer) 162 } 163 return otto.UndefinedValue() 164 } 165 vm.Set("_setTimeout", setTimeout) 166 vm.Set("_setInterval", setInterval) 167 vm.Run(`var setTimeout = function(args) { 168 if (arguments.length < 1) { 169 throw TypeError("Failed to execute 'setTimeout': 1 argument required, but only 0 present."); 170 } 171 return _setTimeout.apply(this, arguments); 172 }`) 173 vm.Run(`var setInterval = function(args) { 174 if (arguments.length < 1) { 175 throw TypeError("Failed to execute 'setInterval': 1 argument required, but only 0 present."); 176 } 177 return _setInterval.apply(this, arguments); 178 }`) 179 vm.Set("clearTimeout", clearTimeout) 180 vm.Set("clearInterval", clearTimeout) 181 182 var waitForCallbacks bool 183 184 loop: 185 for { 186 select { 187 case timer := <-ready: 188 //执行回调,删除/重新安排计时器 189 var arguments []interface{} 190 if len(timer.call.ArgumentList) > 2 { 191 tmp := timer.call.ArgumentList[2:] 192 arguments = make([]interface{}, 2+len(tmp)) 193 for i, value := range tmp { 194 arguments[i+2] = value 195 } 196 } else { 197 arguments = make([]interface{}, 1) 198 } 199 arguments[0] = timer.call.ArgumentList[0] 200 _, err := vm.Call(`Function.call.call`, nil, arguments...) 201 if err != nil { 202 fmt.Println("js error:", err, arguments) 203 } 204 205 _, inreg := registry[timer] //当从回调中调用ClearInterval时,不要重置它 206 if timer.interval && inreg { 207 timer.timer.Reset(timer.duration) 208 } else { 209 delete(registry, timer) 210 if waitForCallbacks && (len(registry) == 0) { 211 break loop 212 } 213 } 214 case req := <-re.evalQueue: 215 //运行代码,返回结果 216 req.fn(vm) 217 close(req.done) 218 if waitForCallbacks && (len(registry) == 0) { 219 break loop 220 } 221 case waitForCallbacks = <-re.stopEventLoop: 222 if !waitForCallbacks || (len(registry) == 0) { 223 break loop 224 } 225 } 226 } 227 228 for _, timer := range registry { 229 timer.timer.Stop() 230 delete(registry, timer) 231 } 232 } 233 234 //do在JS事件循环上执行给定的函数。 235 func (re *JSRE) Do(fn func(*otto.Otto)) { 236 done := make(chan bool) 237 req := &evalReq{fn, done} 238 re.evalQueue <- req 239 <-done 240 } 241 242 //在退出前停止事件循环,或者等待所有计时器过期 243 func (re *JSRE) Stop(waitForCallbacks bool) { 244 select { 245 case <-re.closed: 246 case re.stopEventLoop <- waitForCallbacks: 247 <-re.closed 248 } 249 } 250 251 //exec(文件)加载并运行文件的内容 252 //如果给定了相对路径,则使用JSRE的assetpath 253 func (re *JSRE) Exec(file string) error { 254 code, err := ioutil.ReadFile(common.AbsolutePath(re.assetPath, file)) 255 if err != nil { 256 return err 257 } 258 var script *otto.Script 259 re.Do(func(vm *otto.Otto) { 260 script, err = vm.Compile(file, code) 261 if err != nil { 262 return 263 } 264 _, err = vm.Run(script) 265 }) 266 return err 267 } 268 269 //bind将值v赋给JS环境中的变量 270 //此方法已弃用,请使用set。 271 func (re *JSRE) Bind(name string, v interface{}) error { 272 return re.Set(name, v) 273 } 274 275 //运行运行一段JS代码。 276 func (re *JSRE) Run(code string) (v otto.Value, err error) { 277 re.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) 278 return v, err 279 } 280 281 //get返回JS环境中变量的值。 282 func (re *JSRE) Get(ns string) (v otto.Value, err error) { 283 re.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) 284 return v, err 285 } 286 287 //set将值v赋给JS环境中的变量。 288 func (re *JSRE) Set(ns string, v interface{}) (err error) { 289 re.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) 290 return err 291 } 292 293 //loadscript从当前执行的JS代码内部执行JS脚本。 294 func (re *JSRE) loadScript(call otto.FunctionCall) otto.Value { 295 file, err := call.Argument(0).ToString() 296 if err != nil { 297 //TODO:引发异常 298 return otto.FalseValue() 299 } 300 file = common.AbsolutePath(re.assetPath, file) 301 source, err := ioutil.ReadFile(file) 302 if err != nil { 303 //TODO:引发异常 304 return otto.FalseValue() 305 } 306 if _, err := compileAndRun(call.Otto, file, source); err != nil { 307 //TODO:引发异常 308 fmt.Println("err:", err) 309 return otto.FalseValue() 310 } 311 //TODO:返回评估结果 312 return otto.TrueValue() 313 } 314 315 //evaluate执行代码并将结果漂亮地打印到指定的输出 316 //溪流。 317 func (re *JSRE) Evaluate(code string, w io.Writer) error { 318 var fail error 319 320 re.Do(func(vm *otto.Otto) { 321 val, err := vm.Run(code) 322 if err != nil { 323 prettyError(vm, err, w) 324 } else { 325 prettyPrint(vm, val, w) 326 } 327 fmt.Fprintln(w) 328 }) 329 return fail 330 } 331 332 //编译然后运行一段JS代码。 333 func (re *JSRE) Compile(filename string, src interface{}) (err error) { 334 re.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) 335 return err 336 } 337 338 func compileAndRun(vm *otto.Otto, filename string, src interface{}) (otto.Value, error) { 339 script, err := vm.Compile(filename, src) 340 if err != nil { 341 return otto.Value{}, err 342 } 343 return vm.Run(script) 344 }