github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/textui/peers.go (about)

     1  package textui
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/piotrnar/gocoin/client/network"
    11  	"github.com/piotrnar/gocoin/client/network/peersdb"
    12  	"github.com/piotrnar/gocoin/client/usif"
    13  	"github.com/piotrnar/gocoin/lib/others/qdb"
    14  )
    15  
    16  func show_node_stats(par string) {
    17  	ns := make(map[string]int)
    18  	peersdb.Lock()
    19  	peersdb.PeerDB.Browse(func(k qdb.KeyType, v []byte) uint32 {
    20  		pr := peersdb.NewPeer(v)
    21  		if pr.NodeAgent != "" {
    22  			ns[pr.NodeAgent]++
    23  		}
    24  		return 0
    25  	})
    26  	peersdb.Unlock()
    27  	if len(ns) == 0 {
    28  		fmt.Println("Nothing to see here")
    29  		return
    30  	}
    31  	ss := make([]string, len(ns))
    32  	var i, sum int
    33  	for k, v := range ns {
    34  		ss[i] = fmt.Sprintf("%5d %s", v, k)
    35  		sum += v
    36  		i++
    37  	}
    38  	sort.Strings(ss)
    39  	for _, s := range ss {
    40  		fmt.Println(s)
    41  	}
    42  	fmt.Println("Total:", sum)
    43  }
    44  
    45  func show_addresses(par string) {
    46  	pars := strings.Split(par, " ")
    47  	if len(pars) < 1 || pars[0] == "" {
    48  		bcnt, acnt := 0, 0
    49  		peersdb.PeerDB.Browse(func(k qdb.KeyType, v []byte) uint32 {
    50  			pr := peersdb.NewPeer(v)
    51  			if pr.Banned != 0 {
    52  				bcnt++
    53  			}
    54  			if pr.SeenAlive {
    55  				acnt++
    56  			}
    57  			return 0
    58  		})
    59  		fmt.Println("Peers in DB:", peersdb.PeerDB.Count())
    60  		fmt.Println("Peers seen alive:", acnt)
    61  		fmt.Println("Peers banned:", bcnt)
    62  		fmt.Println("QDB stats:", peersdb.PeerDB.GetStats())
    63  		return
    64  	}
    65  
    66  	var only_ban, only_alive, show_help bool
    67  	var ban_reason, only_agent string
    68  	limit := peersdb.PeerDB.Count()
    69  	check_next := true
    70  	switch pars[0] {
    71  	case "ali":
    72  		only_alive = true
    73  	case "ban":
    74  		only_ban = true
    75  	case "help":
    76  		show_help = true
    77  	case "str":
    78  		only_agent = "/Gocoin"
    79  	case "all":
    80  		// do nothing
    81  	case "purge":
    82  		var torem []qdb.KeyType
    83  		peersdb.Lock()
    84  		peersdb.PeerDB.Browse(func(k qdb.KeyType, v []byte) uint32 {
    85  			pr := peersdb.NewPeer(v)
    86  			if !pr.SeenAlive {
    87  				torem = append(torem, k)
    88  			}
    89  			return 0
    90  		})
    91  		fmt.Println("Purginig", len(torem), "records")
    92  		for _, k := range torem {
    93  			peersdb.PeerDB.Del(k)
    94  		}
    95  		peersdb.Unlock()
    96  		show_addresses("")
    97  		return
    98  
    99  	case "defrag":
   100  		peersdb.PeerDB.Defrag(true)
   101  		return
   102  
   103  	case "save":
   104  		peersdb.PeerDB.Sync()
   105  		return
   106  
   107  	default:
   108  		if u, e := strconv.ParseUint(pars[0], 10, 32); e != nil {
   109  			fmt.Println("Incorrect number A of peers max count:", e.Error())
   110  			show_help = true
   111  		} else {
   112  			limit = int(u)
   113  			check_next = false
   114  		}
   115  	}
   116  	if check_next {
   117  		if len(pars) >= 2 {
   118  			if u, e := strconv.ParseUint(pars[1], 10, 32); e != nil {
   119  				if only_ban {
   120  					ban_reason = pars[1]
   121  					if len(pars) >= 3 {
   122  						if u, e := strconv.ParseUint(pars[2], 10, 32); e == nil {
   123  							limit = int(u)
   124  						}
   125  					}
   126  				} else if only_agent != "" {
   127  					only_agent = pars[1]
   128  				} else {
   129  					fmt.Println("Incorrect number B of peers max count:", e.Error())
   130  					show_help = true
   131  				}
   132  			} else {
   133  				limit = int(u)
   134  			}
   135  		}
   136  	}
   137  
   138  	if show_help {
   139  		fmt.Println("Use 'peers all [max_cnt]' or 'peers [max_cnt]' to list all")
   140  		fmt.Println("Use 'peers ali [max_cnt]' to list only those seen alive")
   141  		fmt.Println("Use 'peers ban [ban_reason] [max_cnt]' to list the banned ones")
   142  		fmt.Println("Use 'peers str [string]' to list only if agent contains string")
   143  		fmt.Println("Use 'peers agents' to see node agent statistics")
   144  		fmt.Println("Use 'peers purge' to remove all peers never seen alive")
   145  		fmt.Println("Use 'peers defrag' to defragment DB")
   146  		fmt.Println("Use 'peers save' to save DB now")
   147  		return
   148  	}
   149  	prs := peersdb.GetRecentPeers(uint(limit), true, func(p *peersdb.PeerAddr) bool {
   150  		if only_agent != "" && !strings.Contains(p.NodeAgent, only_agent) {
   151  			return true
   152  		}
   153  		if only_alive && !p.SeenAlive {
   154  			return true
   155  		}
   156  		if only_ban {
   157  			if p.Banned == 0 || ban_reason != "" && p.BanReason != ban_reason {
   158  				return true
   159  			}
   160  			p.Time, p.Banned = p.Banned, p.Time // to sort them by when they were banned
   161  		}
   162  		return false
   163  	})
   164  	for i, p := range prs {
   165  		var sc string
   166  		if only_ban {
   167  			p.Time, p.Banned = p.Banned, p.Time // Revert the change
   168  		}
   169  		if network.ConnectionActive(p) {
   170  			sc = "*"
   171  		} else {
   172  			sc = " "
   173  		}
   174  
   175  		fmt.Printf("%4d%s%s\n", i+1, sc, p.String())
   176  	}
   177  	fmt.Println("Note: currently connected peers marked with *")
   178  }
   179  
   180  func unban_peer(par string) {
   181  	ps := strings.Split(par, " ")
   182  	for _, s := range ps {
   183  		fmt.Print(usif.UnbanPeer(s))
   184  	}
   185  }
   186  
   187  func add_peer(par string) {
   188  	ad, er := peersdb.NewAddrFromString(par, false)
   189  	if er != nil {
   190  		fmt.Println(par, er.Error())
   191  		return
   192  	}
   193  	ad.Time = uint32(time.Now().Unix())
   194  	ad.Save()
   195  }
   196  
   197  func del_peer(par string) {
   198  	peersdb.Lock()
   199  	defer peersdb.Unlock()
   200  
   201  	ad, er := peersdb.NewAddrFromString(par, false)
   202  	if er != nil {
   203  		fmt.Println(par, er.Error())
   204  		return
   205  	}
   206  
   207  	fmt.Print("Deleting ", ad.Ip(), " ... ")
   208  	id := ad.UniqID()
   209  	if peersdb.PeerDB.Get(qdb.KeyType(id)) != nil {
   210  		peersdb.PeerDB.Del(qdb.KeyType(id))
   211  		fmt.Println("OK")
   212  	} else {
   213  		fmt.Println("not found")
   214  	}
   215  }
   216  
   217  func init() {
   218  	newUi("ban", false, show_node_stats, "Ban a peer specified by IP")
   219  	newUi("nodestat ns", false, show_node_stats, "Shows all known nodes version statistics")
   220  	newUi("peeradd pa", false, add_peer, "Add a peer to the database, mark it as alive")
   221  	newUi("peerdel pd", false, del_peer, "Delete peer from the DB")
   222  	newUi("peers p", false, show_addresses, "Operation on pers database ('peers help' for help)")
   223  	newUi("unban", false, unban_peer, "Unban a peer specified by IP[:port] (or 'unban all')")
   224  }