// newREPLConsole creates a new JavaScript interpreter console that can be used // by the API to serve fronted console requests. func newREPLConsole(eapis *etherapis.EtherAPIs) *jsre.JSRE { // Create a JavaScript interpreter with web3 injected console := jsre.New("") client, _ := eapis.Geth().Stack().Attach() jeth := utils.NewJeth(console, client) console.Set("jeth", struct{}{}) t, _ := console.Get("jeth") jethObj := t.Object() jethObj.Set("send", jeth.Send) jethObj.Set("sendAsync", jeth.Send) console.Compile("bignumber.js", jsre.BigNumber_JS) console.Compile("web3.js", jsre.Web3_JS) console.Run("var Web3 = require('web3');") console.Run("var web3 = new Web3(jeth);") // Inject all of the APIs exposed by the inproc RPC client shortcut := "var eth = web3.eth; var personal = web3.personal; " apis, _ := client.SupportedModules() for api, _ := range apis { if api == "web3" || api == "rpc" { continue } if jsFile, ok := web3ext.Modules[api]; ok { console.Compile(fmt.Sprintf("%s.js", api), jsFile) shortcut += fmt.Sprintf("var %s = web3.%s; ", api, api) } } console.Run(shortcut) // Finally return the ready console return console }
func (js *jsre) apiBindings() error { apis, err := js.supportedApis() if err != nil { return err } apiNames := make([]string, 0, len(apis)) for a, _ := range apis { apiNames = append(apiNames, a) } jeth := utils.NewJeth(js.re, js.client) js.re.Set("jeth", struct{}{}) t, _ := js.re.Get("jeth") jethObj := t.Object() jethObj.Set("send", jeth.Send) jethObj.Set("sendAsync", jeth.Send) err = js.re.Compile("bignumber.js", re.BigNumber_JS) if err != nil { utils.Fatalf("Error loading bignumber.js: %v", err) } err = js.re.Compile("web3.js", re.Web3_JS) if err != nil { utils.Fatalf("Error loading web3.js: %v", err) } _, err = js.re.Run("var Web3 = require('web3');") if err != nil { utils.Fatalf("Error requiring web3: %v", err) } _, err = js.re.Run("var web3 = new Web3(jeth);") if err != nil { utils.Fatalf("Error setting web3 provider: %v", err) } // load only supported API's in javascript runtime shortcuts := "var eth = web3.eth; var personal = web3.personal; " for _, apiName := range apiNames { if apiName == "web3" || apiName == "rpc" { continue // manually mapped or ignore } if jsFile, ok := web3ext.Modules[apiName]; ok { if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), jsFile); err == nil { shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName) } else { utils.Fatalf("Error loading %s.js: %v", apiName, err) } } } _, err = js.re.Run(shortcuts) if err != nil { utils.Fatalf("Error setting namespaces: %v", err) } js.re.Run(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`) // overrule some of the methods that require password as input and ask for it interactively p, err := js.re.Get("personal") if err != nil { fmt.Println("Unable to overrule sensitive methods in personal module") return nil } // Override the unlockAccount and newAccount methods on the personal object since these require user interaction. // Assign the jeth.unlockAccount and jeth.newAccount in the jsre the original web3 callbacks. These will be called // by the jeth.* methods after they got the password from the user and send the original web3 request to the backend. if persObj := p.Object(); persObj != nil { // make sure the personal api is enabled over the interface js.re.Run(`jeth.unlockAccount = personal.unlockAccount;`) persObj.Set("unlockAccount", jeth.UnlockAccount) js.re.Run(`jeth.newAccount = personal.newAccount;`) persObj.Set("newAccount", jeth.NewAccount) } // The admin.sleep and admin.sleepBlocks are offered by the console and not by the RPC layer. // Bind these if the admin module is available. if a, err := js.re.Get("admin"); err == nil { if adminObj := a.Object(); adminObj != nil { adminObj.Set("sleepBlocks", jeth.SleepBlocks) adminObj.Set("sleep", jeth.Sleep) } } return nil }