github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/cmd/puppeth/wizard_netstats.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  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"strings"
    24  
    25  	"github.com/wtc/go-wtc/core"
    26  	"github.com/wtc/go-wtc/log"
    27  	"github.com/olekukonko/tablewriter"
    28  )
    29  
    30  // networkStats verifies the status of network components and generates a protip
    31  // configuration set to give users hints on how to do various tasks.
    32  func (w *wizard) networkStats(tips bool) {
    33  	if len(w.servers) == 0 {
    34  		log.Error("No remote machines to gather stats from")
    35  		return
    36  	}
    37  	protips := new(protips)
    38  
    39  	// Iterate over all the specified hosts and check their status
    40  	stats := tablewriter.NewWriter(os.Stdout)
    41  	stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
    42  	stats.SetColWidth(100)
    43  
    44  	for server, pubkey := range w.conf.Servers {
    45  		client := w.servers[server]
    46  		logger := log.New("server", server)
    47  		logger.Info("Starting remote server health-check")
    48  
    49  		// If the server is not connected, try to connect again
    50  		if client == nil {
    51  			conn, err := dial(server, pubkey)
    52  			if err != nil {
    53  				logger.Error("Failed to establish remote connection", "err", err)
    54  				stats.Append([]string{server, "", err.Error(), "", ""})
    55  				continue
    56  			}
    57  			client = conn
    58  		}
    59  		// Client connected one way or another, run health-checks
    60  		services := make(map[string]string)
    61  		logger.Debug("Checking for nginx availability")
    62  		if infos, err := checkNginx(client, w.network); err != nil {
    63  			if err != ErrServiceUnknown {
    64  				services["nginx"] = err.Error()
    65  			}
    66  		} else {
    67  			services["nginx"] = infos.String()
    68  		}
    69  		logger.Debug("Checking for ethstats availability")
    70  		if infos, err := checkEthstats(client, w.network); err != nil {
    71  			if err != ErrServiceUnknown {
    72  				services["ethstats"] = err.Error()
    73  			}
    74  		} else {
    75  			services["ethstats"] = infos.String()
    76  			protips.ethstats = infos.config
    77  		}
    78  		logger.Debug("Checking for bootnode availability")
    79  		if infos, err := checkNode(client, w.network, true); err != nil {
    80  			if err != ErrServiceUnknown {
    81  				services["bootnode"] = err.Error()
    82  			}
    83  		} else {
    84  			services["bootnode"] = infos.String()
    85  
    86  			protips.genesis = string(infos.genesis)
    87  			protips.bootFull = append(protips.bootFull, infos.enodeFull)
    88  			if infos.enodeLight != "" {
    89  				protips.bootLight = append(protips.bootLight, infos.enodeLight)
    90  			}
    91  		}
    92  		logger.Debug("Checking for sealnode availability")
    93  		if infos, err := checkNode(client, w.network, false); err != nil {
    94  			if err != ErrServiceUnknown {
    95  				services["sealnode"] = err.Error()
    96  			}
    97  		} else {
    98  			services["sealnode"] = infos.String()
    99  			protips.genesis = string(infos.genesis)
   100  		}
   101  		logger.Debug("Checking for faucet availability")
   102  		if infos, err := checkFaucet(client, w.network); err != nil {
   103  			if err != ErrServiceUnknown {
   104  				services["faucet"] = err.Error()
   105  			}
   106  		} else {
   107  			services["faucet"] = infos.String()
   108  		}
   109  		logger.Debug("Checking for dashboard availability")
   110  		if infos, err := checkDashboard(client, w.network); err != nil {
   111  			if err != ErrServiceUnknown {
   112  				services["dashboard"] = err.Error()
   113  			}
   114  		} else {
   115  			services["dashboard"] = infos.String()
   116  		}
   117  		// All status checks complete, report and check next server
   118  		delete(w.services, server)
   119  		for service := range services {
   120  			w.services[server] = append(w.services[server], service)
   121  		}
   122  		server, address := client.server, client.address
   123  		for service, status := range services {
   124  			stats.Append([]string{server, address, "online", service, status})
   125  			server, address = "", ""
   126  		}
   127  		if len(services) == 0 {
   128  			stats.Append([]string{server, address, "online", "", ""})
   129  		}
   130  	}
   131  	// If a genesis block was found, load it into our configs
   132  	if protips.genesis != "" {
   133  		genesis := new(core.Genesis)
   134  		if err := json.Unmarshal([]byte(protips.genesis), genesis); err != nil {
   135  			log.Error("Failed to parse remote genesis", "err", err)
   136  		} else {
   137  			w.conf.genesis = genesis
   138  			protips.network = genesis.Config.ChainId.Int64()
   139  		}
   140  	}
   141  	if protips.ethstats != "" {
   142  		w.conf.ethstats = protips.ethstats
   143  	}
   144  	w.conf.bootFull = protips.bootFull
   145  	w.conf.bootLight = protips.bootLight
   146  
   147  	// Print any collected stats and return
   148  	if !tips {
   149  		stats.Render()
   150  	} else {
   151  		protips.print(w.network)
   152  	}
   153  }
   154  
   155  // protips contains a collection of network infos to report pro-tips
   156  // based on.
   157  type protips struct {
   158  	genesis   string
   159  	network   int64
   160  	bootFull  []string
   161  	bootLight []string
   162  	ethstats  string
   163  }
   164  
   165  // print analyzes the network information available and prints a collection of
   166  // pro tips for the user's consideration.
   167  func (p *protips) print(network string) {
   168  	// If a known genesis block is available, display it and prepend an init command
   169  	fullinit, lightinit := "", ""
   170  	if p.genesis != "" {
   171  		fullinit = fmt.Sprintf("gwtc --datadir=$HOME/.%s init %s.json && ", network, network)
   172  		lightinit = fmt.Sprintf("gwtc --datadir=$HOME/.%s --light init %s.json && ", network, network)
   173  	}
   174  	// If an ethstats server is available, add the ethstats flag
   175  	statsflag := ""
   176  	if p.ethstats != "" {
   177  		if strings.Contains(p.ethstats, " ") {
   178  			statsflag = fmt.Sprintf(` --ethstats="yournode:%s"`, p.ethstats)
   179  		} else {
   180  			statsflag = fmt.Sprintf(` --ethstats=yournode:%s`, p.ethstats)
   181  		}
   182  	}
   183  	// If bootnodes have been specified, add the bootnode flag
   184  	bootflagFull := ""
   185  	if len(p.bootFull) > 0 {
   186  		bootflagFull = fmt.Sprintf(` --bootnodes %s`, strings.Join(p.bootFull, ","))
   187  	}
   188  	bootflagLight := ""
   189  	if len(p.bootLight) > 0 {
   190  		bootflagLight = fmt.Sprintf(` --bootnodes %s`, strings.Join(p.bootLight, ","))
   191  	}
   192  	// Assemble all the known pro-tips
   193  	var tasks, tips []string
   194  
   195  	tasks = append(tasks, "Run an archive node with historical data")
   196  	tips = append(tips, fmt.Sprintf("%sgwtc --networkid=%d --datadir=$HOME/.%s --cache=1024%s%s", fullinit, p.network, network, statsflag, bootflagFull))
   197  
   198  	tasks = append(tasks, "Run a full node with recent data only")
   199  	tips = append(tips, fmt.Sprintf("%sgwtc --networkid=%d --datadir=$HOME/.%s --cache=512 --fast%s%s", fullinit, p.network, network, statsflag, bootflagFull))
   200  
   201  	tasks = append(tasks, "Run a light node with on demand retrievals")
   202  	tips = append(tips, fmt.Sprintf("%sgwtc --networkid=%d --datadir=$HOME/.%s --light%s%s", lightinit, p.network, network, statsflag, bootflagLight))
   203  
   204  	tasks = append(tasks, "Run an embedded node with constrained memory")
   205  	tips = append(tips, fmt.Sprintf("%sgwtc --networkid=%d --datadir=$HOME/.%s --cache=32 --light%s%s", lightinit, p.network, network, statsflag, bootflagLight))
   206  
   207  	// If the tips are short, display in a table
   208  	short := true
   209  	for _, tip := range tips {
   210  		if len(tip) > 100 {
   211  			short = false
   212  			break
   213  		}
   214  	}
   215  	fmt.Println()
   216  	if short {
   217  		howto := tablewriter.NewWriter(os.Stdout)
   218  		howto.SetHeader([]string{"Fun tasks for you", "Tips on how to"})
   219  		howto.SetColWidth(100)
   220  
   221  		for i := 0; i < len(tasks); i++ {
   222  			howto.Append([]string{tasks[i], tips[i]})
   223  		}
   224  		howto.Render()
   225  		return
   226  	}
   227  	// Meh, tips got ugly, split into many lines
   228  	for i := 0; i < len(tasks); i++ {
   229  		fmt.Println(tasks[i])
   230  		fmt.Println(strings.Repeat("-", len(tasks[i])))
   231  		fmt.Println(tips[i])
   232  		fmt.Println()
   233  		fmt.Println()
   234  	}
   235  }