diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index 97b14d6..8d972ef 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -3,9 +3,12 @@ package provider import ( "bufio" "context" + "encoding/json" "errors" "fmt" + "io" "net/http" + "net/url" "os" "strings" "time" @@ -25,6 +28,8 @@ import ( "github.com/urfave/cli/v2" ) +const filfoxPeerAPI = "https://filfox.info/api/v1/peer" + var ProviderCmd = &cli.Command{ Name: "provider", Usage: "Show information about providers known to an indexer", @@ -114,6 +119,10 @@ var providerFlags = []cli.Flag{ Aliases: []string{"pub"}, Usage: "Only print publisher address info.", }, + &cli.BoolFlag{ + Name: "spid", + Usage: "Print the provider's Filecoin storage provider ID. Optionally usable with --id-only.", + }, &cli.StringFlag{ Name: "topic", Usage: "Topic on which index advertisements are published. Only needed to get head advertisement via Graphsync with non-standard topic.", @@ -324,7 +333,17 @@ func followDistance(cctx *cli.Context, include, exclude map[peer.ID]struct{}, pc func showProviderInfo(cctx *cli.Context, pinfo *model.ProviderInfo) { if cctx.Bool("id-only") { - fmt.Println(pinfo.AddrInfo.ID) + if cctx.Bool("spid") { + fmt.Print() + miners, err := getSPID(cctx.Context, pinfo.AddrInfo.ID) + if err != nil { + miners = err.Error() + } + fmt.Println(pinfo.AddrInfo.ID, " ", miners) + } else { + fmt.Println(pinfo.AddrInfo.ID) + } + return } if cctx.Bool("publisher") { @@ -399,6 +418,14 @@ func showProviderInfo(cctx *cli.Context, pinfo *model.ProviderInfo) { } } + if cctx.Bool("spid") { + miners, err := getSPID(cctx.Context, pinfo.AddrInfo.ID) + if err != nil { + miners = fmt.Sprint("error:", err) + } + fmt.Println(" SPID:", miners) + } + fmt.Println() } @@ -466,3 +493,41 @@ func getLastSeenDistance(cctx *cli.Context, pinfo *model.ProviderInfo, p2pHost h return adDist.Get(cctx.Context, *pinfo.Publisher, pinfo.LastAdvertisement, cid.Undef) } + +func getSPID(ctx context.Context, peerID peer.ID) (string, error) { + apiURL, err := url.JoinPath(filfoxPeerAPI, peerID.String()) + if err != nil { + return "", err + } + req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil) + if err != nil { + return "", err + } + req.Header.Add("Accept-Encoding", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound { + return "", nil + } + if resp.StatusCode >= 400 { + return "", errors.New(resp.Status) + } + data, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + // {"peerId":"12D3KooWFWXbQG9x44JVauFnG7zqzfuR4eDo9iGbXUm9rTLvW7kv","miners":["f0811822"],"multiAddresses":["/ip4/3.140.191.240/tcp/7523"]} + var spinfo struct { + Miners []string `json:"miners"` + } + if err = json.Unmarshal(data, &spinfo); err != nil { + return "", err + } + + return strings.Join(spinfo.Miners, ", "), nil +} diff --git a/version.go b/version.go index 6b15316..3cbee85 100644 --- a/version.go +++ b/version.go @@ -20,9 +20,11 @@ var versionJSON []byte func init() { // Read version from embedded JSON file. - var verMap map[string]string - json.Unmarshal(versionJSON, &verMap) - Release = verMap["version"] + var v struct { + Version string `json:"version"` + } + json.Unmarshal(versionJSON, &v) + Release = v.Version // If running from a module, try to get the build info. bi, ok := debug.ReadBuildInfo()