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 }