@cryptotaxi247 / kubo / commits / 918aa07c9

refactor: move `ipfs stat provide/reprovide` to `ipfs provide stat` (#10896)

- Move `ipfs stat reprovide` to `ipfs provide stat` - Mark `ipfs stat provide` as deprecated and replaces by `ipfs provide stat` - Mark `ipfs stat reprovide` as deprecated and replaces by `ipfs provide stat` - Remove redundant code from deprecated subcommands Closes #10869

Andrew Gillis committed Aug 7, 2025 at 17:17 UTC 918aa07c9ee64500f57eab8b8e12e9a4c727a94e
5 files changed +124 -144
core/commands/commands_test.go
+1
@@ -165,6 +165,7 @@ func TestCommands(t *testing.T) {
165 "/ping",
166 "/provide",
167 "/provide/clear",
168 + "/provide/stat",
169 "/pubsub",
170 "/pubsub/ls",
171 "/pubsub/peers",
core/commands/provide.go
+99 -3
@@ -3,9 +3,15 @@ package commands
3 import (
4 "fmt"
5 "io"
6 + "text/tabwriter"
7 + "time"
8
9 + humanize "github.com/dustin/go-humanize"
10 + "github.com/ipfs/boxo/provider"
11 cmds "github.com/ipfs/go-ipfs-cmds"
8 - cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
12 + "github.com/ipfs/kubo/core/commands/cmdenv"
13 + "github.com/libp2p/go-libp2p-kad-dht/fullrt"
14 + "golang.org/x/exp/constraints"
15 )
16
17 const (
@@ -28,11 +34,12 @@ reprovide' provides statistics. Additionally, 'ipfs bitswap reprovide' and
34 },
35
36 Subcommands: map[string]*cmds.Command{
31 - "clear": ProvideClearCmd,
37 + "clear": provideClearCmd,
38 + "stat": provideStatCmd,
39 },
40 }
41
35 -var ProvideClearCmd = &cmds.Command{
42 +var provideClearCmd = &cmds.Command{
43 Status: cmds.Experimental,
44 Helptext: cmds.HelpText{
45 Tagline: "Clear all CIDs from the provide queue.",
@@ -80,3 +87,92 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy
87 }),
88 },
89 }
90 +
91 +type provideStats struct {
92 + provider.ReproviderStats
93 + fullRT bool
94 +}
95 +
96 +var provideStatCmd = &cmds.Command{
97 + Status: cmds.Experimental,
98 + Helptext: cmds.HelpText{
99 + Tagline: "Returns statistics about the node's provider system.",
100 + ShortDescription: `
101 +Returns statistics about the content the node is reproviding every
102 +Reprovider.Interval according to Reprovider.Strategy:
103 +https://github.com/ipfs/kubo/blob/master/docs/config.md#reprovider
104 +
105 +This interface is not stable and may change from release to release.
106 +
107 +`,
108 + },
109 + Arguments: []cmds.Argument{},
110 + Options: []cmds.Option{},
111 + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
112 + nd, err := cmdenv.GetNode(env)
113 + if err != nil {
114 + return err
115 + }
116 +
117 + if !nd.IsOnline {
118 + return ErrNotOnline
119 + }
120 +
121 + stats, err := nd.Provider.Stat()
122 + if err != nil {
123 + return err
124 + }
125 + _, fullRT := nd.DHTClient.(*fullrt.FullRT)
126 +
127 + if err := res.Emit(provideStats{stats, fullRT}); err != nil {
128 + return err
129 + }
130 +
131 + return nil
132 + },
133 + Encoders: cmds.EncoderMap{
134 + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s provideStats) error {
135 + wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
136 + defer wtr.Flush()
137 +
138 + fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.TotalReprovides))
139 + fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
140 + fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
141 + if !s.LastRun.IsZero() {
142 + fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.LastRun))
143 + if s.fullRT {
144 + fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
145 + }
146 + }
147 + return nil
148 + }),
149 + },
150 + Type: provideStats{},
151 +}
152 +
153 +func humanDuration(val time.Duration) string {
154 + return val.Truncate(time.Microsecond).String()
155 +}
156 +
157 +func humanTime(val time.Time) string {
158 + return val.Format("2006-01-02 15:04:05")
159 +}
160 +
161 +func humanNumber[T constraints.Float | constraints.Integer](n T) string {
162 + nf := float64(n)
163 + str := humanSI(nf, 0)
164 + fullStr := humanFull(nf, 0)
165 + if str != fullStr {
166 + return fmt.Sprintf("%s\t(%s)", str, fullStr)
167 + }
168 + return str
169 +}
170 +
171 +func humanSI(val float64, decimals int) string {
172 + v, unit := humanize.ComputeSI(val)
173 + return fmt.Sprintf("%s%s", humanFull(v, decimals), unit)
174 +}
175 +
176 +func humanFull(val float64, decimals int) string {
177 + return humanize.CommafWithDigits(val, decimals)
178 +}
core/commands/stat_provide.go
+6 -49
@@ -1,65 +1,22 @@
1 package commands
2
3 import (
4 - "fmt"
5 - "io"
6 - "text/tabwriter"
7 -
4 cmds "github.com/ipfs/go-ipfs-cmds"
9 - "github.com/ipfs/kubo/core/commands/cmdenv"
10 - "github.com/libp2p/go-libp2p-kad-dht/fullrt"
5 )
6
7 var statProvideCmd = &cmds.Command{
8 Status: cmds.Deprecated,
9 Helptext: cmds.HelpText{
16 - Tagline: "Deprecated command, use 'ipfs stats reprovide' instead.",
10 + Tagline: "Deprecated command, use 'ipfs provide stat' instead.",
11 ShortDescription: `
12 'ipfs stats provide' is deprecated because provide and reprovide operations
13 are now distinct. This command may be replaced by provide only stats in the
14 future.
15 `,
16 },
23 - Arguments: []cmds.Argument{},
24 - Options: []cmds.Option{},
25 - Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
26 - nd, err := cmdenv.GetNode(env)
27 - if err != nil {
28 - return err
29 - }
30 -
31 - if !nd.IsOnline {
32 - return ErrNotOnline
33 - }
34 -
35 - stats, err := nd.Provider.Stat()
36 - if err != nil {
37 - return err
38 - }
39 - _, fullRT := nd.DHTClient.(*fullrt.FullRT)
40 -
41 - if err := res.Emit(reprovideStats{stats, fullRT}); err != nil {
42 - return err
43 - }
44 -
45 - return nil
46 - },
47 - Encoders: cmds.EncoderMap{
48 - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s reprovideStats) error {
49 - wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
50 - defer wtr.Flush()
51 -
52 - fmt.Fprintf(wtr, "TotalProvides:\t%s\n", humanNumber(s.TotalReprovides))
53 - fmt.Fprintf(wtr, "AvgProvideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
54 - fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
55 - if !s.LastRun.IsZero() {
56 - fmt.Fprintf(wtr, "LastRun:\t%s\n", humanTime(s.LastRun))
57 - if s.fullRT {
58 - fmt.Fprintf(wtr, "NextRun:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
59 - }
60 - }
61 - return nil
62 - }),
63 - },
64 - Type: reprovideStats{},
17 + Arguments: provideStatCmd.Arguments,
18 + Options: provideStatCmd.Options,
19 + Run: provideStatCmd.Run,
20 + Encoders: provideStatCmd.Encoders,
21 + Type: provideStatCmd.Type,
22 }
core/commands/stat_reprovide.go
+9 -92
@@ -1,104 +1,21 @@
1 package commands
2
3 import (
4 - "fmt"
5 - "io"
6 - "text/tabwriter"
7 - "time"
8 -
9 - humanize "github.com/dustin/go-humanize"
10 - "github.com/ipfs/boxo/provider"
4 cmds "github.com/ipfs/go-ipfs-cmds"
12 - "github.com/ipfs/kubo/core/commands/cmdenv"
13 - "github.com/libp2p/go-libp2p-kad-dht/fullrt"
14 - "golang.org/x/exp/constraints"
5 )
6
17 -type reprovideStats struct {
18 - provider.ReproviderStats
19 - fullRT bool
20 -}
21 -
7 var statReprovideCmd = &cmds.Command{
23 - Status: cmds.Experimental,
8 + Status: cmds.Deprecated,
9 Helptext: cmds.HelpText{
25 - Tagline: "Returns statistics about the node's reprovider system.",
10 + Tagline: "Deprecated command, use 'ipfs provide stat' instead.",
11 ShortDescription: `
27 -Returns statistics about the content the node is reproviding every
28 -Reprovider.Interval according to Reprovider.Strategy:
29 -https://github.com/ipfs/kubo/blob/master/docs/config.md#reprovider
30 -
31 -This interface is not stable and may change from release to release.
32 -
12 +'ipfs stats reprovide' is deprecated because provider stats are now
13 +available fomr 'ipfs provide stat'.
14 `,
15 },
35 - Arguments: []cmds.Argument{},
36 - Options: []cmds.Option{},
37 - Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
38 - nd, err := cmdenv.GetNode(env)
39 - if err != nil {
40 - return err
41 - }
42 -
43 - if !nd.IsOnline {
44 - return ErrNotOnline
45 - }
46 -
47 - stats, err := nd.Provider.Stat()
48 - if err != nil {
49 - return err
50 - }
51 - _, fullRT := nd.DHTClient.(*fullrt.FullRT)
52 -
53 - if err := res.Emit(reprovideStats{stats, fullRT}); err != nil {
54 - return err
55 - }
56 -
57 - return nil
58 - },
59 - Encoders: cmds.EncoderMap{
60 - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s reprovideStats) error {
61 - wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
62 - defer wtr.Flush()
63 -
64 - fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.TotalReprovides))
65 - fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
66 - fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
67 - if !s.LastRun.IsZero() {
68 - fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.LastRun))
69 - if s.fullRT {
70 - fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
71 - }
72 - }
73 - return nil
74 - }),
75 - },
76 - Type: reprovideStats{},
77 -}
78 -
79 -func humanDuration(val time.Duration) string {
80 - return val.Truncate(time.Microsecond).String()
81 -}
82 -
83 -func humanTime(val time.Time) string {
84 - return val.Format("2006-01-02 15:04:05")
85 -}
86 -
87 -func humanNumber[T constraints.Float | constraints.Integer](n T) string {
88 - nf := float64(n)
89 - str := humanSI(nf, 0)
90 - fullStr := humanFull(nf, 0)
91 - if str != fullStr {
92 - return fmt.Sprintf("%s\t(%s)", str, fullStr)
93 - }
94 - return str
95 -}
96 -
97 -func humanSI(val float64, decimals int) string {
98 - v, unit := humanize.ComputeSI(val)
99 - return fmt.Sprintf("%s%s", humanFull(v, decimals), unit)
100 -}
101 -
102 -func humanFull(val float64, decimals int) string {
103 - return humanize.CommafWithDigits(val, decimals)
16 + Arguments: provideStatCmd.Arguments,
17 + Options: provideStatCmd.Options,
18 + Run: provideStatCmd.Run,
19 + Encoders: provideStatCmd.Encoders,
20 + Type: provideStatCmd.Type,
21 }
docs/changelogs/v0.37.md
+9
@@ -13,6 +13,7 @@ This release was brought to you by the [Interplanetary Shipyard](https://ipship
13 - [Clear provide queue when reprovide strategy changes](#clear-provide-queue-when-reprovide-strategy-changes)
14 - [Named pins in `ipfs add` command](#-named-pins-in-ipfs-add-command)
15 - [Removed unnecessary dependencies](#removed-unnecessary-dependencies)
16 + - [Deprecated `ipfs stats reprovide`](#deprecated-ipfs-stats-reprovide)
17 - [📦️ Important dependency updates](#-important-dependency-updates)
18 - [📝 Changelog](#-changelog)
19 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
@@ -55,6 +56,14 @@ Kubo has been cleaned up by removing unnecessary dependencies and packages:
56
57 These changes reduce the dependency footprint while improving code maintainability and following Go best practices.
58
59 +#### Deprecated `ipfs stats reprovide`
60 +
61 +The `ipfs stats reprovide` command has moved to `ipfs provide stat`. This was done to organize provider commands in one location.
62 +
63 +> [!NOTE]
64 +> `ipfs stats reprovide` still works, but is marked as deprecated and will be removed in a future release.
65 +
66 +
67 #### 📦️ Important dependency updates
68
69 - update `go-libp2p` to [v0.42.1](https://github.com/libp2p/go-libp2p/releases/tag/v0.42.1)