github.com/core-coin/go-core/v2@v2.1.9/cmd/gocore/consolecmd.go (about) 1 // Copyright 2016 by the Authors 2 // This file is part of go-core. 3 // 4 // go-core 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 // go-core 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 go-core. 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 "gopkg.in/urfave/cli.v1" 28 29 "github.com/core-coin/go-core/v2/cmd/utils" 30 "github.com/core-coin/go-core/v2/console" 31 "github.com/core-coin/go-core/v2/node" 32 "github.com/core-coin/go-core/v2/rpc" 33 ) 34 35 var ( 36 consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} 37 38 consoleCommand = cli.Command{ 39 Action: utils.MigrateFlags(localConsole), 40 Name: "console", 41 Usage: "Start an interactive JavaScript environment", 42 Flags: append(append(nodeFlags, rpcFlags...), consoleFlags...), 43 Category: "CONSOLE COMMANDS", 44 Description: ` 45 The Gocore console is an interactive shell for the JavaScript runtime environment 46 which exposes a node admin interface as well as the Ðapp JavaScript API. 47 See https://github.com/core-coin/go-core/v2/wiki/JavaScript-Console.`, 48 } 49 50 attachCommand = cli.Command{ 51 Action: utils.MigrateFlags(remoteConsole), 52 Name: "attach", 53 Usage: "Start an interactive JavaScript environment (connect to node)", 54 ArgsUsage: "[endpoint]", 55 Flags: append(consoleFlags, utils.DataDirFlag), 56 Category: "CONSOLE COMMANDS", 57 Description: ` 58 The Gocore console is an interactive shell for the JavaScript runtime environment 59 which exposes a node admin interface as well as the Ðapp JavaScript API. 60 See https://github.com/core-coin/go-core/v2/wiki/JavaScript-Console. 61 This command allows to open a console on a running gocore node.`, 62 } 63 64 javascriptCommand = cli.Command{ 65 Action: utils.MigrateFlags(ephemeralConsole), 66 Name: "js", 67 Usage: "Execute the specified JavaScript files", 68 ArgsUsage: "<jsfile> [jsfile...]", 69 Flags: append(nodeFlags, consoleFlags...), 70 Category: "CONSOLE COMMANDS", 71 Description: ` 72 The JavaScript VM exposes a node admin interface as well as the Ðapp 73 JavaScript API. See https://github.com/core-coin/go-core/v2/wiki/JavaScript-Console`, 74 } 75 ) 76 77 // localConsole starts a new gocore node, attaching a JavaScript console to it at the 78 // same time. 79 func localConsole(ctx *cli.Context) error { 80 // Create and start the node based on the CLI flags 81 prepare(ctx) 82 stack, backend := makeFullNode(ctx) 83 startNode(ctx, stack, backend) 84 defer stack.Close() 85 86 // Attach to the newly started node and start the JavaScript console 87 client, err := stack.Attach() 88 if err != nil { 89 utils.Fatalf("Failed to attach to the inproc gocore: %v", err) 90 } 91 config := console.Config{ 92 DataDir: utils.MakeDataDir(ctx), 93 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 94 Client: client, 95 Preload: utils.MakeConsolePreloads(ctx), 96 } 97 98 console, err := console.New(config) 99 if err != nil { 100 utils.Fatalf("Failed to start the JavaScript console: %v", err) 101 } 102 defer console.Stop(false) 103 104 // If only a short execution was requested, evaluate and return 105 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 106 console.Evaluate(script) 107 return nil 108 } 109 // Otherwise print the welcome screen and enter interactive mode 110 console.Welcome() 111 console.Interactive() 112 113 return nil 114 } 115 116 // remoteConsole will connect to a remote gocore instance, attaching a JavaScript 117 // console to it. 118 func remoteConsole(ctx *cli.Context) error { 119 // Attach to a remotely running gocore instance and start the JavaScript console 120 endpoint := ctx.Args().First() 121 if endpoint == "" { 122 path := node.DefaultDataDir() 123 if ctx.GlobalIsSet(utils.DataDirFlag.Name) { 124 path = ctx.GlobalString(utils.DataDirFlag.Name) 125 } 126 if path != "" { 127 if ctx.GlobalBool(utils.DevinFlag.Name) { 128 // Maintain compatibility with older Gocore configurations storing the 129 // Devin database in `testnet` instead of `devin`. 130 legacyPath := filepath.Join(path, "testnet") 131 if _, err := os.Stat(legacyPath); !os.IsNotExist(err) { 132 path = legacyPath 133 } else { 134 path = filepath.Join(path, "devin") 135 } 136 } 137 } 138 endpoint = fmt.Sprintf("%s/gocore.ipc", path) 139 } 140 client, err := dialRPC(endpoint) 141 if err != nil { 142 utils.Fatalf("Unable to attach to remote gocore: %v", err) 143 } 144 config := console.Config{ 145 DataDir: utils.MakeDataDir(ctx), 146 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 147 Client: client, 148 Preload: utils.MakeConsolePreloads(ctx), 149 } 150 151 console, err := console.New(config) 152 if err != nil { 153 utils.Fatalf("Failed to start the JavaScript console: %v", err) 154 } 155 defer console.Stop(false) 156 157 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 158 console.Evaluate(script) 159 return nil 160 } 161 162 // Otherwise print the welcome screen and enter interactive mode 163 console.Welcome() 164 console.Interactive() 165 166 return nil 167 } 168 169 // dialRPC returns a RPC client which connects to the given endpoint. 170 // The check for empty endpoint implements the defaulting logic 171 // for "gocore attach" and "gocore monitor" with no argument. 172 func dialRPC(endpoint string) (*rpc.Client, error) { 173 if endpoint == "" { 174 endpoint = node.DefaultIPCEndpoint(clientIdentifier) 175 } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { 176 // Backwards compatibility with gocore < 1.5 which required 177 // these prefixes. 178 endpoint = endpoint[4:] 179 } 180 return rpc.Dial(endpoint) 181 } 182 183 // ephemeralConsole starts a new gocore node, attaches an ephemeral JavaScript 184 // console to it, executes each of the files specified as arguments and tears 185 // everything down. 186 func ephemeralConsole(ctx *cli.Context) error { 187 // Create and start the node based on the CLI flags 188 stack, backend := makeFullNode(ctx) 189 startNode(ctx, stack, backend) 190 defer stack.Close() 191 192 // Attach to the newly started node and start the JavaScript console 193 client, err := stack.Attach() 194 if err != nil { 195 utils.Fatalf("Failed to attach to the inproc gocore: %v", err) 196 } 197 config := console.Config{ 198 DataDir: utils.MakeDataDir(ctx), 199 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 200 Client: client, 201 Preload: utils.MakeConsolePreloads(ctx), 202 } 203 204 console, err := console.New(config) 205 if err != nil { 206 utils.Fatalf("Failed to start the JavaScript console: %v", err) 207 } 208 defer console.Stop(false) 209 210 // Evaluate each of the specified JavaScript files 211 for _, file := range ctx.Args() { 212 if err = console.Execute(file); err != nil { 213 utils.Fatalf("Failed to execute %s: %v", file, err) 214 } 215 } 216 // Wait for pending callbacks, but stop for Ctrl-C. 217 abort := make(chan os.Signal, 1) 218 signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) 219 220 go func() { 221 <-abort 222 os.Exit(0) 223 }() 224 console.Stop(true) 225 226 return nil 227 }