mirror of
https://github.com/PeernetOfficial/Cmd.git
synced 2026-07-17 02:47:52 +01:00
287 lines
8.2 KiB
Go
287 lines
8.2 KiB
Go
/*
|
|
File Name: Command Line.go
|
|
Copyright: 2021 Peernet Foundation s.r.o.
|
|
Author: Peter Kleissner
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/PeernetOfficial/core"
|
|
)
|
|
|
|
func getUserOptionString(reader *bufio.Reader) (response string, valid bool) {
|
|
responseA, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
|
|
responseA = strings.TrimSpace(responseA)
|
|
|
|
return responseA, true
|
|
}
|
|
|
|
func getUserOptionBool(reader *bufio.Reader) (response bool, valid bool) {
|
|
responseA, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return false, false
|
|
}
|
|
|
|
responseA = strings.TrimSpace(responseA) // also removes the delimiter
|
|
|
|
responseI, err := strconv.Atoi(responseA)
|
|
if err != nil || (responseI != 0 && responseI != 1) {
|
|
return false, false
|
|
}
|
|
|
|
return responseI == 1, true
|
|
}
|
|
|
|
func getUserOptionInt(reader *bufio.Reader) (response int, valid bool) {
|
|
responseA, err := reader.ReadString('\n')
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
|
|
responseA = strings.TrimSpace(responseA) // also removes the delimiter
|
|
|
|
responseI, err := strconv.Atoi(responseA)
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
|
|
return responseI, true
|
|
}
|
|
|
|
func showHelp() {
|
|
fmt.Print("Please enter a command:\n")
|
|
fmt.Print("help Show this help\n" +
|
|
"net list Lists all network adapters and their IPs\n" +
|
|
"status Get current status\n" +
|
|
"chat Send text to all peers\n" +
|
|
"peer list List current peers\n" +
|
|
"debug key create Create Public-Private Key pair\n" +
|
|
"debug key self List current Public-Private Key pair\n" +
|
|
"\n")
|
|
}
|
|
|
|
func userCommands() {
|
|
reader := bufio.NewReader(os.Stdin)
|
|
|
|
fmt.Print("Peernet Cmd " + core.Version + "\n------------------------------\n")
|
|
showHelp()
|
|
|
|
for {
|
|
command, valid := getUserOptionString(reader)
|
|
if !valid {
|
|
time.Sleep(time.Second)
|
|
continue
|
|
}
|
|
command = strings.ToLower(command)
|
|
|
|
switch command {
|
|
case "help", "?":
|
|
showHelp()
|
|
|
|
case "net list":
|
|
fmt.Print(NetworkListOutput())
|
|
|
|
case "debug key create":
|
|
privateKey, publicKey, err := core.Secp256k1NewPrivateKey()
|
|
if err != nil {
|
|
fmt.Printf("Error: %s\n", err.Error())
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Private Key: %s\n", hex.EncodeToString(privateKey.Serialize()))
|
|
fmt.Printf("Public Key: %s\n", hex.EncodeToString(publicKey.SerializeCompressed()))
|
|
|
|
case "debug key self":
|
|
privateKey, publicKey := core.ExportPrivateKey()
|
|
fmt.Printf("Private Key: %s\n", hex.EncodeToString(privateKey.Serialize()))
|
|
fmt.Printf("Public Key: %s\n", hex.EncodeToString(publicKey.SerializeCompressed()))
|
|
|
|
case "peer list":
|
|
for _, peer := range core.PeerlistGet() {
|
|
fmt.Printf("* %s\n%s Packets sent: %d\n Packets received: %d\n\n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()), textPeerConnections(peer), peer.StatsPacketSent, peer.StatsPacketReceived)
|
|
}
|
|
|
|
case "chat all", "chat":
|
|
if text, valid := getUserOptionString(reader); valid {
|
|
core.SendChatAll(text)
|
|
}
|
|
|
|
case "status":
|
|
_, publicKey := core.ExportPrivateKey()
|
|
fmt.Printf("----------------\nPublic Key: %s\n\n", hex.EncodeToString(publicKey.SerializeCompressed()))
|
|
|
|
fmt.Printf("Listen Address Multicast IP out\n")
|
|
|
|
for _, network := range core.GetNetworks(4) {
|
|
address, _, broadcastIPv4 := network.GetListen()
|
|
fmt.Printf("%-30s\n", address.String())
|
|
|
|
for _, broadcastIP := range broadcastIPv4 {
|
|
fmt.Printf(" %-30s\n", broadcastIP.String())
|
|
}
|
|
}
|
|
for _, network := range core.GetNetworks(6) {
|
|
address, multicastIP, _ := network.GetListen()
|
|
fmt.Printf("%-30s %-30s\n", address.String(), multicastIP.String())
|
|
}
|
|
|
|
fmt.Printf("\nPeer ID Sent Received IP \n")
|
|
for _, peer := range core.PeerlistGet() {
|
|
addressA := "N/A"
|
|
if connectionsActive := peer.GetConnections(true); len(connectionsActive) > 0 {
|
|
addressA = connectionsActive[0].Address.String()
|
|
}
|
|
fmt.Printf("%-66s %-8d %-8d %-30s \n", hex.EncodeToString(peer.PublicKey.SerializeCompressed()), peer.StatsPacketSent, peer.StatsPacketReceived, addressA)
|
|
}
|
|
|
|
fmt.Printf("\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
// NetworkListOutput provides a user friendly output
|
|
func NetworkListOutput() (text string) {
|
|
|
|
interfaceList, err := net.Interfaces()
|
|
if err != nil {
|
|
return "Error " + err.Error()
|
|
}
|
|
|
|
// iterate through all interfaces
|
|
for _, ifaceSingle := range interfaceList {
|
|
text += "Interface " + ifaceSingle.Name + ":\n"
|
|
//text += " MAC: " + ifaceSingle.HardwareAddr.String() + "\n"
|
|
|
|
addresses, err := ifaceSingle.Addrs()
|
|
if err != nil {
|
|
text += " Error getting addresses: " + err.Error() + "\n\n"
|
|
continue
|
|
}
|
|
|
|
// iterate through all IPs of the interfaces
|
|
for _, address := range addresses {
|
|
text += " IP: " + address.(*net.IPNet).IP.String() + "\n"
|
|
}
|
|
|
|
// Subscribed Multicast IPs of adapters are not really newsworthy
|
|
//addresses2, err := ifaceSingle.MulticastAddrs()
|
|
//if err != nil {
|
|
// text += " Error getting multicast addresses: " + err.Error() + "\n\n"
|
|
// continue
|
|
//}
|
|
|
|
//for _, address := range addresses2 {
|
|
// text += " Multicast: " + address.(*net.IPAddr).IP.String() + "\n"
|
|
//}
|
|
|
|
text += "\n"
|
|
}
|
|
|
|
return text
|
|
}
|
|
|
|
const dateFormat = "2006-01-02 15:04:05"
|
|
|
|
func textPeerConnections(peer *core.PeerInfo) (text string) {
|
|
connectionsActive := peer.GetConnections(true)
|
|
connectionsInactive := peer.GetConnections(false)
|
|
|
|
mapConnectionsA := make(map[string][]*core.Connection)
|
|
mapConnectionsI := make(map[string][]*core.Connection)
|
|
var listAdapters []string
|
|
|
|
// for better human readability, sort all connections based on the network name
|
|
for _, c := range connectionsActive {
|
|
adapterName := c.Network.GetAdapterName()
|
|
|
|
list, ok := mapConnectionsA[adapterName]
|
|
if ok {
|
|
mapConnectionsA[adapterName] = append(list, c)
|
|
} else {
|
|
mapConnectionsA[adapterName] = []*core.Connection{c}
|
|
listAdapters = append(listAdapters, adapterName)
|
|
}
|
|
}
|
|
|
|
for _, c := range connectionsInactive {
|
|
adapterName := c.Network.GetAdapterName()
|
|
|
|
_, ok1 := mapConnectionsA[adapterName]
|
|
if !ok1 {
|
|
if _, ok2 := mapConnectionsI[adapterName]; !ok2 {
|
|
listAdapters = append(listAdapters, adapterName)
|
|
}
|
|
}
|
|
|
|
list, ok := mapConnectionsI[adapterName]
|
|
if ok {
|
|
mapConnectionsI[adapterName] = append(list, c)
|
|
} else {
|
|
mapConnectionsI[adapterName] = []*core.Connection{c}
|
|
}
|
|
}
|
|
|
|
sort.Strings(listAdapters)
|
|
|
|
text += " Status Local -> Remote Last Packet In Last Packet Out \n"
|
|
|
|
for _, adapterName := range listAdapters {
|
|
text += " -- adapter '" + adapterName + "' --\n"
|
|
|
|
list, _ := mapConnectionsA[adapterName]
|
|
for _, c := range list {
|
|
listenAddress, _, _ := c.Network.GetListen()
|
|
text += fmt.Sprintf(" %-9s %-50s -> %-50s %-19s %-19s\n", connectionStatusToA(c.Status), listenAddress.String(), addressToA(c.Address), c.LastPacketIn.Format(dateFormat), c.LastPacketOut.Format(dateFormat))
|
|
}
|
|
|
|
list, _ = mapConnectionsI[adapterName]
|
|
for _, c := range list {
|
|
listenAddress, _, _ := c.Network.GetListen()
|
|
text += fmt.Sprintf(" %-9s %-50s -> %-50s %-19s %-19s\n", connectionStatusToA(c.Status), listenAddress.String(), addressToA(c.Address), c.LastPacketIn.Format(dateFormat), c.LastPacketOut.Format(dateFormat))
|
|
}
|
|
}
|
|
|
|
text += " --\n"
|
|
|
|
return text
|
|
}
|
|
|
|
// addressToA is UDPAddr.String without IPv6 zone
|
|
func addressToA(a *net.UDPAddr) (result string) {
|
|
if a == nil || len(a.IP) == 0 {
|
|
return "<nil>"
|
|
}
|
|
return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port))
|
|
}
|
|
|
|
// connectionStatusToA translates the connection status to a readable text
|
|
func connectionStatusToA(status int) (result string) {
|
|
switch status {
|
|
case core.ConnectionActive:
|
|
return "active"
|
|
case core.ConnectionInactive:
|
|
return "inactive"
|
|
case core.ConnectionRemoved:
|
|
return "removed"
|
|
case core.ConnectionRedundant:
|
|
return "redundant"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|