consolecmd.go 5.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// Copyright 2016 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.

package main

import (
20
	"fmt"
21
	"strings"
22 23 24

	"github.com/ethereum/go-ethereum/cmd/utils"
	"github.com/ethereum/go-ethereum/console"
25
	"github.com/ethereum/go-ethereum/internal/flags"
26
	"github.com/urfave/cli/v2"
27 28
)

29 30 31
var (
	consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}

32 33 34 35
	consoleCommand = &cli.Command{
		Action: localConsole,
		Name:   "console",
		Usage:  "Start an interactive JavaScript environment",
36
		Flags:  flags.Merge(nodeFlags, rpcFlags, consoleFlags),
37 38 39
		Description: `
The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
40
See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.`,
41
	}
42

43 44
	attachCommand = &cli.Command{
		Action:    remoteConsole,
45 46
		Name:      "attach",
		Usage:     "Start an interactive JavaScript environment (connect to node)",
47
		ArgsUsage: "[endpoint]",
48
		Flags:     flags.Merge([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags),
49 50 51
		Description: `
The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
52
See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.
53
This command allows to open a console on a running geth node.`,
54
	}
55

56 57
	javascriptCommand = &cli.Command{
		Action:    ephemeralConsole,
58
		Name:      "js",
59
		Usage:     "(DEPRECATED) Execute the specified JavaScript files",
60
		ArgsUsage: "<jsfile> [jsfile...]",
61
		Flags:     flags.Merge(nodeFlags, consoleFlags),
62 63
		Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp
64
JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console`,
65 66 67 68 69
	}
)

// localConsole starts a new geth node, attaching a JavaScript console to it at the
// same time.
70
func localConsole(ctx *cli.Context) error {
71
	// Create and start the node based on the CLI flags
72
	prepare(ctx)
73
	stack, backend := makeFullNode(ctx)
74
	startNode(ctx, stack, backend, true)
75
	defer stack.Close()
76

77
	// Attach to the newly started node and create the JavaScript console.
78
	client := stack.Attach()
79
	config := console.Config{
80
		DataDir: utils.MakeDataDir(ctx),
81
		DocRoot: ctx.String(utils.JSpathFlag.Name),
82 83 84 85 86
		Client:  client,
		Preload: utils.MakeConsolePreloads(ctx),
	}
	console, err := console.New(config)
	if err != nil {
87
		return fmt.Errorf("failed to start the JavaScript console: %v", err)
88 89 90
	}
	defer console.Stop(false)

91
	// If only a short execution was requested, evaluate and return.
92
	if script := ctx.String(utils.ExecFlag.Name); script != "" {
93
		console.Evaluate(script)
94
		return nil
95
	}
96 97 98 99 100 101 102 103 104

	// Track node shutdown and stop the console when it goes down.
	// This happens when SIGTERM is sent to the process.
	go func() {
		stack.Wait()
		console.StopInteractive()
	}()

	// Print the welcome screen and enter interactive mode.
105 106
	console.Welcome()
	console.Interactive()
107
	return nil
108 109 110 111
}

// remoteConsole will connect to a remote geth instance, attaching a JavaScript
// console to it.
112
func remoteConsole(ctx *cli.Context) error {
113 114 115
	if ctx.Args().Len() > 1 {
		utils.Fatalf("invalid command-line: too many arguments")
	}
116
	endpoint := ctx.Args().First()
117
	if endpoint == "" {
118 119 120
		cfg := defaultNodeConfig()
		utils.SetDataDir(ctx, &cfg)
		endpoint = cfg.IPCEndpoint()
121
	}
122
	client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name))
123 124 125 126
	if err != nil {
		utils.Fatalf("Unable to attach to remote geth: %v", err)
	}
	config := console.Config{
127
		DataDir: utils.MakeDataDir(ctx),
128
		DocRoot: ctx.String(utils.JSpathFlag.Name),
129 130 131 132 133 134 135 136 137
		Client:  client,
		Preload: utils.MakeConsolePreloads(ctx),
	}
	console, err := console.New(config)
	if err != nil {
		utils.Fatalf("Failed to start the JavaScript console: %v", err)
	}
	defer console.Stop(false)

138
	if script := ctx.String(utils.ExecFlag.Name); script != "" {
139
		console.Evaluate(script)
140
		return nil
141
	}
142

143 144 145
	// Otherwise print the welcome screen and enter interactive mode
	console.Welcome()
	console.Interactive()
146
	return nil
147 148
}

149 150 151 152 153
// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript
// console to it, executes each of the files specified as arguments and tears
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
	var b strings.Builder
154
	for _, file := range ctx.Args().Slice() {
155 156 157 158 159 160
		b.Write([]byte(fmt.Sprintf("loadScript('%s');", file)))
	}
	utils.Fatalf(`The "js" command is deprecated. Please use the following instead:
geth --exec "%s" console`, b.String())
	return nil
}