Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skywire cli rtree #1743

Merged
merged 8 commits into from
Feb 23, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package clidmsghttp cmd/skywire-cli/commands/dmsghttp/root.go
package clidmsghttp
// Package cliconfig cmd/skywire-cli/commands/config/dmsghttp.go
package cliconfig

import (
"context"
Expand All @@ -16,20 +16,15 @@ import (
"github.com/skycoin/skywire-utilities/pkg/skyenv"
)

var (
path string
)

func init() {
updateCmd.AddCommand(dmsghttpCmd)
dmsghttpCmd.Flags().SortFlags = false
//TODO: fix path for non linux package defaults
dmsghttpCmd.Flags().StringVarP(&path, "path", "p", "/opt/skywire/dmsghttp-config.json", "path of dmsghttp-config file, default is for pkg installation")
}

// RootCmd is surveyCmd
var RootCmd = dmsghttpCmd

var dmsghttpCmd = &cobra.Command{
Use: "dmsghttp update",
Use: "dmsghttp",
Short: "update dmsghttp-config.json file from config bootstrap service",
Run: func(cmd *cobra.Command, args []string) {
log := logging.MustGetLogger("dmsghttp_updater")
Expand Down
1 change: 1 addition & 0 deletions cmd/skywire-cli/commands/config/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
Test: visorconfig.DmsgHTTPServersData{DMSGServers: []*disc.Entry{}},
Prod: visorconfig.DmsgHTTPServersData{DMSGServers: []*disc.Entry{}},
}
path string
noFetch bool
noDefaults bool
stcprPort int
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package cliservices cmd/skywire-cli/commands/services/root.go
package cliservices
// Package cliconfig cmd/skywire-cli/commands/config/services.go
package cliconfig

import (
"context"
Expand All @@ -16,20 +16,15 @@ import (
"github.com/skycoin/skywire/pkg/visor/visorconfig"
)

var (
path string
)

func init() {
updateCmd.AddCommand(servicesCmd)
servicesCmd.Flags().SortFlags = false
//TODO: fix path for non linux package defaults
servicesCmd.Flags().StringVarP(&path, "path", "p", "/opt/skywire/services-config.json", "path of services-config file, default is for pkg installation")
}

// RootCmd is servicesCmd
var RootCmd = servicesCmd

var servicesCmd = &cobra.Command{
Use: "services update",
Use: "svc",
Short: "update services-config.json file from config bootstrap service",
Run: func(cmd *cobra.Command, args []string) {
log := logging.MustGetLogger("services_updater")
Expand Down Expand Up @@ -59,11 +54,6 @@ var servicesCmd = &cobra.Command{
},
}

type servicesConf struct { //nolint
Test visorconfig.Services `json:"test"`
Prod visorconfig.Services `json:"prod"`
}

func fetchServicesConf() (servicesConf, error) {
var newConf servicesConf
var prodConf visorconfig.Services
Expand Down
33 changes: 2 additions & 31 deletions cmd/skywire-cli/commands/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"bytes"
"context"
"fmt"
"net/http"
"os"
"strings"
"text/tabwriter"
Expand Down Expand Up @@ -282,7 +281,7 @@ var listCmd = &cobra.Command{
Short: "List servers",
Long: fmt.Sprintf("List %v servers from service discovery\n%v/api/services?type=%v\n%v/api/services?type=%v&country=US\n\nSet cache file location to \"\" to avoid using cache files", serviceType, skyenv.ServiceDiscAddr, serviceType, skyenv.ServiceDiscAddr, serviceType),
Run: func(cmd *cobra.Command, args []string) {
sds := getData(cacheFileSD, sdURL+"/api/services?type="+serviceType)
sds := internal.GetData(cacheFileSD, sdURL+"/api/services?type="+serviceType, cacheFilesAge)
if rawData {
script.Echo(string(pretty.Color(pretty.Pretty([]byte(sds)), nil))).Stdout() //nolint
return
Expand Down Expand Up @@ -325,7 +324,7 @@ var listCmd = &cobra.Command{
script.Echo(sdkeys).Stdout() //nolint
return
}
uts := getData(cacheFileUT, utURL+"/uptimes?v=v2")
uts := internal.GetData(cacheFileUT, utURL+"/uptimes?v=v2", cacheFilesAge)
utkeys, _ := script.Echo(uts).JQ(".[] | select(.on) | .pk").Replace("\"", "").String() //nolint
if isStats {
count, _ := script.Echo(sdkeys + utkeys).Freq().Match("2 ").Column(2).CountLines() //nolint
Expand All @@ -347,31 +346,3 @@ var listCmd = &cobra.Command{

},
}

func getData(cachefile, thisurl string) (thisdata string) {
var shouldfetch bool
buf1 := new(bytes.Buffer)
cTime := time.Now()
if cachefile == "" {
thisdata, _ = script.NewPipe().WithHTTPClient(&http.Client{Timeout: 30 * time.Second}).Get(thisurl).String() //nolint
return thisdata
}
if cachefile != "" {
if u, err := os.Stat(cachefile); err != nil {
shouldfetch = true
} else {
if cTime.Sub(u.ModTime()).Minutes() > float64(cacheFilesAge) {
shouldfetch = true
}
}
if shouldfetch {
_, _ = script.NewPipe().WithHTTPClient(&http.Client{Timeout: 30 * time.Second}).Get(thisurl).Tee(buf1).WriteFile(cachefile) //nolint
thisdata = buf1.String()
} else {
thisdata, _ = script.File(cachefile).String() //nolint
}
} else {
thisdata, _ = script.NewPipe().WithHTTPClient(&http.Client{Timeout: 30 * time.Second}).Get(thisurl).String() //nolint
}
return thisdata
}
6 changes: 2 additions & 4 deletions cmd/skywire-cli/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import (
"github.com/skycoin/skywire-utilities/pkg/buildinfo"
clicompletion "github.com/skycoin/skywire/cmd/skywire-cli/commands/completion"
cliconfig "github.com/skycoin/skywire/cmd/skywire-cli/commands/config"
clidmsghttp "github.com/skycoin/skywire/cmd/skywire-cli/commands/dmsghttp"
clidmsgpty "github.com/skycoin/skywire/cmd/skywire-cli/commands/dmsgpty"
clilog "github.com/skycoin/skywire/cmd/skywire-cli/commands/log"
climdisc "github.com/skycoin/skywire/cmd/skywire-cli/commands/mdisc"
cliskysocksc "github.com/skycoin/skywire/cmd/skywire-cli/commands/proxy"
clireward "github.com/skycoin/skywire/cmd/skywire-cli/commands/reward"
clirewards "github.com/skycoin/skywire/cmd/skywire-cli/commands/rewards"
clirtfind "github.com/skycoin/skywire/cmd/skywire-cli/commands/rtfind"
cliservices "github.com/skycoin/skywire/cmd/skywire-cli/commands/services"
clirtree "github.com/skycoin/skywire/cmd/skywire-cli/commands/rtree"
cliskyfwd "github.com/skycoin/skywire/cmd/skywire-cli/commands/skyfwd"
cliskyrev "github.com/skycoin/skywire/cmd/skywire-cli/commands/skyrev"
clisurvey "github.com/skycoin/skywire/cmd/skywire-cli/commands/survey"
Expand Down Expand Up @@ -193,14 +192,13 @@ func init() {
clirewards.RootCmd,
clisurvey.RootCmd,
clirtfind.RootCmd,
clirtree.RootCmd,
climdisc.RootCmd,
clicompletion.RootCmd,
clilog.RootCmd,
cliskysocksc.RootCmd,
treeCmd,
docCmd,
clidmsghttp.RootCmd,
cliservices.RootCmd,
)
var jsonOutput bool
RootCmd.PersistentFlags().BoolVar(&jsonOutput, internal.JSONString, false, "print output in json")
Expand Down
185 changes: 185 additions & 0 deletions cmd/skywire-cli/commands/rtree/rtree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Package clirtree subcommand for skywire-cli
package clirtree

import (
"fmt"
"os"
"strings"

"github.com/bitfield/script"
"github.com/pterm/pterm"
"github.com/pterm/pterm/putils"
"github.com/spf13/cobra"
"github.com/tidwall/pretty"

utilenv "github.com/skycoin/skywire-utilities/pkg/skyenv"
"github.com/skycoin/skywire/cmd/skywire-cli/internal"
)

var (
sortedEdgeKeys []string
utURL string
tpdURL string
cacheFileTPD string
cacheFileUT string
cacheFilesAge int
padSpaces int
isStats bool
rawData bool
refinedData bool
noFilterOnline bool
)

// RootCmd is rtreeCmd
var RootCmd = rtreeCmd

func init() {
rtreeCmd.Flags().StringVarP(&tpdURL, "tpdurl", "a", utilenv.TpDiscAddr, "transport discovery url")
rtreeCmd.Flags().StringVarP(&utURL, "uturl", "w", utilenv.UptimeTrackerAddr, "uptime tracker url")
rtreeCmd.Flags().BoolVarP(&rawData, "raw", "r", false, "print raw json data")
rtreeCmd.Flags().BoolVarP(&refinedData, "pretty", "p", false, "print pretty json data")
rtreeCmd.Flags().BoolVarP(&noFilterOnline, "noton", "o", false, "do not filter by online status in UT")
rtreeCmd.Flags().StringVar(&cacheFileTPD, "cft", os.TempDir()+"/tpd.json", "TPD cache file location")
rtreeCmd.Flags().StringVar(&cacheFileUT, "cfu", os.TempDir()+"/ut.json", "UT cache file location.")
rtreeCmd.Flags().IntVarP(&cacheFilesAge, "cfa", "m", 5, "update cache files if older than n minutes")
//TODO: calculate tree levels initially and apply appropriate padding ; as an alternative to manually padding
rtreeCmd.Flags().IntVarP(&padSpaces, "pad", "P", 15, "padding between tree and tpid")
rtreeCmd.Flags().BoolVarP(&isStats, "stats", "s", false, "return only statistics")
}

var rtreeCmd = &cobra.Command{
Use: "rtree",
Short: "map of transports on the skywire network",
Long: fmt.Sprintf("display a tree representation of transports from TPD\n\n%v/all-transports\n\nSet cache file location to \"\" to avoid using cache files", utilenv.TpDiscAddr),
Run: func(cmd *cobra.Command, args []string) {
tps := internal.GetData(cacheFileTPD, tpdURL+"/all-transports", cacheFilesAge)
if rawData {
script.Echo(tps).Stdout() //nolint
return
}
if refinedData {
script.Echo(string(pretty.Color(pretty.Pretty([]byte(tps)), nil))).Stdout() //nolint
return
}
var uts string
var utkeys []string
var offlinekeys []string
if !noFilterOnline {
uts = internal.GetData(cacheFileUT, utURL+"/uptimes?v=v2", cacheFilesAge)
utkeys, _ = script.Echo(uts).JQ(".[] | select(.on) | .pk").Replace("\"", "").Slice() //nolint
offlinekeys, _ = script.Echo(uts).JQ(".[] | select(.on | not) | .pk").Replace("\"", "").Slice() //nolint
}

sortedEdgeKeys, _ = script.Echo(tps).JQ(".[].edges[]").Freq().Column(2).Slice() //nolint

if isStats {
fmt.Printf("Unique keys in Transport Discovery: %d\n", len(sortedEdgeKeys))
tpcount, _ := script.Echo(tps).JQ(".[].type").CountLines() //nolint
fmt.Printf("Count of transports: %v\n", tpcount)
tptypes, _ := script.Echo(tps).JQ(".[].type").Freq().String() //nolint
fmt.Printf("types of transports: \n%v\n", tptypes)
vcount, _ := script.Echo(tps).JQ(".[].edges[]").Freq().String() //nolint
fmt.Printf("Visors by transport count:\n%v\n", vcount)
return
}

fmt.Printf("Tree *Online %s %s TPID Type\n", pterm.Black(pterm.BgRed.Sprint("*Offline")), pterm.Red("*Not in UT"))

leveledList := pterm.LeveledList{}
edgeKey := sortedEdgeKeys[0]
leveledList = append(leveledList, pterm.LeveledListItem{Level: 0, Text: filterOnlineStatus(utkeys, offlinekeys, edgeKey)})

var usedkeys []string
usedkeys = append(usedkeys, edgeKey)
var lvl func(n int, k string)
lvl = func(n int, k string) {
l, _ := script.Echo(tps).JQ(".[] | select(.edges[] == " + k + ") | .edges[] | select(. != " + k + ")").Slice() //nolint
for _, m := range l {
if m == k {
continue
}
var ok bool
ok = false
for _, o := range usedkeys {
if m == o {
ok = true
}
}
if ok {
continue
}
usedkeys = append(usedkeys, m)
var tpid string
if n == 0 {
tpid = ""
} else {
tpid, _ = script.Echo(tps).JQ(".[] | select(.edges | index(" + k + ") and index(" + m + ")) | .t_id + \" \" + .type").First(1).String() //nolint
}
leveledList = append(leveledList, pterm.LeveledListItem{Level: n, Text: strings.ReplaceAll(strings.ReplaceAll(fmt.Sprintf("%s %s", filterOnlineStatus(utkeys, offlinekeys, m), strings.Repeat(" ", func() int {
indent := padSpaces - 4 - n*2
if indent < 0 {
return 0
}
return indent
}())+tpid), "\n", ""), "\"", "")})
lvl(n+1, m)
}
}
lvl(1, edgeKey)

pterm.DefaultTree.WithRoot(putils.TreeFromLeveledList(leveledList)).Render() //nolint
for _, edgeKey := range sortedEdgeKeys {
found := false
for _, usedKey := range usedkeys {
if usedKey == edgeKey {
found = true
break
}
}
if !found {
leveledList = pterm.LeveledList{}
leveledList = append(leveledList, pterm.LeveledListItem{Level: 0, Text: filterOnlineStatus(utkeys, offlinekeys, edgeKey)})
usedkeys = append(usedkeys, edgeKey)
lvl(1, edgeKey)
pterm.DefaultTree.WithRoot(putils.TreeFromLeveledList(leveledList)).Render() //nolint
}
}
l, _ := script.Echo(tps).JQ(".[] | select(.edges[0] == .edges[1]) | .edges[0] + \""+strings.Repeat(" ", padSpaces)+"\" + .t_id + \" \" + .type").Replace("\"", "").Slice() //nolint
if len(l) > 0 {
pterm.Println(pterm.Red("Self-transports"))
for _, m := range l {
pterm.Println(filterOnlineStatus(utkeys, offlinekeys, m))
}
}
},
}

func filterOnlineStatus(utkeys, offlinekeys []string, key string) (lvlN string) {
isOnline, isOffline := false, false
lvlN = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(key, " ", ""), "\t", ""), "\n", ""), "\"", "")
if !noFilterOnline {
for _, k := range utkeys {
if strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(k, " ", ""), "\t", ""), "\n", ""), "\"", "") == strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(key, " ", ""), "\t", ""), "\n", ""), "\"", "") {
isOnline = true
break
}
}
if !isOnline {
for _, k := range offlinekeys {
if strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(k, " ", ""), "\t", ""), "\n", ""), "\"", "") == strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(key, " ", ""), "\t", ""), "\n", ""), "\"", "") {
isOffline = true
break
}
}
}
} else {
isOnline, isOffline = true, false
}
if !isOnline && !isOffline {
lvlN = pterm.Red(strings.ReplaceAll(key, "\"", ""))
}
if isOffline {
lvlN = pterm.Black(pterm.BgRed.Sprint(strings.ReplaceAll(key, "\"", "")))
}
return lvlN
}
Loading
Loading