package main import ( "bytes" "encoding/json" "errors" "flag" "fmt" "log" "net" "net/url" "os" "strings" "time" "github.com/olekukonko/tablewriter" "github.com/yggdrasil-network/yggdrasil-go/src/admin" "github.com/yggdrasil-network/yggdrasil-go/src/core" "github.com/yggdrasil-network/yggdrasil-go/src/version" ) func main() { // makes sure we can use defer and still return an error code to the OS os.Exit(run()) } func run() int { logbuffer := &bytes.Buffer{} logger := log.New(logbuffer, "", log.Flags()) defer func() int { if r := recover(); r != nil { logger.Println("Fatal error:", r) fmt.Print(logbuffer) return 1 } return 0 }() cmdLineEnv := newCmdLineEnv() cmdLineEnv.parseFlagsAndArgs() if cmdLineEnv.ver { fmt.Println("Build name:", version.BuildName()) fmt.Println("Build version:", version.BuildVersion()) fmt.Println("To get the version number of the running Yggdrasil node, run", os.Args[0], "getSelf") return 0 } if len(cmdLineEnv.args) == 0 { flag.Usage() return 0 } cmdLineEnv.setEndpoint(logger) var conn net.Conn u, err := url.Parse(cmdLineEnv.endpoint) if err == nil { switch strings.ToLower(u.Scheme) { case "unix": logger.Println("Connecting to UNIX socket", cmdLineEnv.endpoint[7:]) conn, err = net.Dial("unix", cmdLineEnv.endpoint[7:]) case "tcp": logger.Println("Connecting to TCP socket", u.Host) conn, err = net.Dial("tcp", u.Host) default: logger.Println("Unknown protocol or malformed address - check your endpoint") err = errors.New("protocol not supported") } } else { logger.Println("Connecting to TCP socket", u.Host) conn, err = net.Dial("tcp", cmdLineEnv.endpoint) } if err != nil { panic(err) } logger.Println("Connected") defer conn.Close() decoder := json.NewDecoder(conn) encoder := json.NewEncoder(conn) send := &admin.AdminSocketRequest{} recv := &admin.AdminSocketResponse{} for c, a := range cmdLineEnv.args { if c == 0 { if strings.HasPrefix(a, "-") { logger.Printf("Ignoring flag %s as it should be specified before other parameters\n", a) continue } logger.Printf("Sending request: %v\n", a) send.Name = a continue } tokens := strings.SplitN(a, "=", 1) switch { case len(tokens) == 1: panic("incomplete argument supplied") default: send.Arguments[tokens[0]] = tokens[1] } } if err := encoder.Encode(&send); err != nil { panic(err) } logger.Printf("Request sent") if err := decoder.Decode(&recv); err != nil { panic(err) } if recv.Status == "error" { if err := recv.Error; err != "" { fmt.Println("Admin socket returned an error:", err) } else { fmt.Println("Admin socket returned an error but didn't specify any error text") } return 1 } if cmdLineEnv.injson { if json, err := json.MarshalIndent(recv.Response, "", " "); err == nil { fmt.Println(string(json)) } return 0 } table := tablewriter.NewWriter(os.Stdout) table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoFormatHeaders(false) table.SetCenterSeparator("") table.SetColumnSeparator("") table.SetRowSeparator("") table.SetHeaderLine(false) table.SetBorder(false) table.SetTablePadding("\t") // pad with tabs table.SetNoWhiteSpace(true) switch strings.ToLower(recv.Request.Name) { case "list": var resp admin.ListResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.SetHeader([]string{"Command", "Arguments"}) for _, entry := range resp.List { table.Append([]string{entry.Command, strings.Join(entry.Fields, ", ")}) } table.Render() case "getself": var resp admin.GetSelfResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.Append([]string{"Build name:", resp.BuildName}) table.Append([]string{"Build version:", resp.BuildVersion}) table.Append([]string{"IPv6 address:", resp.IPAddress}) table.Append([]string{"IPv6 subnet:", resp.Subnet}) table.Append([]string{"Coordinates:", fmt.Sprintf("%v", resp.Coords)}) table.Append([]string{"Public key:", resp.PublicKey}) table.Render() case "getpeers": var resp admin.GetPeersResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.SetHeader([]string{"Port", "Public Key", "IP Address", "Peering URI", "Uptime", "RX", "TX"}) for _, peer := range resp.Peers { table.Append([]string{ fmt.Sprintf("%d", peer.Port), peer.PublicKey, peer.IPAddress, peer.Remote, (time.Duration(peer.Uptime) * time.Second).String(), peer.RXBytes.String(), peer.TXBytes.String(), }) } table.Render() case "getdht": var resp admin.GetDHTResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.SetHeader([]string{"Public Key", "IP Address", "Port", "Rest"}) for _, dht := range resp.DHT { table.Append([]string{ dht.PublicKey, dht.IPAddress, fmt.Sprintf("%d", dht.Port), fmt.Sprintf("%d", dht.Rest), }) } table.Render() case "getpaths": var resp admin.GetPathsResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.SetHeader([]string{"Public Key", "IP Address", "Path"}) for _, p := range resp.Paths { table.Append([]string{ p.PublicKey, p.IPAddress, fmt.Sprintf("%v", p.Path), }) } table.Render() case "getsessions": var resp admin.GetSessionsResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } table.SetHeader([]string{"Public Key", "IP Address", "Uptime", "RX", "TX"}) for _, p := range resp.Sessions { table.Append([]string{ p.PublicKey, p.IPAddress, (time.Duration(p.Uptime) * time.Second).String(), p.RXBytes.String(), p.TXBytes.String(), }) } table.Render() case "getnodeinfo": var resp core.GetNodeInfoResponse if err := json.Unmarshal(recv.Response, &resp); err != nil { panic(err) } for _, v := range resp { fmt.Println(string(v)) break } default: panic("unknown response type: " + recv.Request.Name) } return 0 }