github.com/aquanetwork/aquachain@v1.7.8/cmd/aquachain/consolecmd.go (about) 1 // Copyright 2016 The aquachain Authors 2 // This file is part of aquachain. 3 // 4 // aquachain is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // aquachain is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with aquachain. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "fmt" 21 "os" 22 "os/signal" 23 "path/filepath" 24 "strings" 25 "syscall" 26 27 "gitlab.com/aquachain/aquachain/cmd/utils" 28 "gitlab.com/aquachain/aquachain/node" 29 "gitlab.com/aquachain/aquachain/opt/console" 30 "gitlab.com/aquachain/aquachain/rpc" 31 "gopkg.in/urfave/cli.v1" 32 ) 33 34 var ( 35 consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} 36 37 consoleCommand = cli.Command{ 38 Action: utils.MigrateFlags(localConsole), 39 Name: "console", 40 Usage: "Start an interactive JavaScript environment", 41 Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...), 42 Category: "CONSOLE COMMANDS", 43 Description: ` 44 The AquaChain console is an interactive shell for the JavaScript runtime environment 45 which exposes a node admin interface as well as the Ðapp JavaScript API. 46 See https://gitlab.com/aquachain/aquachain/wiki/JavaScript-Console.`, 47 } 48 49 daemonCommand = cli.Command{ 50 Action: utils.MigrateFlags(daemonStart), 51 Name: "daemon", 52 Usage: "Start a full node", 53 Category: "CONSOLE COMMANDS", 54 Description: "", 55 } 56 57 attachCommand = cli.Command{ 58 Action: utils.MigrateFlags(remoteConsole), 59 Name: "attach", 60 Usage: "Start an interactive JavaScript environment (connect to node)", 61 ArgsUsage: "[endpoint]", 62 Flags: append(consoleFlags, utils.DataDirFlag), 63 Category: "CONSOLE COMMANDS", 64 Description: ` 65 The AquaChain console is an interactive shell for the JavaScript runtime environment 66 which exposes a node admin interface as well as the Ðapp JavaScript API. 67 See https://gitlab.com/aquachain/aquachain/wiki/JavaScript-Console. 68 This command allows to open a console on a running aquachain node.`, 69 } 70 71 javascriptCommand = cli.Command{ 72 Action: utils.MigrateFlags(ephemeralConsole), 73 Name: "js", 74 Usage: "Execute the specified JavaScript files", 75 ArgsUsage: "<jsfile> [jsfile...]", 76 Flags: append(nodeFlags, consoleFlags...), 77 Category: "CONSOLE COMMANDS", 78 Description: ` 79 The JavaScript VM exposes a node admin interface as well as the Ðapp 80 JavaScript API. See https://gitlab.com/aquachain/aquachain/wiki/JavaScript-Console`, 81 } 82 ) 83 84 // localConsole starts a new aquachain node, attaching a JavaScript console to it at the 85 // same time. 86 func localConsole(ctx *cli.Context) error { 87 // Create and start the node based on the CLI flags 88 if args := ctx.Args(); len(args) != 0 && args[0] != "console" { 89 return fmt.Errorf("invalid command: %q", args[0]) 90 } 91 node := makeFullNode(ctx) 92 startNode(ctx, node) 93 defer node.Stop() 94 95 // Attach to the newly started node and start the JavaScript console 96 client, err := node.Attach() 97 if err != nil { 98 utils.Fatalf("Failed to attach to the inproc aquachain: %v", err) 99 } 100 config := console.Config{ 101 DataDir: utils.MakeDataDir(ctx), 102 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 103 Client: client, 104 Preload: utils.MakeConsolePreloads(ctx), 105 } 106 107 console, err := console.New(config) 108 if err != nil { 109 utils.Fatalf("Failed to start the JavaScript console: %v", err) 110 } 111 defer console.Stop(false) 112 113 // If only a short execution was requested, evaluate and return 114 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 115 console.Evaluate(script) 116 return nil 117 } 118 // Otherwise print the welcome screen and enter interactive mode 119 console.Welcome() 120 console.Interactive() 121 122 return nil 123 } 124 125 // remoteConsole will connect to a remote aquachain instance, attaching a JavaScript 126 // console to it. 127 func remoteConsole(ctx *cli.Context) error { 128 // Attach to a remotely running aquachain instance and start the JavaScript console 129 endpoint := ctx.Args().First() 130 if endpoint == "" { 131 path := node.DefaultDataDir() 132 if ctx.GlobalIsSet(utils.DataDirFlag.Name) { 133 path = ctx.GlobalString(utils.DataDirFlag.Name) 134 } 135 if path != "" { 136 if ctx.GlobalBool(utils.TestnetFlag.Name) { 137 path = filepath.Join(path, "testnet") 138 } else if ctx.GlobalBool(utils.Testnet2Flag.Name) { 139 path = filepath.Join(path, "testnet2") 140 } 141 } 142 endpoint = fmt.Sprintf("%s/aquachain.ipc", path) 143 } 144 client, err := dialRPC(endpoint) 145 if err != nil { 146 utils.Fatalf("Unable to attach to remote aquachain: %v", err) 147 } 148 config := console.Config{ 149 DataDir: utils.MakeDataDir(ctx), 150 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 151 Client: client, 152 Preload: utils.MakeConsolePreloads(ctx), 153 } 154 155 console, err := console.New(config) 156 if err != nil { 157 utils.Fatalf("Failed to start the JavaScript console: %v", err) 158 } 159 defer console.Stop(false) 160 161 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 162 console.Evaluate(script) 163 return nil 164 } 165 166 // Otherwise print the welcome screen and enter interactive mode 167 console.Welcome() 168 console.Interactive() 169 170 return nil 171 } 172 173 // dialRPC returns a RPC client which connects to the given endpoint. 174 // The check for empty endpoint implements the defaulting logic 175 // for "aquachain attach" and "aquachain monitor" with no argument. 176 func dialRPC(endpoint string) (*rpc.Client, error) { 177 if endpoint == "" { 178 endpoint = node.DefaultIPCEndpoint(clientIdentifier) 179 } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { 180 // Backwards compatibility with aquachain < 1.5 which required 181 // these prefixes. 182 endpoint = endpoint[4:] 183 } 184 return rpc.Dial(endpoint) 185 } 186 187 // ephemeralConsole starts a new aquachain node, attaches an ephemeral JavaScript 188 // console to it, executes each of the files specified as arguments and tears 189 // everything down. 190 func ephemeralConsole(ctx *cli.Context) error { 191 // Create and start the node based on the CLI flags 192 node := makeFullNode(ctx) 193 startNode(ctx, node) 194 defer node.Stop() 195 196 // Attach to the newly started node and start the JavaScript console 197 client, err := node.Attach() 198 if err != nil { 199 utils.Fatalf("Failed to attach to the inproc aquachain: %v", err) 200 } 201 config := console.Config{ 202 DataDir: utils.MakeDataDir(ctx), 203 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 204 Client: client, 205 Preload: utils.MakeConsolePreloads(ctx), 206 } 207 208 console, err := console.New(config) 209 if err != nil { 210 utils.Fatalf("Failed to start the JavaScript console: %v", err) 211 } 212 defer console.Stop(false) 213 214 // Evaluate each of the specified JavaScript files 215 for _, file := range ctx.Args() { 216 if err = console.Execute(file); err != nil { 217 utils.Fatalf("Failed to execute %s: %v", file, err) 218 } 219 } 220 // Wait for pending callbacks, but stop for Ctrl-C. 221 abort := make(chan os.Signal, 1) 222 signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) 223 224 go func() { 225 <-abort 226 os.Exit(0) 227 }() 228 console.Stop(true) 229 230 return nil 231 }