github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/neatio/consolecmd.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/signal" 7 "path/filepath" 8 "strings" 9 "syscall" 10 11 "github.com/neatlab/neatio/network/node" 12 "github.com/neatlab/neatio/network/rpc" 13 "github.com/neatlab/neatio/utilities/console" 14 "github.com/neatlab/neatio/utilities/utils" 15 "gopkg.in/urfave/cli.v1" 16 ) 17 18 var ( 19 consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} 20 21 consoleCommand = cli.Command{ 22 Action: utils.MigrateFlags(localConsole), 23 Name: "console", 24 Usage: "Start an interactive JavaScript environment", 25 Flags: append(append(nodeFlags, rpcFlags...), consoleFlags...), 26 Category: "CONSOLE COMMANDS", 27 Description: ` 28 The Geth console is an interactive shell for the JavaScript runtime environment 29 which exposes a node admin interface as well as the Ðapp JavaScript API. 30 See https://github.com/neatlab/neatio/wiki/JavaScript-Console.`, 31 } 32 33 attachCommand = cli.Command{ 34 Action: utils.MigrateFlags(remoteConsole), 35 Name: "attach", 36 Usage: "Start an interactive JavaScript environment (connect to node)", 37 ArgsUsage: "[endpoint]", 38 Flags: append(consoleFlags, utils.DataDirFlag), 39 Category: "CONSOLE COMMANDS", 40 Description: ` 41 The Geth console is an interactive shell for the JavaScript runtime environment 42 which exposes a node admin interface as well as the Ðapp JavaScript API. 43 See https://github.com/neatlab/neatio/wiki/JavaScript-Console. 44 This command allows to open a console on a running neatio node.`, 45 } 46 47 javascriptCommand = cli.Command{ 48 Action: utils.MigrateFlags(ephemeralConsole), 49 Name: "js", 50 Usage: "Execute the specified JavaScript files", 51 ArgsUsage: "<jsfile> [jsfile...]", 52 Flags: append(nodeFlags, consoleFlags...), 53 Category: "CONSOLE COMMANDS", 54 Description: ` 55 The JavaScript VM exposes a node admin interface as well as the Ðapp 56 JavaScript API. See https://github.com/neatlab/neatio/wiki/JavaScript-Console`, 57 } 58 ) 59 60 func localConsole(ctx *cli.Context) error { 61 chainName := ctx.Args().First() 62 if chainName == "" { 63 utils.Fatalf("This command requires chain name specified.") 64 } 65 66 node := makeFullNode(ctx, GetCMInstance(ctx).cch, chainName) 67 utils.StartNode(ctx, node) 68 defer node.Close() 69 70 client, err := node.Attach() 71 if err != nil { 72 utils.Fatalf("Failed to attach to the inproc neatio: %v", err) 73 } 74 config := console.Config{ 75 DataDir: utils.MakeDataDir(ctx), 76 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 77 Client: client, 78 Preload: utils.MakeConsolePreloads(ctx), 79 } 80 81 console, err := console.New(config) 82 if err != nil { 83 utils.Fatalf("Failed to start the JavaScript console: %v", err) 84 } 85 defer console.Stop(false) 86 87 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 88 console.Evaluate(script) 89 return nil 90 } 91 console.Welcome() 92 console.Interactive() 93 94 return nil 95 } 96 97 func remoteConsole(ctx *cli.Context) error { 98 endpoint := ctx.Args().First() 99 if endpoint == "" { 100 path := node.DefaultDataDir() 101 if ctx.GlobalIsSet(utils.DataDirFlag.Name) { 102 path = ctx.GlobalString(utils.DataDirFlag.Name) 103 } 104 if path != "" { 105 if ctx.GlobalBool(utils.TestnetFlag.Name) { 106 path = filepath.Join(path, "testnet") 107 } 108 } 109 endpoint = fmt.Sprintf("%s/neatio.ipc", path) 110 } 111 client, err := dialRPC(endpoint) 112 if err != nil { 113 utils.Fatalf("Unable to attach to remote neatio: %v", err) 114 } 115 config := console.Config{ 116 DataDir: utils.MakeDataDir(ctx), 117 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 118 Client: client, 119 Preload: utils.MakeConsolePreloads(ctx), 120 } 121 122 console, err := console.New(config) 123 if err != nil { 124 utils.Fatalf("Failed to start the JavaScript console: %v", err) 125 } 126 defer console.Stop(false) 127 128 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 129 console.Evaluate(script) 130 return nil 131 } 132 133 console.Welcome() 134 console.Interactive() 135 136 return nil 137 } 138 139 func dialRPC(endpoint string) (*rpc.Client, error) { 140 if endpoint == "" { 141 endpoint = node.DefaultIPCEndpoint(clientIdentifier) 142 } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { 143 endpoint = endpoint[4:] 144 } 145 return rpc.Dial(endpoint) 146 } 147 148 func ephemeralConsole(ctx *cli.Context) error { 149 chainName := ctx.Args().First() 150 if chainName == "" { 151 utils.Fatalf("This command requires chain name specified.") 152 } 153 154 node := makeFullNode(ctx, GetCMInstance(ctx).cch, chainName) 155 utils.StartNode(ctx, node) 156 defer node.Close() 157 158 client, err := node.Attach() 159 if err != nil { 160 utils.Fatalf("Failed to attach to the inproc neatio: %v", err) 161 } 162 config := console.Config{ 163 DataDir: utils.MakeDataDir(ctx), 164 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 165 Client: client, 166 Preload: utils.MakeConsolePreloads(ctx), 167 } 168 169 console, err := console.New(config) 170 if err != nil { 171 utils.Fatalf("Failed to start the JavaScript console: %v", err) 172 } 173 defer console.Stop(false) 174 175 for _, file := range ctx.Args() { 176 if err = console.Execute(file); err != nil { 177 utils.Fatalf("Failed to execute %s: %v", file, err) 178 } 179 } 180 abort := make(chan os.Signal, 1) 181 signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) 182 183 go func() { 184 <-abort 185 os.Exit(0) 186 }() 187 console.Stop(true) 188 189 return nil 190 }