go-ethereum/internal/cli/server/console.go
2022-05-09 17:08:03 +02:00

163 lines
3.8 KiB
Go

package server
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/mitchellh/cli"
)
// ConsoleCommand is the command to Connect to remote Bor IPC console
type ConsoleCommand struct {
// cli configuration
cliConfig *Config
// final configuration
config *Config
configFile []string
UI cli.Ui
ExecCMD string
Endpoint string
PreloadJSFlag string
JSpathFlag string
srv *Server
}
// Help implements the cli.Command interface
func (c *ConsoleCommand) Help() string {
return `Usage: bor console
Connect to local Bor IPC console.`
}
// Synopsis implements the cli.Command interface
func (c *ConsoleCommand) Synopsis() string {
return "Connect to Bor console"
}
// Run implements the cli.Command interface
func (c *ConsoleCommand) Run(args []string) int {
flags := c.Flags()
if err := flags.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
// read config file
config := DefaultConfig()
for _, configFile := range c.configFile {
cfg, err := readConfigFile(configFile)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if err := config.Merge(cfg); err != nil {
c.UI.Error(err.Error())
return 1
}
}
if err := config.Merge(c.cliConfig); err != nil {
c.UI.Error(err.Error())
return 1
}
c.config = config
srv, err := NewServer(config)
if err != nil {
c.UI.Error(err.Error())
return 1
}
c.srv = srv
c.localConsole()
return 0
}
// localConsole starts a new geth node, attaching a JavaScript console to it at the
// same time.
func (c *ConsoleCommand) localConsole() error {
// Create and start the node based on the CLI flags
stack := c.srv.node
stack.Start()
defer stack.Close()
path := node.DefaultDataDir()
if c.Endpoint == "" {
if c.config.DataDir != "" {
path = c.config.DataDir
}
if path != "" {
homeDir, _ := os.UserHomeDir()
path = filepath.Join(homeDir, "/.bor/data")
}
c.Endpoint = fmt.Sprintf("%s/bor.ipc", path)
}
// Attach to the newly started node and start the JavaScript console
client, err := stack.Attach()
if err != nil {
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
}
config := console.Config{
DataDir: path,
DocRoot: c.JSpathFlag,
Client: client,
Preload: c.MakeConsolePreloads(),
}
console, err := console.New(config)
if err != nil {
utils.Fatalf("Failed to start the JavaScript console: %v", err)
}
defer console.Stop(false)
// If only a short execution was requested, evaluate and return
if script := c.ExecCMD; script != "" {
console.Evaluate(script)
return nil
}
// Otherwise print the welcome screen and enter interactive mode
console.Welcome()
console.Interactive()
return nil
}
// dialRPC returns a RPC client which connects to the given endpoint.
// The check for empty endpoint implements the defaulting logic
// for "geth attach" with no argument.
func dialRPC(endpoint string) (*rpc.Client, error) {
if endpoint == "" {
endpoint = node.DefaultIPCEndpoint("bor")
} else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") {
// Backwards compatibility with geth < 1.5 which required
// these prefixes.
endpoint = endpoint[4:]
}
return rpc.Dial(endpoint)
}
// MakeConsolePreloads retrieves the absolute paths for the console JavaScript
// scripts to preload before starting.
func (c *ConsoleCommand) MakeConsolePreloads() []string {
// Skip preloading if there's nothing to preload
if c.PreloadJSFlag == "" {
return nil
}
// Otherwise resolve absolute paths and return them
var preloads []string
for _, file := range strings.Split(c.PreloadJSFlag, ",") {
preloads = append(preloads, strings.TrimSpace(file))
}
return preloads
}