github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/cmd/puppeth/wizard.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of go-wtc.
     3  //
     4  // go-wtc 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-wtc 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-wtc. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"bufio"
    21  	"encoding/json"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"math/big"
    25  	"net"
    26  	"os"
    27  	"path/filepath"
    28  	"sort"
    29  	"strconv"
    30  	"strings"
    31  	"syscall"
    32  
    33  	"github.com/wtc/go-wtc/common"
    34  	"github.com/wtc/go-wtc/core"
    35  	"github.com/wtc/go-wtc/log"
    36  	"golang.org/x/crypto/ssh/terminal"
    37  )
    38  
    39  // config contains all the configurations needed by puppeth that should be saved
    40  // between sessions.
    41  type config struct {
    42  	path      string        // File containing the configuration values
    43  	genesis   *core.Genesis // Genesis block to cache for node deploys
    44  	bootFull  []string      // Bootnodes to always connect to by full nodes
    45  	bootLight []string      // Bootnodes to always connect to by light nodes
    46  	ethstats  string        // Ethstats settings to cache for node deploys
    47  
    48  	Servers map[string][]byte `json:"servers,omitempty"`
    49  }
    50  
    51  // servers retrieves an alphabetically sorted list of servers.
    52  func (c config) servers() []string {
    53  	servers := make([]string, 0, len(c.Servers))
    54  	for server := range c.Servers {
    55  		servers = append(servers, server)
    56  	}
    57  	sort.Strings(servers)
    58  
    59  	return servers
    60  }
    61  
    62  // flush dumps the contents of config to disk.
    63  func (c config) flush() {
    64  	os.MkdirAll(filepath.Dir(c.path), 0755)
    65  
    66  	out, _ := json.MarshalIndent(c, "", "  ")
    67  	if err := ioutil.WriteFile(c.path, out, 0644); err != nil {
    68  		log.Warn("Failed to save puppeth configs", "file", c.path, "err", err)
    69  	}
    70  }
    71  
    72  type wizard struct {
    73  	network string // Network name to manage
    74  	conf    config // Configurations from previous runs
    75  
    76  	servers  map[string]*sshClient // SSH connections to servers to administer
    77  	services map[string][]string   // Wtc services known to be running on servers
    78  
    79  	in *bufio.Reader // Wrapper around stdin to allow reading user input
    80  }
    81  
    82  // read reads a single line from stdin, trimming if from spaces.
    83  func (w *wizard) read() string {
    84  	fmt.Printf("> ")
    85  	text, err := w.in.ReadString('\n')
    86  	if err != nil {
    87  		log.Crit("Failed to read user input", "err", err)
    88  	}
    89  	return strings.TrimSpace(text)
    90  }
    91  
    92  // readString reads a single line from stdin, trimming if from spaces, enforcing
    93  // non-emptyness.
    94  func (w *wizard) readString() string {
    95  	for {
    96  		fmt.Printf("> ")
    97  		text, err := w.in.ReadString('\n')
    98  		if err != nil {
    99  			log.Crit("Failed to read user input", "err", err)
   100  		}
   101  		if text = strings.TrimSpace(text); text != "" {
   102  			return text
   103  		}
   104  	}
   105  }
   106  
   107  // readDefaultString reads a single line from stdin, trimming if from spaces. If
   108  // an empty line is entered, the default value is returned.
   109  func (w *wizard) readDefaultString(def string) string {
   110  	fmt.Printf("> ")
   111  	text, err := w.in.ReadString('\n')
   112  	if err != nil {
   113  		log.Crit("Failed to read user input", "err", err)
   114  	}
   115  	if text = strings.TrimSpace(text); text != "" {
   116  		return text
   117  	}
   118  	return def
   119  }
   120  
   121  // readInt reads a single line from stdin, trimming if from spaces, enforcing it
   122  // to parse into an integer.
   123  func (w *wizard) readInt() int {
   124  	for {
   125  		fmt.Printf("> ")
   126  		text, err := w.in.ReadString('\n')
   127  		if err != nil {
   128  			log.Crit("Failed to read user input", "err", err)
   129  		}
   130  		if text = strings.TrimSpace(text); text == "" {
   131  			continue
   132  		}
   133  		val, err := strconv.Atoi(strings.TrimSpace(text))
   134  		if err != nil {
   135  			log.Error("Invalid input, expected integer", "err", err)
   136  			continue
   137  		}
   138  		return val
   139  	}
   140  }
   141  
   142  // readDefaultInt reads a single line from stdin, trimming if from spaces, enforcing
   143  // it to parse into an integer. If an empty line is entered, the default value is
   144  // returned.
   145  func (w *wizard) readDefaultInt(def int) int {
   146  	for {
   147  		fmt.Printf("> ")
   148  		text, err := w.in.ReadString('\n')
   149  		if err != nil {
   150  			log.Crit("Failed to read user input", "err", err)
   151  		}
   152  		if text = strings.TrimSpace(text); text == "" {
   153  			return def
   154  		}
   155  		val, err := strconv.Atoi(strings.TrimSpace(text))
   156  		if err != nil {
   157  			log.Error("Invalid input, expected integer", "err", err)
   158  			continue
   159  		}
   160  		return val
   161  	}
   162  }
   163  
   164  /*
   165  // readFloat reads a single line from stdin, trimming if from spaces, enforcing it
   166  // to parse into a float.
   167  func (w *wizard) readFloat() float64 {
   168  	for {
   169  		fmt.Printf("> ")
   170  		text, err := w.in.ReadString('\n')
   171  		if err != nil {
   172  			log.Crit("Failed to read user input", "err", err)
   173  		}
   174  		if text = strings.TrimSpace(text); text == "" {
   175  			continue
   176  		}
   177  		val, err := strconv.ParseFloat(strings.TrimSpace(text), 64)
   178  		if err != nil {
   179  			log.Error("Invalid input, expected float", "err", err)
   180  			continue
   181  		}
   182  		return val
   183  	}
   184  }
   185  */
   186  
   187  // readDefaultFloat reads a single line from stdin, trimming if from spaces, enforcing
   188  // it to parse into a float. If an empty line is entered, the default value is returned.
   189  func (w *wizard) readDefaultFloat(def float64) float64 {
   190  	for {
   191  		fmt.Printf("> ")
   192  		text, err := w.in.ReadString('\n')
   193  		if err != nil {
   194  			log.Crit("Failed to read user input", "err", err)
   195  		}
   196  		if text = strings.TrimSpace(text); text == "" {
   197  			return def
   198  		}
   199  		val, err := strconv.ParseFloat(strings.TrimSpace(text), 64)
   200  		if err != nil {
   201  			log.Error("Invalid input, expected float", "err", err)
   202  			continue
   203  		}
   204  		return val
   205  	}
   206  }
   207  
   208  // readPassword reads a single line from stdin, trimming it from the trailing new
   209  // line and returns it. The input will not be echoed.
   210  func (w *wizard) readPassword() string {
   211  	fmt.Printf("> ")
   212  	text, err := terminal.ReadPassword(int(syscall.Stdin))
   213  	if err != nil {
   214  		log.Crit("Failed to read password", "err", err)
   215  	}
   216  	fmt.Println()
   217  	return string(text)
   218  }
   219  
   220  // readAddress reads a single line from stdin, trimming if from spaces and converts
   221  // it to an Wtc address.
   222  func (w *wizard) readAddress() *common.Address {
   223  	for {
   224  		// Read the address from the user
   225  		fmt.Printf("> 0x")
   226  		text, err := w.in.ReadString('\n')
   227  		if err != nil {
   228  			log.Crit("Failed to read user input", "err", err)
   229  		}
   230  		if text = strings.TrimSpace(text); text == "" {
   231  			return nil
   232  		}
   233  		// Make sure it looks ok and return it if so
   234  		if len(text) != 40 {
   235  			log.Error("Invalid address length, please retry")
   236  			continue
   237  		}
   238  		bigaddr, _ := new(big.Int).SetString(text, 16)
   239  		address := common.BigToAddress(bigaddr)
   240  		return &address
   241  	}
   242  }
   243  
   244  // readDefaultAddress reads a single line from stdin, trimming if from spaces and
   245  // converts it to an Wtc address. If an empty line is entered, the default
   246  // value is returned.
   247  func (w *wizard) readDefaultAddress(def common.Address) common.Address {
   248  	for {
   249  		// Read the address from the user
   250  		fmt.Printf("> 0x")
   251  		text, err := w.in.ReadString('\n')
   252  		if err != nil {
   253  			log.Crit("Failed to read user input", "err", err)
   254  		}
   255  		if text = strings.TrimSpace(text); text == "" {
   256  			return def
   257  		}
   258  		// Make sure it looks ok and return it if so
   259  		if len(text) != 40 {
   260  			log.Error("Invalid address length, please retry")
   261  			continue
   262  		}
   263  		bigaddr, _ := new(big.Int).SetString(text, 16)
   264  		return common.BigToAddress(bigaddr)
   265  	}
   266  }
   267  
   268  // readJSON reads a raw JSON message and returns it.
   269  func (w *wizard) readJSON() string {
   270  	var blob json.RawMessage
   271  
   272  	for {
   273  		fmt.Printf("> ")
   274  		if err := json.NewDecoder(w.in).Decode(&blob); err != nil {
   275  			log.Error("Invalid JSON, please try again", "err", err)
   276  			continue
   277  		}
   278  		return string(blob)
   279  	}
   280  }
   281  
   282  // readIPAddress reads a single line from stdin, trimming if from spaces and
   283  // converts it to a network IP address.
   284  func (w *wizard) readIPAddress() net.IP {
   285  	for {
   286  		// Read the IP address from the user
   287  		fmt.Printf("> ")
   288  		text, err := w.in.ReadString('\n')
   289  		if err != nil {
   290  			log.Crit("Failed to read user input", "err", err)
   291  		}
   292  		if text = strings.TrimSpace(text); text == "" {
   293  			return nil
   294  		}
   295  		// Make sure it looks ok and return it if so
   296  		ip := net.ParseIP(text)
   297  		if ip == nil {
   298  			log.Error("Invalid IP address, please retry")
   299  			continue
   300  		}
   301  		return ip
   302  	}
   303  }