Skip to content

Commit

Permalink
improve skywire-cli ut command logic (#1679)
Browse files Browse the repository at this point in the history
* initial commit for improve skywire-cli ut command logic

* fix panic issue

* fix lint issue
  • Loading branch information
mrpalide committed Dec 9, 2023
1 parent 2683198 commit 5dc0aba
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 44 deletions.
153 changes: 110 additions & 43 deletions cmd/skywire-cli/commands/ut/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,28 @@ import (

"github.com/spf13/cobra"

"github.com/skycoin/dmsg/pkg/direct"
"github.com/skycoin/dmsg/pkg/disc"
"github.com/skycoin/dmsg/pkg/dmsg"
"github.com/skycoin/dmsg/pkg/dmsghttp"

"github.com/skycoin/skywire-utilities/pkg/cipher"
"github.com/skycoin/skywire-utilities/pkg/logging"
clirpc "github.com/skycoin/skywire/cmd/skywire-cli/commands/rpc"
"github.com/skycoin/skywire/cmd/skywire-cli/internal"
)

var (
pubkey cipher.PubKey
pk string
thisPk string
online bool
isStats bool
url string
pubkey cipher.PubKey
pk string
thisPk string
online bool
isStats bool
url string
data []byte
dmsgAddr string
dmsgIP string
utDmsgAddr string
)

var minUT int
Expand All @@ -33,7 +44,10 @@ func init() {
RootCmd.Flags().BoolVarP(&online, "on", "o", false, "list currently online visors")
RootCmd.Flags().BoolVarP(&isStats, "stats", "s", false, "count the number of results")
RootCmd.Flags().IntVarP(&minUT, "min", "n", 75, "list visors meeting minimum uptime")
RootCmd.Flags().StringVarP(&url, "url", "u", "", "specify alternative uptime tracker url\ndefault: http://ut.skywire.skycoin.com/uptimes?v=v2")
RootCmd.Flags().StringVarP(&url, "url", "u", "http://ut.skywire.skycoin.com/uptimes?v=v2", "specify alternative uptime tracker url\ndefault: http://ut.skywire.skycoin.com/uptimes?v=v2")
RootCmd.Flags().StringVar(&dmsgAddr, "dmsgAddr", "030c83534af1041aee60c2f124b682a9d60c6421876db7c67fc83a73c5effdbd96", "specific dmsg server address for dmsghttp query")
RootCmd.Flags().StringVar(&dmsgIP, "dmsgIP", "188.121.99.59:8081", "specific dmsg server ip for dmsghttp query")
RootCmd.Flags().StringVar(&utDmsgAddr, "utDmsgAddr", "dmsg://022c424caa6239ba7d1d9d8f7dab56cd5ec6ae2ea9ad97bb94ad4b48f62a540d3f:80", "dmsg address of uptime tracker")
}

// RootCmd contains commands that interact with the skywire-visor
Expand All @@ -42,50 +56,35 @@ var RootCmd = &cobra.Command{
Short: "query uptime tracker",
Long: "query uptime tracker\n Check local visor daily uptime percent with:\n skywire-cli ut -k $(skywire-cli visor pk)",
Run: func(cmd *cobra.Command, _ []string) {
if url == "" {
url = "http://ut.skywire.skycoin.com/uptimes?v=v2"
}
now := time.Now()
if pk != "" {
err := pubkey.Set(pk)
// tyring to connect with running visor
rpcClient, err := clirpc.Client(cmd.Flags())
if err != nil {
internal.PrintError(cmd.Flags(), fmt.Errorf("unable to create RPC client: %w", err))
} else {
data, err = rpcClient.FetchUptimeTrackerData(pk)
if err != nil {
internal.PrintFatalError(cmd.Flags(), fmt.Errorf("Invalid or missing public key"))
} else {
url += "&visors=" + pubkey.String()
internal.PrintError(cmd.Flags(), fmt.Errorf("unable to fetch uptime tracker data from RPC client: %w", err))
}
}
utClient := http.Client{
Timeout: time.Second * 15, // Timeout after 15 seconds
}

req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
log.Fatal(err)
}

res, getErr := utClient.Do(req)
if getErr != nil {
log.Fatal(getErr)
}

if res.Body != nil {
defer func() {
err := res.Body.Close()
if err != nil {
internal.PrintError(cmd.Flags(), fmt.Errorf("Failed to close response body"))
}
}()
// no rpc, so trying to dmsghttp query
if len(data) == 0 {
data, err = dmsgHTTPQuery(cmd)
if err != nil {
internal.PrintError(cmd.Flags(), fmt.Errorf("unable to fetch uptime tracker data in dmsgHTTPQuery method: %w", err))
}
}

body, readErr := io.ReadAll(res.Body)
if readErr != nil {
log.Fatal(readErr)
// nor rpc and dmsghttp, trying to direct http query
if len(data) == 0 {
data, err = httpQuery(cmd)
if err != nil {
internal.PrintFatalError(cmd.Flags(), fmt.Errorf("unable to fetch uptime tracker data in httpQuery method: %w", err))
}
}

now := time.Now()
startDate := time.Date(now.Year(), now.Month(), -1, 0, 0, 0, 0, now.Location()).Format("2006-01-02")
endDate := time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-1 * time.Second).Format("2006-01-02")
uts := uptimes{}
jsonErr := json.Unmarshal(body, &uts)
jsonErr := json.Unmarshal(data, &uts)
if jsonErr != nil {
log.Fatal(jsonErr)
}
Expand Down Expand Up @@ -128,6 +127,74 @@ func selectedDaily(data map[string]string, startDate, endDate string) {
}
}

func dmsgHTTPQuery(cmd *cobra.Command) ([]byte, error) {
pk, sk := cipher.GenerateKeyPair()
var dmsgAddrPK cipher.PubKey
err := dmsgAddrPK.Set(dmsgAddr)
if err != nil {
return []byte{}, err
}

servers := []*disc.Entry{{Server: &disc.Server{Address: dmsgIP}, Static: dmsgAddrPK}}
keys := cipher.PubKeys{pk}

entries := direct.GetAllEntries(keys, servers)
dClient := direct.NewClient(entries, logging.NewMasterLogger().PackageLogger("ut_dmsgHTTPQuery"))

dmsgDC, closeDmsgDC, err := direct.StartDmsg(cmd.Context(), logging.NewMasterLogger().PackageLogger("ut_dmsgHTTPQuery"),
pk, sk, dClient, dmsg.DefaultConfig())
if err != nil {
return []byte{}, fmt.Errorf("failed to start dmsg: %w", err)
}
defer closeDmsgDC()

dmsgHTTP := http.Client{Transport: dmsghttp.MakeHTTPTransport(cmd.Context(), dmsgDC)}

resp, err := dmsgHTTP.Get(utDmsgAddr + "/uptimes?v=v2")
if err != nil {
return []byte{}, err
}
return io.ReadAll(resp.Body)
}

func httpQuery(cmd *cobra.Command) ([]byte, error) {
if pk != "" {
err := pubkey.Set(pk)
if err != nil {
return []byte{}, err
}
url += "&visors=" + pubkey.String()
}
utClient := http.Client{
Timeout: time.Second * 15, // Timeout after 15 seconds
}

req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return []byte{}, err
}

res, err := utClient.Do(req)
if err != nil {
return []byte{}, err
}

if res.Body != nil {
defer func() {
err := res.Body.Close()
if err != nil {
internal.PrintError(cmd.Flags(), fmt.Errorf("Failed to close response body"))
}
}()
}

body, err := io.ReadAll(res.Body)
if err != nil {
return []byte{}, err
}
return body, nil
}

type uptimes []struct {
Pk string `json:"pk"`
Up int `json:"up"`
Expand Down
2 changes: 1 addition & 1 deletion dmsghttp-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
{
"static": "030c83534af1041aee60c2f124b682a9d60c6421876db7c67fc83a73c5effdbd96",
"server": {
"address": "103.216.61.169:8081"
"address": "188.121.99.59:8081"
}
}
],
Expand Down
26 changes: 26 additions & 0 deletions pkg/utclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"time"

Expand All @@ -19,6 +20,7 @@ import (
// APIClient implements uptime tracker API client.
type APIClient interface {
UpdateVisorUptime(context.Context, string) error
FetchUptimes(context.Context, string) ([]byte, error)
}

// httpClient implements Client for uptime tracker API.
Expand Down Expand Up @@ -97,3 +99,27 @@ func (c *httpClient) UpdateVisorUptime(ctx context.Context, version string) erro

return nil
}

// FetchUptimes fetch uptimes data for all visors or specific one
func (c *httpClient) FetchUptimes(ctx context.Context, pk string) ([]byte, error) {
url := "/uptimes?v=v2"
if pk != "" {
url += "&visors=" + pk
}

resp, err := c.Get(ctx, url)
if err != nil {
return []byte{}, err
}

if resp.Body != nil {
defer func() {
err = resp.Body.Close()
if err != nil {
return
}
}()
}

return io.ReadAll(resp.Body)
}
20 changes: 20 additions & 0 deletions pkg/utclient/mock_api_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions pkg/visor/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ type API interface {
StopPing(pk cipher.PubKey) error

TestVisor(config PingConfig) ([]TestResult, error)

//uptime-tracker tools
FetchUptimeTrackerData(pk string) ([]byte, error)
}

// HealthCheckable resource returns its health status as an integer
Expand Down Expand Up @@ -550,6 +553,23 @@ func (v *Visor) StopVPNClient(appName string) error {
return ErrProcNotAvailable
}

// FetchUptimeTrackerData implements API
func (v *Visor) FetchUptimeTrackerData(pk string) ([]byte, error) {
var body []byte
var pubkey cipher.PubKey

if pk != "" {
err := pubkey.Set(pk)
if err != nil {
return body, fmt.Errorf("Invalid or missing public key")
}
}
if v.uptimeTracker == nil {
return body, fmt.Errorf("Uptime tracker module not available")
}
return v.uptimeTracker.FetchUptimes(context.TODO(), pk)
}

// StartSkysocksClient implements API.
func (v *Visor) StartSkysocksClient(serverKey string) error {
var envs []string
Expand Down
8 changes: 8 additions & 0 deletions pkg/visor/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ func (r *RPC) StopVPNClient(name *string, _ *struct{}) (err error) {
return r.visor.StopVPNClient(*name)
}

// FetchUptimeTrackerData trying to fetch ut data
func (r *RPC) FetchUptimeTrackerData(pk string, data *[]byte) (err error) {
defer rpcutil.LogCall(r.log, "FetchUptimeTrackerData", pk)(data, &err)
rep, err := r.visor.FetchUptimeTrackerData(pk)
*data = rep
return err
}

// StartSkysocksClient starts SkysocksClient App
func (r *RPC) StartSkysocksClient(pk string, _ *struct{}) (err error) {
defer rpcutil.LogCall(r.log, "StartSkysocksClient", pk)(nil, &err)
Expand Down
12 changes: 12 additions & 0 deletions pkg/visor/rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ func (rc *rpcClient) StopVPNClient(appName string) error {
return rc.Call("StopVPNClient", &appName, &struct{}{})
}

// FetchUptimeTrackerData calls FetchUptimeTrackerData.
func (rc *rpcClient) FetchUptimeTrackerData(pk string) ([]byte, error) {
var data []byte
err := rc.Call("FetchUptimeTrackerData", pk, &data)
return data, err
}

// StartSkysocksClient calls StartSkysocksClient.
func (rc *rpcClient) StartSkysocksClient(pk string) error {
return rc.Call("StartSkysocksClient", pk, &struct{}{})
Expand Down Expand Up @@ -852,6 +859,11 @@ func (*mockRPCClient) StopVPNClient(string) error {
return nil
}

// FetchUptimeTrackerData implements API.
func (*mockRPCClient) FetchUptimeTrackerData(string) ([]byte, error) {
return []byte{}, nil
}

// StartSkysocksClient implements API.
func (*mockRPCClient) StartSkysocksClient(string) error {
return nil
Expand Down

0 comments on commit 5dc0aba

Please sign in to comment.