diff --git a/.github/workflows/golang-analysis.yml b/.github/workflows/golang-analysis.yml index 1ad843ff497..387d2ab851c 100644 --- a/.github/workflows/golang-analysis.yml +++ b/.github/workflows/golang-analysis.yml @@ -61,3 +61,6 @@ jobs: uses: protocol/multiple-go-modules@v1.4 with: run: go vet ./... + - name: Check generated RPC client + if: always() + run: go run ./tools/gen-rpc-client -check ./client/rpc/ diff --git a/Rules.mk b/Rules.mk index b04e3d73e73..07a782a965f 100644 --- a/Rules.mk +++ b/Rules.mk @@ -70,6 +70,14 @@ mod_tidy: @find . -name go.mod -execdir $(GOCC) mod tidy \; .PHONY: mod_tidy +rpc_client: + $(GOCC) run ./tools/gen-rpc-client -output ./client/rpc/ +.PHONY: rpc_client + +rpc_client_check: + $(GOCC) run ./tools/gen-rpc-client -check ./client/rpc/ +.PHONY: rpc_client_check + coverage: $(COVERAGE) .PHONY: coverage @@ -124,6 +132,7 @@ help: @echo ' nofuse - Build binary with no fuse support' @echo ' install - Build binary and install into $$GOBIN' @echo ' mod_tidy - Remove unused dependencies from go.mod files' + @echo ' rpc_client - Regenerate client/rpc/gen_*.go from command definitions' # @echo ' dist_install - TODO: c.f. ./cmd/ipfs/dist/README.md' @echo '' @echo 'CLEANING TARGETS:' @@ -142,6 +151,7 @@ help: @echo ' test_go_build - Build kubo for all platforms from .github/build-platforms.yml' @echo ' test_go_lint - Run golangci-lint' @echo ' test_sharness - Run sharness tests' + @echo ' rpc_client_check - Verify generated RPC client is up to date' @echo ' coverage - Collect coverage info from unit tests and sharness' @echo .PHONY: help diff --git a/client/rpc/api.go b/client/rpc/api.go index c4b73d387c2..08ca09f63bd 100644 --- a/client/rpc/api.go +++ b/client/rpc/api.go @@ -218,42 +218,52 @@ func (api *HttpApi) Request(command string, args ...string) RequestBuilder { } } +// Deprecated: use HttpApi methods directly (e.g., api.Add, api.Ls). func (api *HttpApi) Unixfs() iface.UnixfsAPI { return (*UnixfsAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.BlockGet, api.BlockPut, api.BlockStat). func (api *HttpApi) Block() iface.BlockAPI { return (*BlockAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.DagGet, api.DagPut, api.DagStat). func (api *HttpApi) Dag() iface.APIDagService { return (*HttpDagServ)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.NamePublish, api.NameResolve). func (api *HttpApi) Name() iface.NameAPI { return (*NameAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.KeyGen, api.KeyLs, api.KeyRm). func (api *HttpApi) Key() iface.KeyAPI { return (*KeyAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.PinAdd, api.PinLs, api.PinRm). func (api *HttpApi) Pin() iface.PinAPI { return (*PinAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.ObjectPatchAddLink, api.ObjectDiff). func (api *HttpApi) Object() iface.ObjectAPI { return (*ObjectAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.SwarmPeers, api.SwarmConnect). func (api *HttpApi) Swarm() iface.SwarmAPI { return (*SwarmAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.PubsubLs, api.PubsubPub, api.PubsubSub). func (api *HttpApi) PubSub() iface.PubSubAPI { return (*PubsubAPI)(api) } +// Deprecated: use HttpApi methods directly (e.g., api.RoutingFindpeer, api.RoutingFindprovs). func (api *HttpApi) Routing() iface.RoutingAPI { return (*RoutingAPI)(api) } diff --git a/client/rpc/block.go b/client/rpc/block.go index 9345a5f1964..113f7d3f796 100644 --- a/client/rpc/block.go +++ b/client/rpc/block.go @@ -14,6 +14,8 @@ import ( mh "github.com/multiformats/go-multihash" ) +// Deprecated: use HttpApi.BlockGet, HttpApi.BlockPut, HttpApi.BlockRm, HttpApi.BlockStat instead. +// This type implements the legacy CoreAPI BlockAPI interface and will be removed in a future release. type BlockAPI HttpApi type blockStat struct { diff --git a/client/rpc/dag.go b/client/rpc/dag.go index 63cac8f61ac..5f87bbd269d 100644 --- a/client/rpc/dag.go +++ b/client/rpc/dag.go @@ -14,6 +14,8 @@ import ( multicodec "github.com/multiformats/go-multicodec" ) +// Deprecated: use HttpApi.DagGet, HttpApi.DagPut, HttpApi.DagStat, HttpApi.DagExport, HttpApi.DagImport instead. +// These types implement the legacy CoreAPI APIDagService interface and will be removed in a future release. type ( httpNodeAdder HttpApi HttpDagServ httpNodeAdder diff --git a/client/rpc/gen_add.go b/client/rpc/gen_add.go new file mode 100644 index 00000000000..dbdc3f23f37 --- /dev/null +++ b/client/rpc/gen_add.go @@ -0,0 +1,271 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "io" + "iter" +) + +type AddResponse struct { + Name string `json:"Name,omitempty"` + Hash string `json:",omitempty"` + Bytes int64 `json:",omitempty"` + Size string `json:",omitempty"` + Mode string `json:",omitempty"` + Mtime int64 `json:",omitempty"` + MtimeNsecs int `json:",omitempty"` +} + +// AddOption configures the add command. +type AddOption func(RequestBuilder) + +// AddRecursive sets the recursive option. +// Add directory paths recursively. +func AddRecursive(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// AddDereferenceArgs sets the dereference-args option. +// DEPRECATED: use --dereference-symlinks instead. Only dereferences symlinks in CLI arguments, not inside directories. +func AddDereferenceArgs(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("dereference-args", v) } +} + +// AddStdinName sets the stdin-name option. +// Assign a name if the file source is stdin. +func AddStdinName(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("stdin-name", v) } +} + +// AddHidden sets the hidden option. +// Include files that are hidden. Only takes effect on recursive add. +func AddHidden(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("hidden", v) } +} + +// AddIgnore sets the ignore option. +// A rule (.gitignore-stype) defining which file(s) should be ignored (variadic, experimental). +func AddIgnore(v []string) AddOption { + return func(rb RequestBuilder) { rb.Option("ignore", v) } +} + +// AddIgnoreRulesPath sets the ignore-rules-path option. +// A path to a file with .gitignore-style ignore rules (experimental). +func AddIgnoreRulesPath(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("ignore-rules-path", v) } +} + +// AddEmptyDirs sets the empty-dirs option. +// Include empty directories in the import. Default: true. +func AddEmptyDirs(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("empty-dirs", v) } +} + +// AddDereferenceSymlinks sets the dereference-symlinks option. +// Recursively resolve all symlinks to their target content. Works on symlinks inside directories, not just CLI arguments. +func AddDereferenceSymlinks(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("dereference-symlinks", v) } +} + +// AddQuiet sets the quiet option. +// Write minimal output. +func AddQuiet(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// AddQuieter sets the quieter option. +// Write only final hash. +func AddQuieter(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("quieter", v) } +} + +// AddSilent sets the silent option. +// Write no output. +func AddSilent(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("silent", v) } +} + +// AddProgress sets the progress option. +// Stream progress data. +func AddProgress(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// AddOnlyHash sets the only-hash option. +// Only chunk and hash - do not write to disk. +func AddOnlyHash(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("only-hash", v) } +} + +// AddWrapWithDirectory sets the wrap-with-directory option. +// Wrap files with a directory object. +func AddWrapWithDirectory(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("wrap-with-directory", v) } +} + +// AddPin sets the pin option. +// Pin locally to protect added files from garbage collection. Default: true. +func AddPin(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("pin", v) } +} + +// AddPinName sets the pin-name option. +// Name to use for the pin. Requires explicit value (e.g., --pin-name=myname). +func AddPinName(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("pin-name", v) } +} + +// AddToFiles sets the to-files option. +// Add reference to Files API (MFS) at the provided path. +func AddToFiles(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("to-files", v) } +} + +// AddCidVersion sets the cid-version option. +// CID version (0 or 1). CIDv1 automatically enables raw-leaves and is required for non-sha2-256 hashes. Default: Import.CidVersion. +func AddCidVersion(v int) AddOption { + return func(rb RequestBuilder) { rb.Option("cid-version", v) } +} + +// AddHash sets the hash option. +// Hash function to use. Implies CIDv1 if not sha2-256. Default: Import.HashFunction. +func AddHash(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// AddRawLeaves sets the raw-leaves option. +// Use raw blocks for leaf nodes. Note: CIDv1 automatically enables raw-leaves. Default: false for CIDv0, true for CIDv1 (Import.UnixFSRawLeaves). +func AddRawLeaves(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("raw-leaves", v) } +} + +// AddChunker sets the chunker option. +// Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash. Files larger than chunk size are split into multiple blocks. Default: Import.UnixFSChunker. +func AddChunker(v string) AddOption { + return func(rb RequestBuilder) { rb.Option("chunker", v) } +} + +// AddTrickle sets the trickle option. +// Use trickle-dag format for dag generation. +func AddTrickle(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("trickle", v) } +} + +// AddMaxFileLinks sets the max-file-links option. +// Limit the maximum number of links in UnixFS file nodes to this value. WARNING: experimental. Default: Import.UnixFSFileMaxLinks. +func AddMaxFileLinks(v int) AddOption { + return func(rb RequestBuilder) { rb.Option("max-file-links", v) } +} + +// AddMaxDirectoryLinks sets the max-directory-links option. +// Limit the maximum number of links in UnixFS basic directory nodes to this value. WARNING: experimental, Import.UnixFSHAMTDirectorySizeThreshold is safer. Default: Import.UnixFSDirectoryMaxLinks. +func AddMaxDirectoryLinks(v int) AddOption { + return func(rb RequestBuilder) { rb.Option("max-directory-links", v) } +} + +// AddMaxHamtFanout sets the max-hamt-fanout option. +// Limit the maximum number of links of a UnixFS HAMT directory node to this (power of 2, multiple of 8). WARNING: experimental, Import.UnixFSHAMTDirectorySizeThreshold is safer. Default: Import.UnixFSHAMTDirectoryMaxFanout. +func AddMaxHamtFanout(v int) AddOption { + return func(rb RequestBuilder) { rb.Option("max-hamt-fanout", v) } +} + +// AddInline sets the inline option. +// Inline small blocks into CIDs. WARNING: experimental. +func AddInline(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("inline", v) } +} + +// AddInlineLimit sets the inline-limit option. +// Maximum block size to inline. Maximum: 128 bytes. WARNING: experimental. Default: 32. +func AddInlineLimit(v int) AddOption { + return func(rb RequestBuilder) { rb.Option("inline-limit", v) } +} + +// AddNocopy sets the nocopy option. +// Add the file using filestore. Implies raw-leaves. WARNING: experimental. +func AddNocopy(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("nocopy", v) } +} + +// AddFscache sets the fscache option. +// Check the filestore for pre-existing blocks. WARNING: experimental. +func AddFscache(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("fscache", v) } +} + +// AddPreserveMode sets the preserve-mode option. +// Apply existing POSIX permissions to created UnixFS entries. WARNING: experimental, forces dag-pb for root block, disables raw-leaves. +func AddPreserveMode(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("preserve-mode", v) } +} + +// AddPreserveMtime sets the preserve-mtime option. +// Apply existing POSIX modification time to created UnixFS entries. WARNING: experimental, forces dag-pb for root block, disables raw-leaves. +func AddPreserveMtime(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("preserve-mtime", v) } +} + +// AddMode sets the mode option. +// Custom POSIX file mode to store in created UnixFS entries. WARNING: experimental, forces dag-pb for root block, disables raw-leaves. +func AddMode(v uint) AddOption { + return func(rb RequestBuilder) { rb.Option("mode", v) } +} + +// AddMtime sets the mtime option. +// Custom POSIX modification time to store in created UnixFS entries (seconds before or after the Unix Epoch). WARNING: experimental, forces dag-pb for root block, disables raw-leaves. +func AddMtime(v int64) AddOption { + return func(rb RequestBuilder) { rb.Option("mtime", v) } +} + +// AddMtimeNsecs sets the mtime-nsecs option. +// Custom POSIX modification time (optional time fraction in nanoseconds). +func AddMtimeNsecs(v uint) AddOption { + return func(rb RequestBuilder) { rb.Option("mtime-nsecs", v) } +} + +// AddFastProvideRoot sets the fast-provide-root option. +// Immediately provide root CID to DHT in addition to regular queue, for faster discovery. Default: Import.FastProvideRoot. +func AddFastProvideRoot(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("fast-provide-root", v) } +} + +// AddFastProvideWait sets the fast-provide-wait option. +// Block until the immediate provide completes before returning. Default: Import.FastProvideWait. +func AddFastProvideWait(v bool) AddOption { + return func(rb RequestBuilder) { rb.Option("fast-provide-wait", v) } +} + +// Add add a file or directory to IPFS.. +func (a *HttpApi) Add(ctx context.Context, path io.Reader, opts ...AddOption) iter.Seq2[AddResponse, error] { + return func(yield func(AddResponse, error) bool) { + req := a.Request("add") + req = req.FileBody(path).(RequestBuilder) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(AddResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(AddResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item AddResponse + if err := dec.Decode(&item); err != nil { + yield(AddResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_bitswap.go b/client/rpc/gen_bitswap.go new file mode 100644 index 00000000000..4ebb30f841b --- /dev/null +++ b/client/rpc/gen_bitswap.go @@ -0,0 +1,106 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type BitswapLedgerResponse struct { + Peer string `json:"Peer,omitempty"` + Value float64 `json:"Value,omitempty"` + Sent uint64 `json:"Sent,omitempty"` + Recv uint64 `json:"Recv,omitempty"` + Exchanged uint64 `json:"Exchanged,omitempty"` +} + +type BitswapStatResponse struct { + Wantlist []string `json:"Wantlist,omitempty"` + Peers []string `json:"Peers,omitempty"` + BlocksReceived uint64 `json:"BlocksReceived,omitempty"` + DataReceived uint64 `json:"DataReceived,omitempty"` + DupBlksReceived uint64 `json:"DupBlksReceived,omitempty"` + DupDataReceived uint64 `json:"DupDataReceived,omitempty"` + MessagesReceived uint64 `json:"MessagesReceived,omitempty"` + BlocksSent uint64 `json:"BlocksSent,omitempty"` + DataSent uint64 `json:"DataSent,omitempty"` +} + +type BitswapWantlistResponse struct { + Keys []string `json:"Keys,omitempty"` +} + +// BitswapLedger show the current ledger for a peer.. +func (a *HttpApi) BitswapLedger(ctx context.Context, peer string) (*BitswapLedgerResponse, error) { + req := a.Request("bitswap/ledger", peer) + var resp BitswapLedgerResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Deprecated: BitswapReprovide may be removed in a future release. +// BitswapReprovide deprecated command to announce to bitswap. Use 'ipfs routing reprovide' instead.. +func (a *HttpApi) BitswapReprovide(ctx context.Context) (*Response, error) { + req := a.Request("bitswap/reprovide") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// BitswapStatOption configures the bitswap/stat command. +type BitswapStatOption func(RequestBuilder) + +// BitswapStatVerbose sets the verbose option. +// Print extra information. +func BitswapStatVerbose(v bool) BitswapStatOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// BitswapStatHuman sets the human option. +// Print sizes in human readable format (e.g., 1K 234M 2G). +func BitswapStatHuman(v bool) BitswapStatOption { + return func(rb RequestBuilder) { rb.Option("human", v) } +} + +// BitswapStat show some diagnostic information on the bitswap agent.. +func (a *HttpApi) BitswapStat(ctx context.Context, opts ...BitswapStatOption) (*BitswapStatResponse, error) { + req := a.Request("bitswap/stat") + for _, o := range opts { + o(req) + } + var resp BitswapStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BitswapWantlistOption configures the bitswap/wantlist command. +type BitswapWantlistOption func(RequestBuilder) + +// BitswapWantlistPeer sets the peer option. +// Specify which peer to show wantlist for. Default: self. +func BitswapWantlistPeer(v string) BitswapWantlistOption { + return func(rb RequestBuilder) { rb.Option("peer", v) } +} + +// BitswapWantlist show blocks currently on the wantlist.. +func (a *HttpApi) BitswapWantlist(ctx context.Context, opts ...BitswapWantlistOption) (*BitswapWantlistResponse, error) { + req := a.Request("bitswap/wantlist") + for _, o := range opts { + o(req) + } + var resp BitswapWantlistResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_block.go b/client/rpc/gen_block.go new file mode 100644 index 00000000000..59a65feff93 --- /dev/null +++ b/client/rpc/gen_block.go @@ -0,0 +1,128 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "io" +) + +type BlockPutResponse struct { + Key string `json:"Key,omitempty"` + Size int `json:"Size,omitempty"` +} + +type BlockRmResponse struct { + Hash string `json:",omitempty"` + Error string `json:",omitempty"` +} + +type BlockStatResponse struct { + Key string `json:"Key,omitempty"` + Size int `json:"Size,omitempty"` +} + +// BlockGet get a raw IPFS block.. +func (a *HttpApi) BlockGet(ctx context.Context, cid string) (*Response, error) { + req := a.Request("block/get", cid) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// BlockPutOption configures the block/put command. +type BlockPutOption func(RequestBuilder) + +// BlockPutCidCodec sets the cid-codec option. +// Multicodec to use in returned CID. Default: raw. +func BlockPutCidCodec(v string) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("cid-codec", v) } +} + +// BlockPutMhtype sets the mhtype option. +// Multihash hash function. +func BlockPutMhtype(v string) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("mhtype", v) } +} + +// BlockPutMhlen sets the mhlen option. +// Multihash hash length. Default: -1. +func BlockPutMhlen(v int) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("mhlen", v) } +} + +// BlockPutPin sets the pin option. +// Pin added blocks recursively. Default: false. +func BlockPutPin(v bool) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("pin", v) } +} + +// BlockPutAllowBigBlock sets the allow-big-block option. +// Disable block size check and allow creation of blocks bigger than 2MiB. WARNING: such blocks won't be transferable over the standard bitswap. Default: false. +func BlockPutAllowBigBlock(v bool) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("allow-big-block", v) } +} + +// BlockPutFormat sets the format option. +// Use legacy format for returned CID (DEPRECATED). +func BlockPutFormat(v string) BlockPutOption { + return func(rb RequestBuilder) { rb.Option("format", v) } +} + +// BlockPut store input as an IPFS block.. +func (a *HttpApi) BlockPut(ctx context.Context, data io.Reader, opts ...BlockPutOption) (*BlockPutResponse, error) { + req := a.Request("block/put") + req = req.FileBody(data).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp BlockPutResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BlockRmOption configures the block/rm command. +type BlockRmOption func(RequestBuilder) + +// BlockRmForce sets the force option. +// Ignore nonexistent blocks. +func BlockRmForce(v bool) BlockRmOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// BlockRmQuiet sets the quiet option. +// Write minimal output. +func BlockRmQuiet(v bool) BlockRmOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// BlockRm remove IPFS block(s) from the local datastore.. +func (a *HttpApi) BlockRm(ctx context.Context, cid []string, opts ...BlockRmOption) (*BlockRmResponse, error) { + req := a.Request("block/rm").Arguments(cid...) + for _, o := range opts { + o(req) + } + var resp BlockRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BlockStat print information of a raw IPFS block.. +func (a *HttpApi) BlockStat(ctx context.Context, cid string) (*BlockStatResponse, error) { + req := a.Request("block/stat", cid) + var resp BlockStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_bootstrap.go b/client/rpc/gen_bootstrap.go new file mode 100644 index 00000000000..a743136d922 --- /dev/null +++ b/client/rpc/gen_bootstrap.go @@ -0,0 +1,101 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type BootstrapAddResponse struct { + Peers []string `json:"Peers,omitempty"` +} + +type BootstrapListResponse struct { + Peers []string `json:"Peers,omitempty"` +} + +type BootstrapResponse struct { + Peers []string `json:"Peers,omitempty"` +} + +type BootstrapRmAllResponse struct { + Peers []string `json:"Peers,omitempty"` +} + +type BootstrapRmResponse struct { + Peers []string `json:"Peers,omitempty"` +} + +// Bootstrap show or edit the list of bootstrap peers.. +func (a *HttpApi) Bootstrap(ctx context.Context) (*BootstrapResponse, error) { + req := a.Request("bootstrap") + var resp BootstrapResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BootstrapAdd add peers to the bootstrap list.. +func (a *HttpApi) BootstrapAdd(ctx context.Context, peer ...string) (*BootstrapAddResponse, error) { + req := a.Request("bootstrap/add").Arguments(peer...) + var resp BootstrapAddResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BootstrapListOption configures the bootstrap/list command. +type BootstrapListOption func(RequestBuilder) + +// BootstrapListExpandAuto sets the expand-auto option. +// Expand 'auto' placeholders from AutoConf service. +func BootstrapListExpandAuto(v bool) BootstrapListOption { + return func(rb RequestBuilder) { rb.Option("expand-auto", v) } +} + +// BootstrapList show peers in the bootstrap list.. +func (a *HttpApi) BootstrapList(ctx context.Context, opts ...BootstrapListOption) (*BootstrapListResponse, error) { + req := a.Request("bootstrap/list") + for _, o := range opts { + o(req) + } + var resp BootstrapListResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BootstrapRmOption configures the bootstrap/rm command. +type BootstrapRmOption func(RequestBuilder) + +// BootstrapRmAll sets the all option. +// Remove all bootstrap peers. (Deprecated, use 'all' subcommand). +func BootstrapRmAll(v bool) BootstrapRmOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// BootstrapRm remove peers from the bootstrap list.. +func (a *HttpApi) BootstrapRm(ctx context.Context, peer []string, opts ...BootstrapRmOption) (*BootstrapRmResponse, error) { + req := a.Request("bootstrap/rm").Arguments(peer...) + for _, o := range opts { + o(req) + } + var resp BootstrapRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// BootstrapRmAll remove all peers from the bootstrap list.. +func (a *HttpApi) BootstrapRmAll(ctx context.Context) (*BootstrapRmAllResponse, error) { + req := a.Request("bootstrap/rm/all") + var resp BootstrapRmAllResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_cat.go b/client/rpc/gen_cat.go new file mode 100644 index 00000000000..3bfe0306a58 --- /dev/null +++ b/client/rpc/gen_cat.go @@ -0,0 +1,45 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +// CatOption configures the cat command. +type CatOption func(RequestBuilder) + +// CatOffset sets the offset option. +// Byte offset to begin reading from. +func CatOffset(v int64) CatOption { + return func(rb RequestBuilder) { rb.Option("offset", v) } +} + +// CatLength sets the length option. +// Maximum number of bytes to read. +func CatLength(v int64) CatOption { + return func(rb RequestBuilder) { rb.Option("length", v) } +} + +// CatProgress sets the progress option. +// Stream progress data. Default: true. +func CatProgress(v bool) CatOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// Cat show IPFS object data.. +func (a *HttpApi) Cat(ctx context.Context, ipfs_path []string, opts ...CatOption) (*Response, error) { + req := a.Request("cat").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_cid.go b/client/rpc/gen_cid.go new file mode 100644 index 00000000000..2d05283d756 --- /dev/null +++ b/client/rpc/gen_cid.go @@ -0,0 +1,168 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type CidBase32Response struct { + CidStr string `json:"CidStr,omitempty"` + Formatted string `json:"Formatted,omitempty"` + ErrorMsg string `json:"ErrorMsg,omitempty"` +} + +type CidBasesItem struct { + Code int `json:"Code,omitempty"` + Name string `json:"Name,omitempty"` +} + +type CidCodecsItem struct { + Code int `json:"Code,omitempty"` + Name string `json:"Name,omitempty"` +} + +type CidFormatResponse struct { + CidStr string `json:"CidStr,omitempty"` + Formatted string `json:"Formatted,omitempty"` + ErrorMsg string `json:"ErrorMsg,omitempty"` +} + +type CidHashesItem struct { + Code int `json:"Code,omitempty"` + Name string `json:"Name,omitempty"` +} + +// CidBase32 convert CIDs to Base32 CID version 1.. +func (a *HttpApi) CidBase32(ctx context.Context, cid ...string) (*CidBase32Response, error) { + req := a.Request("cid/base32").Arguments(cid...) + var resp CidBase32Response + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// CidBasesOption configures the cid/bases command. +type CidBasesOption func(RequestBuilder) + +// CidBasesPrefix sets the prefix option. +// also include the single letter prefixes in addition to the code. +func CidBasesPrefix(v bool) CidBasesOption { + return func(rb RequestBuilder) { rb.Option("prefix", v) } +} + +// CidBasesNumeric sets the numeric option. +// also include numeric codes. +func CidBasesNumeric(v bool) CidBasesOption { + return func(rb RequestBuilder) { rb.Option("numeric", v) } +} + +// CidBases list available multibase encodings.. +func (a *HttpApi) CidBases(ctx context.Context, opts ...CidBasesOption) ([]CidBasesItem, error) { + req := a.Request("cid/bases") + for _, o := range opts { + o(req) + } + var resp []CidBasesItem + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return resp, nil +} + +// CidCodecsOption configures the cid/codecs command. +type CidCodecsOption func(RequestBuilder) + +// CidCodecsNumeric sets the numeric option. +// also include numeric codes. +func CidCodecsNumeric(v bool) CidCodecsOption { + return func(rb RequestBuilder) { rb.Option("numeric", v) } +} + +// CidCodecsSupported sets the supported option. +// list only codecs supported by go-ipfs commands. +func CidCodecsSupported(v bool) CidCodecsOption { + return func(rb RequestBuilder) { rb.Option("supported", v) } +} + +// CidCodecs list available CID multicodecs.. +func (a *HttpApi) CidCodecs(ctx context.Context, opts ...CidCodecsOption) ([]CidCodecsItem, error) { + req := a.Request("cid/codecs") + for _, o := range opts { + o(req) + } + var resp []CidCodecsItem + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return resp, nil +} + +// CidFormatOption configures the cid/format command. +type CidFormatOption func(RequestBuilder) + +// CidFormatF sets the f option. +// Printf style format string. Default: %s. +func CidFormatF(v string) CidFormatOption { + return func(rb RequestBuilder) { rb.Option("f", v) } +} + +// CidFormatV sets the v option. +// CID version to convert to. +func CidFormatV(v string) CidFormatOption { + return func(rb RequestBuilder) { rb.Option("v", v) } +} + +// CidFormatMc sets the mc option. +// CID multicodec to convert to. +func CidFormatMc(v string) CidFormatOption { + return func(rb RequestBuilder) { rb.Option("mc", v) } +} + +// CidFormatB sets the b option. +// Multibase to display CID in. +func CidFormatB(v string) CidFormatOption { + return func(rb RequestBuilder) { rb.Option("b", v) } +} + +// CidFormat format and convert a CID in various useful ways.. +func (a *HttpApi) CidFormat(ctx context.Context, cid []string, opts ...CidFormatOption) (*CidFormatResponse, error) { + req := a.Request("cid/format").Arguments(cid...) + for _, o := range opts { + o(req) + } + var resp CidFormatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// CidHashesOption configures the cid/hashes command. +type CidHashesOption func(RequestBuilder) + +// CidHashesNumeric sets the numeric option. +// also include numeric codes. +func CidHashesNumeric(v bool) CidHashesOption { + return func(rb RequestBuilder) { rb.Option("numeric", v) } +} + +// CidHashesSupported sets the supported option. +// list only codecs supported by go-ipfs commands. +func CidHashesSupported(v bool) CidHashesOption { + return func(rb RequestBuilder) { rb.Option("supported", v) } +} + +// CidHashes list available multihashes.. +func (a *HttpApi) CidHashes(ctx context.Context, opts ...CidHashesOption) ([]CidHashesItem, error) { + req := a.Request("cid/hashes") + for _, o := range opts { + o(req) + } + var resp []CidHashesItem + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return resp, nil +} diff --git a/client/rpc/gen_commands.go b/client/rpc/gen_commands.go new file mode 100644 index 00000000000..dba9ec1fca2 --- /dev/null +++ b/client/rpc/gen_commands.go @@ -0,0 +1,40 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" +) + +type CommandsResponse struct { + Name string `json:"Name,omitempty"` + Subcommands []json.RawMessage `json:"Subcommands,omitempty"` + Options []CommandsResponseOptions `json:"Options,omitempty"` +} + +type CommandsResponseOptions struct { + Names []string `json:"Names,omitempty"` +} + +// CommandsOption configures the commands command. +type CommandsOption func(RequestBuilder) + +// CommandsFlags sets the flags option. +// Show command flags. +func CommandsFlags(v bool) CommandsOption { + return func(rb RequestBuilder) { rb.Option("flags", v) } +} + +// Commands list all available commands.. +func (a *HttpApi) Commands(ctx context.Context, opts ...CommandsOption) (*CommandsResponse, error) { + req := a.Request("commands") + for _, o := range opts { + o(req) + } + var resp CommandsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_config.go b/client/rpc/gen_config.go new file mode 100644 index 00000000000..dc88373467a --- /dev/null +++ b/client/rpc/gen_config.go @@ -0,0 +1,104 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "io" +) + +type ConfigProfileApplyResponse struct { + OldCfg map[string]json.RawMessage `json:"OldCfg,omitempty"` + NewCfg map[string]json.RawMessage `json:"NewCfg,omitempty"` +} + +type ConfigResponse struct { + Key string `json:"Key,omitempty"` + Value json.RawMessage `json:"Value,omitempty"` +} + +// ConfigOption configures the config command. +type ConfigOption func(RequestBuilder) + +// ConfigBool sets the bool option. +// Set a boolean value. +func ConfigBool(v bool) ConfigOption { + return func(rb RequestBuilder) { rb.Option("bool", v) } +} + +// ConfigJson sets the json option. +// Parse stringified JSON. +func ConfigJson(v bool) ConfigOption { + return func(rb RequestBuilder) { rb.Option("json", v) } +} + +// ConfigExpandAuto sets the expand-auto option. +// Expand 'auto' placeholders to their expanded values from AutoConf service. +func ConfigExpandAuto(v bool) ConfigOption { + return func(rb RequestBuilder) { rb.Option("expand-auto", v) } +} + +// Config get and set IPFS config values.. +func (a *HttpApi) Config(ctx context.Context, key string, value string, opts ...ConfigOption) (*ConfigResponse, error) { + req := a.Request("config", key, value) + for _, o := range opts { + o(req) + } + var resp ConfigResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// ConfigProfileApplyOption configures the config/profile/apply command. +type ConfigProfileApplyOption func(RequestBuilder) + +// ConfigProfileApplyDryRun sets the dry-run option. +// print difference between the current config and the config that would be generated. +func ConfigProfileApplyDryRun(v bool) ConfigProfileApplyOption { + return func(rb RequestBuilder) { rb.Option("dry-run", v) } +} + +// ConfigProfileApply apply profile to config.. +func (a *HttpApi) ConfigProfileApply(ctx context.Context, profile string, opts ...ConfigProfileApplyOption) (*ConfigProfileApplyResponse, error) { + req := a.Request("config/profile/apply", profile) + for _, o := range opts { + o(req) + } + var resp ConfigProfileApplyResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// ConfigReplace replace the config with .. +func (a *HttpApi) ConfigReplace(ctx context.Context, file io.Reader) (*Response, error) { + req := a.Request("config/replace") + req = req.FileBody(file).(RequestBuilder) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// ConfigShow output config file contents.. +func (a *HttpApi) ConfigShow(ctx context.Context) (*Response, error) { + req := a.Request("config/show") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_dag.go b/client/rpc/gen_dag.go new file mode 100644 index 00000000000..b97ef7b1afc --- /dev/null +++ b/client/rpc/gen_dag.go @@ -0,0 +1,250 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "io" + "iter" +) + +type DagImportResponse struct { + Root *DagImportResponseRoot `json:",omitempty"` + Stats *DagImportResponseStats `json:",omitempty"` +} + +type DagImportResponseRoot struct { + Cid string `json:"Cid,omitempty"` + PinErrorMsg string `json:"PinErrorMsg,omitempty"` +} + +type DagImportResponseStats struct { + BlockCount uint64 `json:"BlockCount,omitempty"` + BlockBytesCount uint64 `json:"BlockBytesCount,omitempty"` +} + +type DagPutResponse struct { + Cid string `json:"Cid,omitempty"` +} + +type DagResolveResponse struct { + Cid string `json:"Cid,omitempty"` + RemPath string `json:"RemPath,omitempty"` +} + +type DagStatResponse struct { + UniqueBlocks int `json:",omitempty"` + TotalSize uint64 `json:",omitempty"` + SharedSize uint64 `json:",omitempty"` + Ratio float32 `json:",omitempty"` + DagStatsArray []*DagStatResponseDagStatsArray `json:"DagStats,omitempty"` +} + +type DagStatResponseDagStatsArray struct { + Cid string `json:"Cid,omitempty"` + Size uint64 `json:",omitempty"` + NumBlocks int64 `json:",omitempty"` +} + +// DagExportOption configures the dag/export command. +type DagExportOption func(RequestBuilder) + +// DagExportProgress sets the progress option. +// Display progress on CLI. Defaults to true when STDERR is a TTY. +func DagExportProgress(v bool) DagExportOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// DagExport streams the selected DAG as a .car stream on stdout.. +func (a *HttpApi) DagExport(ctx context.Context, root string, opts ...DagExportOption) (*Response, error) { + req := a.Request("dag/export", root) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// DagGetOption configures the dag/get command. +type DagGetOption func(RequestBuilder) + +// DagGetOutputCodec sets the output-codec option. +// Format that the object will be encoded as. Default: dag-json. +func DagGetOutputCodec(v string) DagGetOption { + return func(rb RequestBuilder) { rb.Option("output-codec", v) } +} + +// DagGet get a DAG node from IPFS.. +func (a *HttpApi) DagGet(ctx context.Context, ref string, opts ...DagGetOption) (*Response, error) { + req := a.Request("dag/get", ref) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// DagImportOption configures the dag/import command. +type DagImportOption func(RequestBuilder) + +// DagImportPinRoots sets the pin-roots option. +// Pin optional roots listed in the .car headers after importing. Default: true. +func DagImportPinRoots(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("pin-roots", v) } +} + +// DagImportSilent sets the silent option. +// No output. +func DagImportSilent(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("silent", v) } +} + +// DagImportStats sets the stats option. +// Output stats. +func DagImportStats(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("stats", v) } +} + +// DagImportFastProvideRoot sets the fast-provide-root option. +// Immediately provide root CIDs to DHT in addition to regular queue, for faster discovery. Default: Import.FastProvideRoot. +func DagImportFastProvideRoot(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("fast-provide-root", v) } +} + +// DagImportFastProvideWait sets the fast-provide-wait option. +// Block until the immediate provide completes before returning. Default: Import.FastProvideWait. +func DagImportFastProvideWait(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("fast-provide-wait", v) } +} + +// DagImportAllowBigBlock sets the allow-big-block option. +// Disable block size check and allow creation of blocks bigger than 2MiB. WARNING: such blocks won't be transferable over the standard bitswap. Default: false. +func DagImportAllowBigBlock(v bool) DagImportOption { + return func(rb RequestBuilder) { rb.Option("allow-big-block", v) } +} + +// DagImport import the contents of .car files. +func (a *HttpApi) DagImport(ctx context.Context, path io.Reader, opts ...DagImportOption) iter.Seq2[DagImportResponse, error] { + return func(yield func(DagImportResponse, error) bool) { + req := a.Request("dag/import") + req = req.FileBody(path).(RequestBuilder) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(DagImportResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(DagImportResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item DagImportResponse + if err := dec.Decode(&item); err != nil { + yield(DagImportResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// DagPutOption configures the dag/put command. +type DagPutOption func(RequestBuilder) + +// DagPutStoreCodec sets the store-codec option. +// Codec that the stored object will be encoded with. Default: dag-cbor. +func DagPutStoreCodec(v string) DagPutOption { + return func(rb RequestBuilder) { rb.Option("store-codec", v) } +} + +// DagPutInputCodec sets the input-codec option. +// Codec that the input object is encoded in. Default: dag-json. +func DagPutInputCodec(v string) DagPutOption { + return func(rb RequestBuilder) { rb.Option("input-codec", v) } +} + +// DagPutPin sets the pin option. +// Pin this object when adding. +func DagPutPin(v bool) DagPutOption { + return func(rb RequestBuilder) { rb.Option("pin", v) } +} + +// DagPutHash sets the hash option. +// Hash function to use. +func DagPutHash(v string) DagPutOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// DagPutAllowBigBlock sets the allow-big-block option. +// Disable block size check and allow creation of blocks bigger than 2MiB. WARNING: such blocks won't be transferable over the standard bitswap. Default: false. +func DagPutAllowBigBlock(v bool) DagPutOption { + return func(rb RequestBuilder) { rb.Option("allow-big-block", v) } +} + +// DagPut add a DAG node to IPFS.. +func (a *HttpApi) DagPut(ctx context.Context, object_data io.Reader, opts ...DagPutOption) (*DagPutResponse, error) { + req := a.Request("dag/put") + req = req.FileBody(object_data).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp DagPutResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// DagResolve resolve IPLD block.. +func (a *HttpApi) DagResolve(ctx context.Context, ref string) (*DagResolveResponse, error) { + req := a.Request("dag/resolve", ref) + var resp DagResolveResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// DagStatOption configures the dag/stat command. +type DagStatOption func(RequestBuilder) + +// DagStatProgress sets the progress option. +// Show progress on stderr. Auto-detected if stderr is a terminal. +func DagStatProgress(v bool) DagStatOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// DagStat gets stats for a DAG.. +func (a *HttpApi) DagStat(ctx context.Context, root []string, opts ...DagStatOption) (*DagStatResponse, error) { + req := a.Request("dag/stat").Arguments(root...) + for _, o := range opts { + o(req) + } + var resp DagStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_dht.go b/client/rpc/gen_dht.go new file mode 100644 index 00000000000..1b0ff8d6407 --- /dev/null +++ b/client/rpc/gen_dht.go @@ -0,0 +1,62 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type DhtQueryResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*DhtQueryResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type DhtQueryResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +// DhtQueryOption configures the dht/query command. +type DhtQueryOption func(RequestBuilder) + +// DhtQueryVerbose sets the verbose option. +// Print extra information. +func DhtQueryVerbose(v bool) DhtQueryOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// Deprecated: DhtQuery may be removed in a future release. +// DhtQuery find the closest Peer IDs to a given Peer ID by querying the DHT.. +func (a *HttpApi) DhtQuery(ctx context.Context, peerID []string, opts ...DhtQueryOption) iter.Seq2[DhtQueryResponse, error] { + return func(yield func(DhtQueryResponse, error) bool) { + req := a.Request("dht/query").Arguments(peerID...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(DhtQueryResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(DhtQueryResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item DhtQueryResponse + if err := dec.Decode(&item); err != nil { + yield(DhtQueryResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_diag.go b/client/rpc/gen_diag.go new file mode 100644 index 00000000000..3a8a1ac82b2 --- /dev/null +++ b/client/rpc/gen_diag.go @@ -0,0 +1,132 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" +) + +type DiagCmdsItem struct { + StartTime string `json:"StartTime,omitempty"` + EndTime string `json:"EndTime,omitempty"` + Active bool `json:"Active,omitempty"` + Command string `json:"Command,omitempty"` + Options map[string]json.RawMessage `json:"Options,omitempty"` + Args []string `json:"Args,omitempty"` + ID int `json:"ID,omitempty"` +} + +// DiagCmdsOption configures the diag/cmds command. +type DiagCmdsOption func(RequestBuilder) + +// DiagCmdsVerbose sets the verbose option. +// Print extra information. +func DiagCmdsVerbose(v bool) DiagCmdsOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// DiagCmds list commands run on this IPFS node.. +func (a *HttpApi) DiagCmds(ctx context.Context, opts ...DiagCmdsOption) ([]DiagCmdsItem, error) { + req := a.Request("diag/cmds") + for _, o := range opts { + o(req) + } + var resp []DiagCmdsItem + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return resp, nil +} + +// DiagCmdsClear clear inactive requests from the log.. +func (a *HttpApi) DiagCmdsClear(ctx context.Context) (*Response, error) { + req := a.Request("diag/cmds/clear") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// DiagCmdsSetTime set how long to keep inactive requests in the log.. +func (a *HttpApi) DiagCmdsSetTime(ctx context.Context, time string) (*Response, error) { + req := a.Request("diag/cmds/set-time", time) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// DiagProfileOption configures the diag/profile command. +type DiagProfileOption func(RequestBuilder) + +// DiagProfileOutput sets the output option. +// The path where the output .zip should be stored. Default: ./ipfs-profile-[timestamp].zip. +func DiagProfileOutput(v string) DiagProfileOption { + return func(rb RequestBuilder) { rb.Option("output", v) } +} + +// DiagProfileCollectors sets the collectors option. +// The list of collectors to use for collecting diagnostic data. Default: [goroutines-stack goroutines-pprof version heap allocs bin cpu mutex block trace]. +func DiagProfileCollectors(v []string) DiagProfileOption { + return func(rb RequestBuilder) { rb.Option("collectors", v) } +} + +// DiagProfileProfileTime sets the profile-time option. +// The amount of time spent profiling. If this is set to 0, then sampling profiles are skipped. Default: 30s. +func DiagProfileProfileTime(v string) DiagProfileOption { + return func(rb RequestBuilder) { rb.Option("profile-time", v) } +} + +// DiagProfileMutexProfileFraction sets the mutex-profile-fraction option. +// The fraction 1/n of mutex contention events that are reported in the mutex profile. Default: 4. +func DiagProfileMutexProfileFraction(v int) DiagProfileOption { + return func(rb RequestBuilder) { rb.Option("mutex-profile-fraction", v) } +} + +// DiagProfileBlockProfileRate sets the block-profile-rate option. +// The duration to wait between sampling goroutine-blocking events for the blocking profile. Default: 1ms. +func DiagProfileBlockProfileRate(v string) DiagProfileOption { + return func(rb RequestBuilder) { rb.Option("block-profile-rate", v) } +} + +// DiagProfile collect a performance profile for debugging.. +func (a *HttpApi) DiagProfile(ctx context.Context, opts ...DiagProfileOption) (*Response, error) { + req := a.Request("diag/profile") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// DiagSys print system diagnostic information.. +func (a *HttpApi) DiagSys(ctx context.Context) (*Response, error) { + req := a.Request("diag/sys") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_files.go b/client/rpc/gen_files.go new file mode 100644 index 00000000000..e46d69c9227 --- /dev/null +++ b/client/rpc/gen_files.go @@ -0,0 +1,412 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "io" +) + +type FilesFlushResponse struct { + Cid string `json:"Cid,omitempty"` +} + +type FilesLsResponse struct { + Entries []FilesLsResponseEntries `json:"Entries,omitempty"` +} + +type FilesLsResponseEntries struct { + Name string `json:"Name,omitempty"` + Type int `json:"Type,omitempty"` + Size int64 `json:"Size,omitempty"` + Hash string `json:"Hash,omitempty"` +} + +type FilesStatResponse struct { + Hash string `json:"Hash,omitempty"` + Size uint64 `json:"Size,omitempty"` + CumulativeSize uint64 `json:"CumulativeSize,omitempty"` + Blocks int `json:"Blocks,omitempty"` + Type string `json:"Type,omitempty"` + WithLocality bool `json:",omitempty"` + Local bool `json:",omitempty"` + SizeLocal uint64 `json:",omitempty"` + Mode uint32 `json:",omitempty"` + Mtime int64 `json:",omitempty"` + MtimeNsecs int `json:",omitempty"` +} + +// FilesChcidOption configures the files/chcid command. +type FilesChcidOption func(RequestBuilder) + +// FilesChcidCidVersion sets the cid-version option. +// Cid version to use. (experimental). +func FilesChcidCidVersion(v int) FilesChcidOption { + return func(rb RequestBuilder) { rb.Option("cid-version", v) } +} + +// FilesChcidHash sets the hash option. +// Hash function to use. Will set Cid version to 1 if used. (experimental). +func FilesChcidHash(v string) FilesChcidOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// FilesChcid change the CID version or hash function of the root node of a given path.. +func (a *HttpApi) FilesChcid(ctx context.Context, path string, opts ...FilesChcidOption) (*Response, error) { + req := a.Request("files/chcid", path) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// Experimental: FilesChmod is not yet stable. +// FilesChmod change optional POSIX mode permissions. +func (a *HttpApi) FilesChmod(ctx context.Context, mode string, path string) (*Response, error) { + req := a.Request("files/chmod", mode, path) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesCpOption configures the files/cp command. +type FilesCpOption func(RequestBuilder) + +// FilesCpForce sets the force option. +// Force overwrite of existing files. +func FilesCpForce(v bool) FilesCpOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// FilesCpParents sets the parents option. +// Make parent directories as needed. +func FilesCpParents(v bool) FilesCpOption { + return func(rb RequestBuilder) { rb.Option("parents", v) } +} + +// FilesCp add references to IPFS files and directories in MFS (or copy within MFS).. +func (a *HttpApi) FilesCp(ctx context.Context, source string, dest string, opts ...FilesCpOption) (*Response, error) { + req := a.Request("files/cp", source, dest) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesFlush flush a given path's data to disk.. +func (a *HttpApi) FilesFlush(ctx context.Context, path string) (*FilesFlushResponse, error) { + req := a.Request("files/flush", path) + var resp FilesFlushResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// FilesLsOption configures the files/ls command. +type FilesLsOption func(RequestBuilder) + +// FilesLsLong sets the long option. +// Use long listing format. +func FilesLsLong(v bool) FilesLsOption { + return func(rb RequestBuilder) { rb.Option("long", v) } +} + +// FilesLsU sets the U option. +// Do not sort; list entries in directory order. +func FilesLsU(v bool) FilesLsOption { + return func(rb RequestBuilder) { rb.Option("U", v) } +} + +// FilesLs list directories in the local mutable namespace.. +func (a *HttpApi) FilesLs(ctx context.Context, path string, opts ...FilesLsOption) (*FilesLsResponse, error) { + req := a.Request("files/ls", path) + for _, o := range opts { + o(req) + } + var resp FilesLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// FilesMkdirOption configures the files/mkdir command. +type FilesMkdirOption func(RequestBuilder) + +// FilesMkdirParents sets the parents option. +// No error if existing, make parent directories as needed. +func FilesMkdirParents(v bool) FilesMkdirOption { + return func(rb RequestBuilder) { rb.Option("parents", v) } +} + +// FilesMkdirCidVersion sets the cid-version option. +// Cid version to use. (experimental). +func FilesMkdirCidVersion(v int) FilesMkdirOption { + return func(rb RequestBuilder) { rb.Option("cid-version", v) } +} + +// FilesMkdirHash sets the hash option. +// Hash function to use. Will set Cid version to 1 if used. (experimental). +func FilesMkdirHash(v string) FilesMkdirOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// FilesMkdir make directories.. +func (a *HttpApi) FilesMkdir(ctx context.Context, path string, opts ...FilesMkdirOption) (*Response, error) { + req := a.Request("files/mkdir", path) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesMv move files.. +func (a *HttpApi) FilesMv(ctx context.Context, source string, dest string) (*Response, error) { + req := a.Request("files/mv", source, dest) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesReadOption configures the files/read command. +type FilesReadOption func(RequestBuilder) + +// FilesReadOffset sets the offset option. +// Byte offset to begin reading from. +func FilesReadOffset(v int64) FilesReadOption { + return func(rb RequestBuilder) { rb.Option("offset", v) } +} + +// FilesReadCount sets the count option. +// Maximum number of bytes to read. +func FilesReadCount(v int64) FilesReadOption { + return func(rb RequestBuilder) { rb.Option("count", v) } +} + +// FilesRead read a file from MFS.. +func (a *HttpApi) FilesRead(ctx context.Context, path string, opts ...FilesReadOption) (*Response, error) { + req := a.Request("files/read", path) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesRmOption configures the files/rm command. +type FilesRmOption func(RequestBuilder) + +// FilesRmRecursive sets the recursive option. +// Recursively remove directories. +func FilesRmRecursive(v bool) FilesRmOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// FilesRmForce sets the force option. +// Forcibly remove target at path; implies -r for directories. +func FilesRmForce(v bool) FilesRmOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// FilesRm remove a file from MFS.. +func (a *HttpApi) FilesRm(ctx context.Context, path []string, opts ...FilesRmOption) (*Response, error) { + req := a.Request("files/rm").Arguments(path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesStatOption configures the files/stat command. +type FilesStatOption func(RequestBuilder) + +// FilesStatFormat sets the format option. +// Print statistics in given format. Allowed tokens: and optional .Conflicts with other format options. Default: Size: CumulativeSize: ChildBlocks: Type: Mode: () Mtime: . +func FilesStatFormat(v string) FilesStatOption { + return func(rb RequestBuilder) { rb.Option("format", v) } +} + +// FilesStatHash sets the hash option. +// Print only hash. Implies '--format='. Conflicts with other format options. +func FilesStatHash(v bool) FilesStatOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// FilesStatSize sets the size option. +// Print only size. Implies '--format='. Conflicts with other format options. +func FilesStatSize(v bool) FilesStatOption { + return func(rb RequestBuilder) { rb.Option("size", v) } +} + +// FilesStatWithLocal sets the with-local option. +// Compute the amount of the dag that is local, and if possible the total size. +func FilesStatWithLocal(v bool) FilesStatOption { + return func(rb RequestBuilder) { rb.Option("with-local", v) } +} + +// FilesStat display file status.. +func (a *HttpApi) FilesStat(ctx context.Context, path string, opts ...FilesStatOption) (*FilesStatResponse, error) { + req := a.Request("files/stat", path) + for _, o := range opts { + o(req) + } + var resp FilesStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// FilesTouchOption configures the files/touch command. +type FilesTouchOption func(RequestBuilder) + +// FilesTouchMtime sets the mtime option. +// Modification time in seconds before or since the Unix Epoch to apply to created UnixFS entries. +func FilesTouchMtime(v int64) FilesTouchOption { + return func(rb RequestBuilder) { rb.Option("mtime", v) } +} + +// FilesTouchMtimeNsecs sets the mtime-nsecs option. +// Modification time fraction in nanoseconds. +func FilesTouchMtimeNsecs(v uint) FilesTouchOption { + return func(rb RequestBuilder) { rb.Option("mtime-nsecs", v) } +} + +// Experimental: FilesTouch is not yet stable. +// FilesTouch set or change optional POSIX modification times.. +func (a *HttpApi) FilesTouch(ctx context.Context, path string, opts ...FilesTouchOption) (*Response, error) { + req := a.Request("files/touch", path) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// FilesWriteOption configures the files/write command. +type FilesWriteOption func(RequestBuilder) + +// FilesWriteOffset sets the offset option. +// Byte offset to begin writing at. +func FilesWriteOffset(v int64) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("offset", v) } +} + +// FilesWriteCreate sets the create option. +// Create the file if it does not exist. +func FilesWriteCreate(v bool) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("create", v) } +} + +// FilesWriteParents sets the parents option. +// Make parent directories as needed. +func FilesWriteParents(v bool) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("parents", v) } +} + +// FilesWriteTruncate sets the truncate option. +// Truncate the file to size zero before writing. +func FilesWriteTruncate(v bool) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("truncate", v) } +} + +// FilesWriteCount sets the count option. +// Maximum number of bytes to read. +func FilesWriteCount(v int64) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("count", v) } +} + +// FilesWriteRawLeaves sets the raw-leaves option. +// Use raw blocks for newly created leaf nodes. (experimental). +func FilesWriteRawLeaves(v bool) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("raw-leaves", v) } +} + +// FilesWriteCidVersion sets the cid-version option. +// Cid version to use. (experimental). +func FilesWriteCidVersion(v int) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("cid-version", v) } +} + +// FilesWriteHash sets the hash option. +// Hash function to use. Will set Cid version to 1 if used. (experimental). +func FilesWriteHash(v string) FilesWriteOption { + return func(rb RequestBuilder) { rb.Option("hash", v) } +} + +// FilesWrite append to (modify) a file in MFS.. +func (a *HttpApi) FilesWrite(ctx context.Context, path string, data io.Reader, opts ...FilesWriteOption) (*Response, error) { + req := a.Request("files/write", path) + req = req.FileBody(data).(RequestBuilder) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_filestore.go b/client/rpc/gen_filestore.go new file mode 100644 index 00000000000..f2ed805dd12 --- /dev/null +++ b/client/rpc/gen_filestore.go @@ -0,0 +1,90 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type FilestoreDupsResponse struct { + Ref string `json:"Ref,omitempty"` + Err string `json:"Err,omitempty"` +} + +type FilestoreLsResponse struct { + Status int32 `json:"Status,omitempty"` + ErrorMsg string `json:"ErrorMsg,omitempty"` + Key string `json:"Key,omitempty"` + FilePath string `json:"FilePath,omitempty"` + Offset uint64 `json:"Offset,omitempty"` + Size uint64 `json:"Size,omitempty"` +} + +type FilestoreVerifyResponse struct { + Status int32 `json:"Status,omitempty"` + ErrorMsg string `json:"ErrorMsg,omitempty"` + Key string `json:"Key,omitempty"` + FilePath string `json:"FilePath,omitempty"` + Offset uint64 `json:"Offset,omitempty"` + Size uint64 `json:"Size,omitempty"` +} + +// FilestoreDups list blocks that are both in the filestore and standard block storage.. +func (a *HttpApi) FilestoreDups(ctx context.Context) (*FilestoreDupsResponse, error) { + req := a.Request("filestore/dups") + var resp FilestoreDupsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// FilestoreLsOption configures the filestore/ls command. +type FilestoreLsOption func(RequestBuilder) + +// FilestoreLsFileOrder sets the file-order option. +// sort the results based on the path of the backing file. +func FilestoreLsFileOrder(v bool) FilestoreLsOption { + return func(rb RequestBuilder) { rb.Option("file-order", v) } +} + +// FilestoreLs list objects in filestore.. +func (a *HttpApi) FilestoreLs(ctx context.Context, obj []string, opts ...FilestoreLsOption) (*FilestoreLsResponse, error) { + req := a.Request("filestore/ls").Arguments(obj...) + for _, o := range opts { + o(req) + } + var resp FilestoreLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// FilestoreVerifyOption configures the filestore/verify command. +type FilestoreVerifyOption func(RequestBuilder) + +// FilestoreVerifyFileOrder sets the file-order option. +// verify the objects based on the order of the backing file. +func FilestoreVerifyFileOrder(v bool) FilestoreVerifyOption { + return func(rb RequestBuilder) { rb.Option("file-order", v) } +} + +// FilestoreVerifyRemoveBadBlocks sets the remove-bad-blocks option. +// remove bad blocks. WARNING: This may remove pinned data. You should run 'ipfs pin verify' after running this command and correct any issues. +func FilestoreVerifyRemoveBadBlocks(v bool) FilestoreVerifyOption { + return func(rb RequestBuilder) { rb.Option("remove-bad-blocks", v) } +} + +// FilestoreVerify verify objects in filestore.. +func (a *HttpApi) FilestoreVerify(ctx context.Context, obj []string, opts ...FilestoreVerifyOption) (*FilestoreVerifyResponse, error) { + req := a.Request("filestore/verify").Arguments(obj...) + for _, o := range opts { + o(req) + } + var resp FilestoreVerifyResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_get.go b/client/rpc/gen_get.go new file mode 100644 index 00000000000..166dbca3cb2 --- /dev/null +++ b/client/rpc/gen_get.go @@ -0,0 +1,57 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +// GetOption configures the get command. +type GetOption func(RequestBuilder) + +// GetOutput sets the output option. +// The path where the output should be stored. +func GetOutput(v string) GetOption { + return func(rb RequestBuilder) { rb.Option("output", v) } +} + +// GetArchive sets the archive option. +// Output a TAR archive. +func GetArchive(v bool) GetOption { + return func(rb RequestBuilder) { rb.Option("archive", v) } +} + +// GetCompress sets the compress option. +// Compress the output with GZIP compression. +func GetCompress(v bool) GetOption { + return func(rb RequestBuilder) { rb.Option("compress", v) } +} + +// GetCompressionLevel sets the compression-level option. +// The level of compression (1-9). +func GetCompressionLevel(v int) GetOption { + return func(rb RequestBuilder) { rb.Option("compression-level", v) } +} + +// GetProgress sets the progress option. +// Stream progress data. Default: true. +func GetProgress(v bool) GetOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// Get download IPFS objects.. +func (a *HttpApi) Get(ctx context.Context, ipfs_path string, opts ...GetOption) (*Response, error) { + req := a.Request("get", ipfs_path) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_id.go b/client/rpc/gen_id.go new file mode 100644 index 00000000000..b9c7ed3ae48 --- /dev/null +++ b/client/rpc/gen_id.go @@ -0,0 +1,43 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type IdResponse struct { + ID string `json:"ID,omitempty"` + PublicKey string `json:"PublicKey,omitempty"` + Addresses []string `json:"Addresses,omitempty"` + AgentVersion string `json:"AgentVersion,omitempty"` + Protocols []string `json:"Protocols,omitempty"` +} + +// IdOption configures the id command. +type IdOption func(RequestBuilder) + +// IdFormat sets the format option. +// Optional output format. +func IdFormat(v string) IdOption { + return func(rb RequestBuilder) { rb.Option("format", v) } +} + +// IdPeeridBase sets the peerid-base option. +// Encoding used for peer IDs: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: b58mh. +func IdPeeridBase(v string) IdOption { + return func(rb RequestBuilder) { rb.Option("peerid-base", v) } +} + +// Id show IPFS node id info.. +func (a *HttpApi) Id(ctx context.Context, peerid string, opts ...IdOption) (*IdResponse, error) { + req := a.Request("id", peerid) + for _, o := range opts { + o(req) + } + var resp IdResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_key.go b/client/rpc/gen_key.go new file mode 100644 index 00000000000..e0c2d5b437e --- /dev/null +++ b/client/rpc/gen_key.go @@ -0,0 +1,320 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "io" +) + +type KeyGenResponse struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeyImportResponse struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeyListResponse struct { + Keys []KeyListResponseKeys `json:"Keys,omitempty"` +} + +type KeyListResponseKeys struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeyLsResponse struct { + Keys []KeyLsResponseKeys `json:"Keys,omitempty"` +} + +type KeyLsResponseKeys struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeyRenameResponse struct { + Was string `json:"Was,omitempty"` + Now string `json:"Now,omitempty"` + Id string `json:"Id,omitempty"` + Overwrite bool `json:"Overwrite,omitempty"` +} + +type KeyRmResponse struct { + Keys []KeyRmResponseKeys `json:"Keys,omitempty"` +} + +type KeyRmResponseKeys struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeySignResponse struct { + Key KeySignResponseKey `json:"Key,omitempty"` + Signature string `json:"Signature,omitempty"` +} + +type KeySignResponseKey struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +type KeyVerifyResponse struct { + Key KeyVerifyResponseKey `json:"Key,omitempty"` + SignatureValid bool `json:"SignatureValid,omitempty"` +} + +type KeyVerifyResponseKey struct { + Name string `json:"Name,omitempty"` + Id string `json:"Id,omitempty"` +} + +// KeyGenOption configures the key/gen command. +type KeyGenOption func(RequestBuilder) + +// KeyGenType sets the type option. +// type of the key to create: rsa, ed25519. Default: ed25519. +func KeyGenType(v string) KeyGenOption { + return func(rb RequestBuilder) { rb.Option("type", v) } +} + +// KeyGenSize sets the size option. +// size of the key to generate. +func KeyGenSize(v int) KeyGenOption { + return func(rb RequestBuilder) { rb.Option("size", v) } +} + +// KeyGenIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyGenIpnsBase(v string) KeyGenOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// KeyGen create a new keypair. +func (a *HttpApi) KeyGen(ctx context.Context, name string, opts ...KeyGenOption) (*KeyGenResponse, error) { + req := a.Request("key/gen", name) + for _, o := range opts { + o(req) + } + var resp KeyGenResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyImportOption configures the key/import command. +type KeyImportOption func(RequestBuilder) + +// KeyImportIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyImportIpnsBase(v string) KeyImportOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// KeyImportFormat sets the format option. +// The format of the private key to import, libp2p-protobuf-cleartext or pem-pkcs8-cleartext. Default: libp2p-protobuf-cleartext. +func KeyImportFormat(v string) KeyImportOption { + return func(rb RequestBuilder) { rb.Option("format", v) } +} + +// KeyImportAllowAnyKeyType sets the allow-any-key-type option. +// Allow importing any key type. Default: false. +func KeyImportAllowAnyKeyType(v bool) KeyImportOption { + return func(rb RequestBuilder) { rb.Option("allow-any-key-type", v) } +} + +// KeyImport import a key and prints imported key id. +func (a *HttpApi) KeyImport(ctx context.Context, name string, key io.Reader, opts ...KeyImportOption) (*KeyImportResponse, error) { + req := a.Request("key/import", name) + req = req.FileBody(key).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp KeyImportResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyListOption configures the key/list command. +type KeyListOption func(RequestBuilder) + +// KeyListL sets the l option. +// Show extra information about keys. +func KeyListL(v bool) KeyListOption { + return func(rb RequestBuilder) { rb.Option("l", v) } +} + +// KeyListIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyListIpnsBase(v string) KeyListOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// Deprecated: KeyList may be removed in a future release. +// KeyList deprecated: use 'ipfs key ls' instead.. +func (a *HttpApi) KeyList(ctx context.Context, opts ...KeyListOption) (*KeyListResponse, error) { + req := a.Request("key/list") + for _, o := range opts { + o(req) + } + var resp KeyListResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyLsOption configures the key/ls command. +type KeyLsOption func(RequestBuilder) + +// KeyLsL sets the l option. +// Show extra information about keys. +func KeyLsL(v bool) KeyLsOption { + return func(rb RequestBuilder) { rb.Option("l", v) } +} + +// KeyLsIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyLsIpnsBase(v string) KeyLsOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// KeyLs list all local keypairs.. +func (a *HttpApi) KeyLs(ctx context.Context, opts ...KeyLsOption) (*KeyLsResponse, error) { + req := a.Request("key/ls") + for _, o := range opts { + o(req) + } + var resp KeyLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyRenameOption configures the key/rename command. +type KeyRenameOption func(RequestBuilder) + +// KeyRenameForce sets the force option. +// Allow to overwrite an existing key. +func KeyRenameForce(v bool) KeyRenameOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// KeyRenameIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyRenameIpnsBase(v string) KeyRenameOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// KeyRename rename a keypair.. +func (a *HttpApi) KeyRename(ctx context.Context, name string, newName string, opts ...KeyRenameOption) (*KeyRenameResponse, error) { + req := a.Request("key/rename", name, newName) + for _, o := range opts { + o(req) + } + var resp KeyRenameResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyRmOption configures the key/rm command. +type KeyRmOption func(RequestBuilder) + +// KeyRmL sets the l option. +// Show extra information about keys. +func KeyRmL(v bool) KeyRmOption { + return func(rb RequestBuilder) { rb.Option("l", v) } +} + +// KeyRmIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyRmIpnsBase(v string) KeyRmOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// KeyRm remove a keypair.. +func (a *HttpApi) KeyRm(ctx context.Context, name []string, opts ...KeyRmOption) (*KeyRmResponse, error) { + req := a.Request("key/rm").Arguments(name...) + for _, o := range opts { + o(req) + } + var resp KeyRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeySignOption configures the key/sign command. +type KeySignOption func(RequestBuilder) + +// KeySignKey sets the key option. +// The name of the key to use for signing. +func KeySignKey(v string) KeySignOption { + return func(rb RequestBuilder) { rb.Option("key", v) } +} + +// KeySignIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeySignIpnsBase(v string) KeySignOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// Experimental: KeySign is not yet stable. +// KeySign generates a signature for the given data with a specified key. Useful for proving the key ownership.. +func (a *HttpApi) KeySign(ctx context.Context, data io.Reader, opts ...KeySignOption) (*KeySignResponse, error) { + req := a.Request("key/sign") + req = req.FileBody(data).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp KeySignResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// KeyVerifyOption configures the key/verify command. +type KeyVerifyOption func(RequestBuilder) + +// KeyVerifyKey sets the key option. +// The name of the key to use for verifying. +func KeyVerifyKey(v string) KeyVerifyOption { + return func(rb RequestBuilder) { rb.Option("key", v) } +} + +// KeyVerifySignature sets the signature option. +// Multibase-encoded signature to verify. +func KeyVerifySignature(v string) KeyVerifyOption { + return func(rb RequestBuilder) { rb.Option("signature", v) } +} + +// KeyVerifyIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func KeyVerifyIpnsBase(v string) KeyVerifyOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// Experimental: KeyVerify is not yet stable. +// KeyVerify verify that the given data and signature match.. +func (a *HttpApi) KeyVerify(ctx context.Context, data io.Reader, opts ...KeyVerifyOption) (*KeyVerifyResponse, error) { + req := a.Request("key/verify") + req = req.FileBody(data).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp KeyVerifyResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_log.go b/client/rpc/gen_log.go new file mode 100644 index 00000000000..8c7bf415209 --- /dev/null +++ b/client/rpc/gen_log.go @@ -0,0 +1,79 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type LogLevelResponse struct { + Levels map[string]string `json:",omitempty"` + Message string `json:",omitempty"` +} + +type LogLsResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +// LogLevel change or get the logging level.. +func (a *HttpApi) LogLevel(ctx context.Context, subsystem string, level string) (*LogLevelResponse, error) { + req := a.Request("log/level", subsystem, level) + var resp LogLevelResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// LogLs list the logging subsystems.. +func (a *HttpApi) LogLs(ctx context.Context) (*LogLsResponse, error) { + req := a.Request("log/ls") + var resp LogLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// LogTailOption configures the log/tail command. +type LogTailOption func(RequestBuilder) + +// LogTailLogLevel sets the log-level option. +// Log level to listen to. Default: . +func LogTailLogLevel(v string) LogTailOption { + return func(rb RequestBuilder) { rb.Option("log-level", v) } +} + +// Experimental: LogTail is not yet stable. +// LogTail read and output log messages.. +func (a *HttpApi) LogTail(ctx context.Context, opts ...LogTailOption) iter.Seq2[json.RawMessage, error] { + return func(yield func(json.RawMessage, error) bool) { + req := a.Request("log/tail") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(nil, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(nil, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item json.RawMessage + if err := dec.Decode(&item); err != nil { + yield(nil, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_ls.go b/client/rpc/gen_ls.go new file mode 100644 index 00000000000..2bc343c23e6 --- /dev/null +++ b/client/rpc/gen_ls.go @@ -0,0 +1,92 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type LsResponse struct { + Objects []LsResponseObjects `json:"Objects,omitempty"` +} + +type LsResponseObjects struct { + Hash string `json:"Hash,omitempty"` + Links []LsResponseObjectsLinks `json:"Links,omitempty"` +} + +type LsResponseObjectsLinks struct { + Name string `json:"Name,omitempty"` + Hash string `json:"Hash,omitempty"` + Size uint64 `json:"Size,omitempty"` + Type int32 `json:"Type,omitempty"` + Target string `json:"Target,omitempty"` + Mode uint32 `json:"Mode,omitempty"` + ModTime string `json:"ModTime,omitempty"` +} + +// LsOption configures the ls command. +type LsOption func(RequestBuilder) + +// LsHeaders sets the headers option. +// Print table headers (Hash, Size, Name). +func LsHeaders(v bool) LsOption { + return func(rb RequestBuilder) { rb.Option("headers", v) } +} + +// LsResolveType sets the resolve-type option. +// Resolve linked objects to find out their types. Default: true. +func LsResolveType(v bool) LsOption { + return func(rb RequestBuilder) { rb.Option("resolve-type", v) } +} + +// LsSize sets the size option. +// Resolve linked objects to find out their file size. Default: true. +func LsSize(v bool) LsOption { + return func(rb RequestBuilder) { rb.Option("size", v) } +} + +// LsStream sets the stream option. +// Enable experimental streaming of directory entries as they are traversed. +func LsStream(v bool) LsOption { + return func(rb RequestBuilder) { rb.Option("stream", v) } +} + +// LsLong sets the long option. +// Use a long listing format, showing file mode and modification time. +func LsLong(v bool) LsOption { + return func(rb RequestBuilder) { rb.Option("long", v) } +} + +// Ls list directory contents for Unix filesystem objects.. +func (a *HttpApi) Ls(ctx context.Context, ipfs_path []string, opts ...LsOption) iter.Seq2[LsResponse, error] { + return func(yield func(LsResponse, error) bool) { + req := a.Request("ls").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(LsResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(LsResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item LsResponse + if err := dec.Decode(&item); err != nil { + yield(LsResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_mount.go b/client/rpc/gen_mount.go new file mode 100644 index 00000000000..e162cf1203a --- /dev/null +++ b/client/rpc/gen_mount.go @@ -0,0 +1,49 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type MountResponse struct { + IPFS string `json:"IPFS,omitempty"` + IPNS string `json:"IPNS,omitempty"` + MFS string `json:"MFS,omitempty"` + FuseAllowOther bool `json:"FuseAllowOther,omitempty"` +} + +// MountOption configures the mount command. +type MountOption func(RequestBuilder) + +// MountIpfsPath sets the ipfs-path option. +// The path where IPFS should be mounted. +func MountIpfsPath(v string) MountOption { + return func(rb RequestBuilder) { rb.Option("ipfs-path", v) } +} + +// MountIpnsPath sets the ipns-path option. +// The path where IPNS should be mounted. +func MountIpnsPath(v string) MountOption { + return func(rb RequestBuilder) { rb.Option("ipns-path", v) } +} + +// MountMfsPath sets the mfs-path option. +// The path where MFS should be mounted. +func MountMfsPath(v string) MountOption { + return func(rb RequestBuilder) { rb.Option("mfs-path", v) } +} + +// Experimental: Mount is not yet stable. +// Mount mounts IPFS to the filesystem (read-only).. +func (a *HttpApi) Mount(ctx context.Context, opts ...MountOption) (*MountResponse, error) { + req := a.Request("mount") + for _, o := range opts { + o(req) + } + var resp MountResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_multibase.go b/client/rpc/gen_multibase.go new file mode 100644 index 00000000000..10f69e94c02 --- /dev/null +++ b/client/rpc/gen_multibase.go @@ -0,0 +1,110 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "io" +) + +type MultibaseListItem struct { + Code int `json:"Code,omitempty"` + Name string `json:"Name,omitempty"` +} + +// MultibaseDecode decode multibase string. +func (a *HttpApi) MultibaseDecode(ctx context.Context, encoded_file io.Reader) (*Response, error) { + req := a.Request("multibase/decode") + req = req.FileBody(encoded_file).(RequestBuilder) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// MultibaseEncodeOption configures the multibase/encode command. +type MultibaseEncodeOption func(RequestBuilder) + +// MultibaseEncodeB sets the b option. +// multibase encoding. Default: base64url. +func MultibaseEncodeB(v string) MultibaseEncodeOption { + return func(rb RequestBuilder) { rb.Option("b", v) } +} + +// MultibaseEncode encode data into multibase string. +func (a *HttpApi) MultibaseEncode(ctx context.Context, file io.Reader, opts ...MultibaseEncodeOption) (*Response, error) { + req := a.Request("multibase/encode") + req = req.FileBody(file).(RequestBuilder) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// MultibaseListOption configures the multibase/list command. +type MultibaseListOption func(RequestBuilder) + +// MultibaseListPrefix sets the prefix option. +// also include the single letter prefixes in addition to the code. +func MultibaseListPrefix(v bool) MultibaseListOption { + return func(rb RequestBuilder) { rb.Option("prefix", v) } +} + +// MultibaseListNumeric sets the numeric option. +// also include numeric codes. +func MultibaseListNumeric(v bool) MultibaseListOption { + return func(rb RequestBuilder) { rb.Option("numeric", v) } +} + +// MultibaseList list available multibase encodings.. +func (a *HttpApi) MultibaseList(ctx context.Context, opts ...MultibaseListOption) ([]MultibaseListItem, error) { + req := a.Request("multibase/list") + for _, o := range opts { + o(req) + } + var resp []MultibaseListItem + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return resp, nil +} + +// MultibaseTranscodeOption configures the multibase/transcode command. +type MultibaseTranscodeOption func(RequestBuilder) + +// MultibaseTranscodeB sets the b option. +// multibase encoding. Default: base64url. +func MultibaseTranscodeB(v string) MultibaseTranscodeOption { + return func(rb RequestBuilder) { rb.Option("b", v) } +} + +// MultibaseTranscode transcode multibase string between bases. +func (a *HttpApi) MultibaseTranscode(ctx context.Context, encoded_file io.Reader, opts ...MultibaseTranscodeOption) (*Response, error) { + req := a.Request("multibase/transcode") + req = req.FileBody(encoded_file).(RequestBuilder) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_name.go b/client/rpc/gen_name.go new file mode 100644 index 00000000000..20a7f6aca85 --- /dev/null +++ b/client/rpc/gen_name.go @@ -0,0 +1,310 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "io" +) + +type NameInspectResponse struct { + Entry NameInspectResponseEntry `json:"Entry,omitempty"` + PbSize int `json:"PbSize,omitempty"` + SignatureType string `json:"SignatureType,omitempty"` + HexDump string `json:"HexDump,omitempty"` + Validation *NameInspectResponseValidation `json:"Validation,omitempty"` +} + +type NameInspectResponseEntry struct { + Value string `json:"Value,omitempty"` + ValidityType *int64 `json:"ValidityType,omitempty"` + Validity *string `json:"Validity,omitempty"` + Sequence *uint64 `json:"Sequence,omitempty"` + TTL *string `json:"TTL,omitempty"` +} + +type NameInspectResponseValidation struct { + Valid bool `json:"Valid,omitempty"` + Reason string `json:"Reason,omitempty"` + Name string `json:"Name,omitempty"` +} + +type NamePublishResponse struct { + Name string `json:"Name,omitempty"` + Value string `json:"Value,omitempty"` +} + +type NamePubsubCancelResponse struct { + Canceled bool `json:"Canceled,omitempty"` +} + +type NamePubsubStateResponse struct { + Enabled bool `json:"Enabled,omitempty"` +} + +type NamePubsubSubsResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type NamePutResponse struct { + Name string `json:"Name,omitempty"` + Value string `json:"Value,omitempty"` +} + +type NameResolveResponse struct { + Path string `json:"Path,omitempty"` +} + +// Experimental: NameGet is not yet stable. +// NameGet retrieve a signed IPNS record.. +func (a *HttpApi) NameGet(ctx context.Context, name string) (*Response, error) { + req := a.Request("name/get", name) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// NameInspectOption configures the name/inspect command. +type NameInspectOption func(RequestBuilder) + +// NameInspectVerify sets the verify option. +// CID of the public IPNS key to validate against. +func NameInspectVerify(v string) NameInspectOption { + return func(rb RequestBuilder) { rb.Option("verify", v) } +} + +// NameInspectDump sets the dump option. +// Include a full hex dump of the raw Protobuf record. Default: true. +func NameInspectDump(v bool) NameInspectOption { + return func(rb RequestBuilder) { rb.Option("dump", v) } +} + +// Experimental: NameInspect is not yet stable. +// NameInspect inspects an IPNS Record. +func (a *HttpApi) NameInspect(ctx context.Context, record io.Reader, opts ...NameInspectOption) (*NameInspectResponse, error) { + req := a.Request("name/inspect") + req = req.FileBody(record).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp NameInspectResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// NamePublishOption configures the name/publish command. +type NamePublishOption func(RequestBuilder) + +// NamePublishKey sets the key option. +// Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: self. +func NamePublishKey(v string) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("key", v) } +} + +// NamePublishResolve sets the resolve option. +// Check if the given path can be resolved before publishing. Default: true. +func NamePublishResolve(v bool) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("resolve", v) } +} + +// NamePublishLifetime sets the lifetime option. +// Time duration the signed record will be valid for. Accepts durations such as "300s", "1.5h" or "7d2h45m". Default: 48h0m0s. +func NamePublishLifetime(v string) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("lifetime", v) } +} + +// NamePublishTtl sets the ttl option. +// Time duration hint, akin to --lifetime, indicating how long to cache this record before checking for updates. Default: 5m0s. +func NamePublishTtl(v string) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("ttl", v) } +} + +// NamePublishQuieter sets the quieter option. +// Write only final IPNS Name encoded as CIDv1 (for use in /ipns content paths). +func NamePublishQuieter(v bool) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("quieter", v) } +} + +// NamePublishV1compat sets the v1compat option. +// Produce a backward-compatible IPNS Record by including fields for both V1 and V2 signatures. Default: true. +func NamePublishV1compat(v bool) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("v1compat", v) } +} + +// NamePublishAllowOffline sets the allow-offline option. +// Allow publishing when offline - publishes to local datastore without requiring network connectivity. +func NamePublishAllowOffline(v bool) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("allow-offline", v) } +} + +// NamePublishAllowDelegated sets the allow-delegated option. +// Allow publishing without DHT connectivity - uses local datastore and HTTP delegated publishers only. +func NamePublishAllowDelegated(v bool) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("allow-delegated", v) } +} + +// NamePublishSequence sets the sequence option. +// Set a custom sequence number for the IPNS record (must be higher than current). +func NamePublishSequence(v uint64) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("sequence", v) } +} + +// NamePublishIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func NamePublishIpnsBase(v string) NamePublishOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// NamePublish publish IPNS names.. +func (a *HttpApi) NamePublish(ctx context.Context, ipfs_path string, opts ...NamePublishOption) (*NamePublishResponse, error) { + req := a.Request("name/publish", ipfs_path) + for _, o := range opts { + o(req) + } + var resp NamePublishResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: NamePubsubCancel is not yet stable. +// NamePubsubCancel cancel a name subscription.. +func (a *HttpApi) NamePubsubCancel(ctx context.Context, name string) (*NamePubsubCancelResponse, error) { + req := a.Request("name/pubsub/cancel", name) + var resp NamePubsubCancelResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: NamePubsubState is not yet stable. +// NamePubsubState query the state of IPNS pubsub.. +func (a *HttpApi) NamePubsubState(ctx context.Context) (*NamePubsubStateResponse, error) { + req := a.Request("name/pubsub/state") + var resp NamePubsubStateResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// NamePubsubSubsOption configures the name/pubsub/subs command. +type NamePubsubSubsOption func(RequestBuilder) + +// NamePubsubSubsIpnsBase sets the ipns-base option. +// Encoding used for keys: Can either be a multibase encoded CID or a base58btc encoded multihash. Takes {b58mh|base36|k|base32|b...}. Default: base36. +func NamePubsubSubsIpnsBase(v string) NamePubsubSubsOption { + return func(rb RequestBuilder) { rb.Option("ipns-base", v) } +} + +// Experimental: NamePubsubSubs is not yet stable. +// NamePubsubSubs show current name subscriptions.. +func (a *HttpApi) NamePubsubSubs(ctx context.Context, opts ...NamePubsubSubsOption) (*NamePubsubSubsResponse, error) { + req := a.Request("name/pubsub/subs") + for _, o := range opts { + o(req) + } + var resp NamePubsubSubsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// NamePutOption configures the name/put command. +type NamePutOption func(RequestBuilder) + +// NamePutForce sets the force option. +// Skip validation (signature, sequence, size). +func NamePutForce(v bool) NamePutOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// NamePutAllowOffline sets the allow-offline option. +// Store locally without broadcasting to the network. +func NamePutAllowOffline(v bool) NamePutOption { + return func(rb RequestBuilder) { rb.Option("allow-offline", v) } +} + +// NamePutAllowDelegated sets the allow-delegated option. +// Publish via HTTP delegated publishers only (no DHT). +func NamePutAllowDelegated(v bool) NamePutOption { + return func(rb RequestBuilder) { rb.Option("allow-delegated", v) } +} + +// NamePutQuiet sets the quiet option. +// Write no output. +func NamePutQuiet(v bool) NamePutOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// Experimental: NamePut is not yet stable. +// NamePut store a pre-signed IPNS record in the routing system.. +func (a *HttpApi) NamePut(ctx context.Context, name string, record io.Reader, opts ...NamePutOption) (*NamePutResponse, error) { + req := a.Request("name/put", name) + req = req.FileBody(record).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp NamePutResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// NameResolveOption configures the name/resolve command. +type NameResolveOption func(RequestBuilder) + +// NameResolveRecursive sets the recursive option. +// Resolve until the result is not an IPNS name. Default: true. +func NameResolveRecursive(v bool) NameResolveOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// NameResolveNocache sets the nocache option. +// Do not use cached entries. +func NameResolveNocache(v bool) NameResolveOption { + return func(rb RequestBuilder) { rb.Option("nocache", v) } +} + +// NameResolveDhtRecordCount sets the dht-record-count option. +// Number of records to request for DHT resolution. Default: 16. +func NameResolveDhtRecordCount(v uint) NameResolveOption { + return func(rb RequestBuilder) { rb.Option("dht-record-count", v) } +} + +// NameResolveDhtTimeout sets the dht-timeout option. +// Max time to collect values during DHT resolution e.g. "30s". Pass 0 for no timeout. Default: 1m0s. +func NameResolveDhtTimeout(v string) NameResolveOption { + return func(rb RequestBuilder) { rb.Option("dht-timeout", v) } +} + +// NameResolveStream sets the stream option. +// Stream entries as they are found. +func NameResolveStream(v bool) NameResolveOption { + return func(rb RequestBuilder) { rb.Option("stream", v) } +} + +// NameResolve resolve IPNS names.. +func (a *HttpApi) NameResolve(ctx context.Context, name string, opts ...NameResolveOption) (*NameResolveResponse, error) { + req := a.Request("name/resolve", name) + for _, o := range opts { + o(req) + } + var resp NameResolveResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_object.go b/client/rpc/gen_object.go new file mode 100644 index 00000000000..e65539c14dc --- /dev/null +++ b/client/rpc/gen_object.go @@ -0,0 +1,97 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type ObjectDiffResponse struct { + Changes []*ObjectDiffResponseChanges `json:"Changes,omitempty"` +} + +type ObjectDiffResponseChanges struct { + Type int `json:"Type,omitempty"` + Path string `json:"Path,omitempty"` + Before string `json:"Before,omitempty"` + After string `json:"After,omitempty"` +} + +type ObjectPatchAddLinkResponse struct { + Hash string `json:"Hash,omitempty"` + Links []ObjectPatchAddLinkResponseLinks `json:"Links,omitempty"` +} + +type ObjectPatchAddLinkResponseLinks struct { + Name string `json:"Name,omitempty"` + Hash string `json:"Hash,omitempty"` + Size uint64 `json:"Size,omitempty"` +} + +type ObjectPatchRmLinkResponse struct { + Hash string `json:"Hash,omitempty"` + Links []ObjectPatchRmLinkResponseLinks `json:"Links,omitempty"` +} + +type ObjectPatchRmLinkResponseLinks struct { + Name string `json:"Name,omitempty"` + Hash string `json:"Hash,omitempty"` + Size uint64 `json:"Size,omitempty"` +} + +// ObjectDiffOption configures the object/diff command. +type ObjectDiffOption func(RequestBuilder) + +// ObjectDiffVerbose sets the verbose option. +// Print extra information. +func ObjectDiffVerbose(v bool) ObjectDiffOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// Deprecated: ObjectDiff may be removed in a future release. +// ObjectDiff display the diff between two IPFS objects.. +func (a *HttpApi) ObjectDiff(ctx context.Context, obj_a string, obj_b string, opts ...ObjectDiffOption) (*ObjectDiffResponse, error) { + req := a.Request("object/diff", obj_a, obj_b) + for _, o := range opts { + o(req) + } + var resp ObjectDiffResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// ObjectPatchAddLinkOption configures the object/patch/add-link command. +type ObjectPatchAddLinkOption func(RequestBuilder) + +// ObjectPatchAddLinkCreate sets the create option. +// Create intermediary nodes. +func ObjectPatchAddLinkCreate(v bool) ObjectPatchAddLinkOption { + return func(rb RequestBuilder) { rb.Option("create", v) } +} + +// Deprecated: ObjectPatchAddLink may be removed in a future release. +// ObjectPatchAddLink deprecated way to add a link to a given dag-pb.. +func (a *HttpApi) ObjectPatchAddLink(ctx context.Context, root string, name string, ref string, opts ...ObjectPatchAddLinkOption) (*ObjectPatchAddLinkResponse, error) { + req := a.Request("object/patch/add-link", root, name, ref) + for _, o := range opts { + o(req) + } + var resp ObjectPatchAddLinkResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Deprecated: ObjectPatchRmLink may be removed in a future release. +// ObjectPatchRmLink deprecated way to remove a link from dag-pb object.. +func (a *HttpApi) ObjectPatchRmLink(ctx context.Context, root string, name string) (*ObjectPatchRmLinkResponse, error) { + req := a.Request("object/patch/rm-link", root, name) + var resp ObjectPatchRmLinkResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_p2p.go b/client/rpc/gen_p2p.go new file mode 100644 index 00000000000..56faf0e34b8 --- /dev/null +++ b/client/rpc/gen_p2p.go @@ -0,0 +1,222 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type P2pForwardResponse struct { + Status string `json:"Status,omitempty"` + Protocol string `json:"Protocol,omitempty"` + Address string `json:"Address,omitempty"` +} + +type P2pListenResponse struct { + Status string `json:"Status,omitempty"` + Protocol string `json:"Protocol,omitempty"` + Address string `json:"Address,omitempty"` +} + +type P2pLsResponse struct { + Listeners []P2pLsResponseListeners `json:"Listeners,omitempty"` +} + +type P2pLsResponseListeners struct { + Protocol string `json:"Protocol,omitempty"` + ListenAddress string `json:"ListenAddress,omitempty"` + TargetAddress string `json:"TargetAddress,omitempty"` +} + +type P2pStreamLsResponse struct { + Streams []P2pStreamLsResponseStreams `json:"Streams,omitempty"` +} + +type P2pStreamLsResponseStreams struct { + HandlerID string `json:"HandlerID,omitempty"` + Protocol string `json:"Protocol,omitempty"` + OriginAddress string `json:"OriginAddress,omitempty"` + TargetAddress string `json:"TargetAddress,omitempty"` +} + +// P2pCloseOption configures the p2p/close command. +type P2pCloseOption func(RequestBuilder) + +// P2pCloseAll sets the all option. +// Close all listeners. +func P2pCloseAll(v bool) P2pCloseOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// P2pCloseProtocol sets the protocol option. +// Match protocol name. +func P2pCloseProtocol(v string) P2pCloseOption { + return func(rb RequestBuilder) { rb.Option("protocol", v) } +} + +// P2pCloseListenAddress sets the listen-address option. +// Match listen address. +func P2pCloseListenAddress(v string) P2pCloseOption { + return func(rb RequestBuilder) { rb.Option("listen-address", v) } +} + +// P2pCloseTargetAddress sets the target-address option. +// Match target address. +func P2pCloseTargetAddress(v string) P2pCloseOption { + return func(rb RequestBuilder) { rb.Option("target-address", v) } +} + +// Experimental: P2pClose is not yet stable. +// P2pClose stop listening for new connections to forward.. +func (a *HttpApi) P2pClose(ctx context.Context, opts ...P2pCloseOption) (*Response, error) { + req := a.Request("p2p/close") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// P2pForwardOption configures the p2p/forward command. +type P2pForwardOption func(RequestBuilder) + +// P2pForwardAllowCustomProtocol sets the allow-custom-protocol option. +// Don't require /x/ prefix. +func P2pForwardAllowCustomProtocol(v bool) P2pForwardOption { + return func(rb RequestBuilder) { rb.Option("allow-custom-protocol", v) } +} + +// P2pForwardForeground sets the foreground option. +// Run in foreground; forwarder is removed when command exits. +func P2pForwardForeground(v bool) P2pForwardOption { + return func(rb RequestBuilder) { rb.Option("foreground", v) } +} + +// Experimental: P2pForward is not yet stable. +// P2pForward forward connections to libp2p service.. +func (a *HttpApi) P2pForward(ctx context.Context, protocol string, listen_address string, target_address string, opts ...P2pForwardOption) (*P2pForwardResponse, error) { + req := a.Request("p2p/forward", protocol, listen_address, target_address) + for _, o := range opts { + o(req) + } + var resp P2pForwardResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// P2pListenOption configures the p2p/listen command. +type P2pListenOption func(RequestBuilder) + +// P2pListenAllowCustomProtocol sets the allow-custom-protocol option. +// Don't require /x/ prefix. +func P2pListenAllowCustomProtocol(v bool) P2pListenOption { + return func(rb RequestBuilder) { rb.Option("allow-custom-protocol", v) } +} + +// P2pListenReportPeerId sets the report-peer-id option. +// Send remote base58 peerid to target when a new connection is established. +func P2pListenReportPeerId(v bool) P2pListenOption { + return func(rb RequestBuilder) { rb.Option("report-peer-id", v) } +} + +// P2pListenForeground sets the foreground option. +// Run in foreground; listener is removed when command exits. +func P2pListenForeground(v bool) P2pListenOption { + return func(rb RequestBuilder) { rb.Option("foreground", v) } +} + +// Experimental: P2pListen is not yet stable. +// P2pListen create libp2p service.. +func (a *HttpApi) P2pListen(ctx context.Context, protocol string, target_address string, opts ...P2pListenOption) (*P2pListenResponse, error) { + req := a.Request("p2p/listen", protocol, target_address) + for _, o := range opts { + o(req) + } + var resp P2pListenResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// P2pLsOption configures the p2p/ls command. +type P2pLsOption func(RequestBuilder) + +// P2pLsHeaders sets the headers option. +// Print table headers (Protocol, Listen, Target). +func P2pLsHeaders(v bool) P2pLsOption { + return func(rb RequestBuilder) { rb.Option("headers", v) } +} + +// Experimental: P2pLs is not yet stable. +// P2pLs list active p2p listeners.. +func (a *HttpApi) P2pLs(ctx context.Context, opts ...P2pLsOption) (*P2pLsResponse, error) { + req := a.Request("p2p/ls") + for _, o := range opts { + o(req) + } + var resp P2pLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// P2pStreamCloseOption configures the p2p/stream/close command. +type P2pStreamCloseOption func(RequestBuilder) + +// P2pStreamCloseAll sets the all option. +// Close all streams. +func P2pStreamCloseAll(v bool) P2pStreamCloseOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// Experimental: P2pStreamClose is not yet stable. +// P2pStreamClose close active p2p stream.. +func (a *HttpApi) P2pStreamClose(ctx context.Context, id string, opts ...P2pStreamCloseOption) (*Response, error) { + req := a.Request("p2p/stream/close", id) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// P2pStreamLsOption configures the p2p/stream/ls command. +type P2pStreamLsOption func(RequestBuilder) + +// P2pStreamLsHeaders sets the headers option. +// Print table headers (ID, Protocol, Local, Remote). +func P2pStreamLsHeaders(v bool) P2pStreamLsOption { + return func(rb RequestBuilder) { rb.Option("headers", v) } +} + +// Experimental: P2pStreamLs is not yet stable. +// P2pStreamLs list active p2p streams.. +func (a *HttpApi) P2pStreamLs(ctx context.Context, opts ...P2pStreamLsOption) (*P2pStreamLsResponse, error) { + req := a.Request("p2p/stream/ls") + for _, o := range opts { + o(req) + } + var resp P2pStreamLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_pin.go b/client/rpc/gen_pin.go new file mode 100644 index 00000000000..16f7170e93e --- /dev/null +++ b/client/rpc/gen_pin.go @@ -0,0 +1,461 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type PinAddResponse struct { + Pins []string `json:",omitempty"` + Progress int `json:",omitempty"` + Bytes uint64 `json:",omitempty"` +} + +type PinLsResponse struct { + Keys map[string]PinLsResponseKeysVal `json:",omitempty"` + Cid string `json:",omitempty"` + Name string `json:",omitempty"` + Type string `json:",omitempty"` +} + +type PinLsResponseKeysVal struct { + Type string `json:"Type,omitempty"` + Name string `json:"Name,omitempty"` +} + +type PinRemoteAddResponse struct { + Status string `json:"Status,omitempty"` + Cid string `json:"Cid,omitempty"` + Name string `json:"Name,omitempty"` +} + +type PinRemoteLsResponse struct { + Status string `json:"Status,omitempty"` + Cid string `json:"Cid,omitempty"` + Name string `json:"Name,omitempty"` +} + +type PinRemoteServiceLsResponse struct { + RemoteServices []PinRemoteServiceLsResponseRemoteServices `json:"RemoteServices,omitempty"` +} + +type PinRemoteServiceLsResponseRemoteServices struct { + Service string `json:"Service,omitempty"` + ApiEndpoint string `json:"ApiEndpoint,omitempty"` + Stat *PinRemoteServiceLsResponseRemoteServicesStat `json:",omitempty"` +} + +type PinRemoteServiceLsResponseRemoteServicesStat struct { + Status string `json:"Status,omitempty"` + PinCount *PinRemoteServiceLsResponseRemoteServicesStatPinCount `json:",omitempty"` +} + +type PinRemoteServiceLsResponseRemoteServicesStatPinCount struct { + Queued int `json:"Queued,omitempty"` + Pinning int `json:"Pinning,omitempty"` + Pinned int `json:"Pinned,omitempty"` + Failed int `json:"Failed,omitempty"` +} + +type PinRmResponse struct { + Pins []string `json:"Pins,omitempty"` +} + +type PinUpdateResponse struct { + Pins []string `json:"Pins,omitempty"` +} + +type PinVerifyResponse struct { + Cid string `json:",omitempty"` + Err string `json:",omitempty"` + Ok bool `json:",omitempty"` + BadNodes []PinVerifyResponseBadNodes `json:",omitempty"` +} + +type PinVerifyResponseBadNodes struct { + Cid string `json:"Cid,omitempty"` + Err string `json:"Err,omitempty"` +} + +// PinAddOption configures the pin/add command. +type PinAddOption func(RequestBuilder) + +// PinAddRecursive sets the recursive option. +// Recursively pin the object linked to by the specified object(s). Default: true. +func PinAddRecursive(v bool) PinAddOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// PinAddName sets the name option. +// An optional name for created pin(s). +func PinAddName(v string) PinAddOption { + return func(rb RequestBuilder) { rb.Option("name", v) } +} + +// PinAddProgress sets the progress option. +// Show progress. +func PinAddProgress(v bool) PinAddOption { + return func(rb RequestBuilder) { rb.Option("progress", v) } +} + +// PinAdd pin objects to local storage.. +func (a *HttpApi) PinAdd(ctx context.Context, ipfs_path []string, opts ...PinAddOption) iter.Seq2[PinAddResponse, error] { + return func(yield func(PinAddResponse, error) bool) { + req := a.Request("pin/add").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(PinAddResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(PinAddResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item PinAddResponse + if err := dec.Decode(&item); err != nil { + yield(PinAddResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// PinLsOption configures the pin/ls command. +type PinLsOption func(RequestBuilder) + +// PinLsType sets the type option. +// The type of pinned keys to list. Can be "direct", "indirect", "recursive", or "all". Default: all. +func PinLsType(v string) PinLsOption { + return func(rb RequestBuilder) { rb.Option("type", v) } +} + +// PinLsQuiet sets the quiet option. +// Output only the CIDs of pins. +func PinLsQuiet(v bool) PinLsOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// PinLsName sets the name option. +// Limit returned pins to ones with names that contain the value provided (case-sensitive, partial match). Implies --names=true. +func PinLsName(v string) PinLsOption { + return func(rb RequestBuilder) { rb.Option("name", v) } +} + +// PinLsStream sets the stream option. +// Enable streaming of pins as they are discovered. +func PinLsStream(v bool) PinLsOption { + return func(rb RequestBuilder) { rb.Option("stream", v) } +} + +// PinLsNames sets the names option. +// Include pin names in the output (slower, disabled by default). +func PinLsNames(v bool) PinLsOption { + return func(rb RequestBuilder) { rb.Option("names", v) } +} + +// PinLs list objects pinned to local storage.. +func (a *HttpApi) PinLs(ctx context.Context, ipfs_path []string, opts ...PinLsOption) iter.Seq2[PinLsResponse, error] { + return func(yield func(PinLsResponse, error) bool) { + req := a.Request("pin/ls").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(PinLsResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(PinLsResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item PinLsResponse + if err := dec.Decode(&item); err != nil { + yield(PinLsResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// PinRemoteAddOption configures the pin/remote/add command. +type PinRemoteAddOption func(RequestBuilder) + +// PinRemoteAddService sets the service option. +// Name of the remote pinning service to use (mandatory). +func PinRemoteAddService(v string) PinRemoteAddOption { + return func(rb RequestBuilder) { rb.Option("service", v) } +} + +// PinRemoteAddName sets the name option. +// An optional name for the pin. +func PinRemoteAddName(v string) PinRemoteAddOption { + return func(rb RequestBuilder) { rb.Option("name", v) } +} + +// PinRemoteAddBackground sets the background option. +// Add to the queue on the remote service and return immediately (does not wait for pinned status). Default: false. +func PinRemoteAddBackground(v bool) PinRemoteAddOption { + return func(rb RequestBuilder) { rb.Option("background", v) } +} + +// PinRemoteAdd pin object to remote pinning service.. +func (a *HttpApi) PinRemoteAdd(ctx context.Context, ipfs_path string, opts ...PinRemoteAddOption) (*PinRemoteAddResponse, error) { + req := a.Request("pin/remote/add", ipfs_path) + for _, o := range opts { + o(req) + } + var resp PinRemoteAddResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// PinRemoteLsOption configures the pin/remote/ls command. +type PinRemoteLsOption func(RequestBuilder) + +// PinRemoteLsService sets the service option. +// Name of the remote pinning service to use (mandatory). +func PinRemoteLsService(v string) PinRemoteLsOption { + return func(rb RequestBuilder) { rb.Option("service", v) } +} + +// PinRemoteLsName sets the name option. +// Return pins with names that contain the value provided (case-sensitive, exact match). +func PinRemoteLsName(v string) PinRemoteLsOption { + return func(rb RequestBuilder) { rb.Option("name", v) } +} + +// PinRemoteLsCid sets the cid option. +// Return pins for the specified CIDs (comma-separated). +func PinRemoteLsCid(v []string) PinRemoteLsOption { + return func(rb RequestBuilder) { rb.Option("cid", v) } +} + +// PinRemoteLsStatus sets the status option. +// Return pins with the specified statuses (queued,pinning,pinned,failed). Default: [pinned]. +func PinRemoteLsStatus(v []string) PinRemoteLsOption { + return func(rb RequestBuilder) { rb.Option("status", v) } +} + +// PinRemoteLs list objects pinned to remote pinning service.. +func (a *HttpApi) PinRemoteLs(ctx context.Context, opts ...PinRemoteLsOption) (*PinRemoteLsResponse, error) { + req := a.Request("pin/remote/ls") + for _, o := range opts { + o(req) + } + var resp PinRemoteLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// PinRemoteRmOption configures the pin/remote/rm command. +type PinRemoteRmOption func(RequestBuilder) + +// PinRemoteRmService sets the service option. +// Name of the remote pinning service to use (mandatory). +func PinRemoteRmService(v string) PinRemoteRmOption { + return func(rb RequestBuilder) { rb.Option("service", v) } +} + +// PinRemoteRmName sets the name option. +// Remove pins with names that contain provided value (case-sensitive, exact match). +func PinRemoteRmName(v string) PinRemoteRmOption { + return func(rb RequestBuilder) { rb.Option("name", v) } +} + +// PinRemoteRmCid sets the cid option. +// Remove pins for the specified CIDs. +func PinRemoteRmCid(v []string) PinRemoteRmOption { + return func(rb RequestBuilder) { rb.Option("cid", v) } +} + +// PinRemoteRmStatus sets the status option. +// Remove pins with the specified statuses (queued,pinning,pinned,failed). Default: [pinned]. +func PinRemoteRmStatus(v []string) PinRemoteRmOption { + return func(rb RequestBuilder) { rb.Option("status", v) } +} + +// PinRemoteRmForce sets the force option. +// Allow removal of multiple pins matching the query without additional confirmation. Default: false. +func PinRemoteRmForce(v bool) PinRemoteRmOption { + return func(rb RequestBuilder) { rb.Option("force", v) } +} + +// PinRemoteRm remove pins from remote pinning service.. +func (a *HttpApi) PinRemoteRm(ctx context.Context, opts ...PinRemoteRmOption) (*Response, error) { + req := a.Request("pin/remote/rm") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// PinRemoteServiceAdd add remote pinning service.. +func (a *HttpApi) PinRemoteServiceAdd(ctx context.Context, service string, endpoint string, key string) (*Response, error) { + req := a.Request("pin/remote/service/add", service, endpoint, key) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// PinRemoteServiceLsOption configures the pin/remote/service/ls command. +type PinRemoteServiceLsOption func(RequestBuilder) + +// PinRemoteServiceLsStat sets the stat option. +// Try to fetch and display current pin count on remote service (queued/pinning/pinned/failed). Default: false. +func PinRemoteServiceLsStat(v bool) PinRemoteServiceLsOption { + return func(rb RequestBuilder) { rb.Option("stat", v) } +} + +// PinRemoteServiceLs list remote pinning services.. +func (a *HttpApi) PinRemoteServiceLs(ctx context.Context, opts ...PinRemoteServiceLsOption) (*PinRemoteServiceLsResponse, error) { + req := a.Request("pin/remote/service/ls") + for _, o := range opts { + o(req) + } + var resp PinRemoteServiceLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// PinRemoteServiceRm remove remote pinning service.. +func (a *HttpApi) PinRemoteServiceRm(ctx context.Context, service string) (*Response, error) { + req := a.Request("pin/remote/service/rm", service) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// PinRmOption configures the pin/rm command. +type PinRmOption func(RequestBuilder) + +// PinRmRecursive sets the recursive option. +// Recursively unpin the object linked to by the specified object(s). Default: true. +func PinRmRecursive(v bool) PinRmOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// PinRm remove object from pin-list.. +func (a *HttpApi) PinRm(ctx context.Context, ipfs_path []string, opts ...PinRmOption) (*PinRmResponse, error) { + req := a.Request("pin/rm").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + var resp PinRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// PinUpdateOption configures the pin/update command. +type PinUpdateOption func(RequestBuilder) + +// PinUpdateUnpin sets the unpin option. +// Remove the old pin. Default: true. +func PinUpdateUnpin(v bool) PinUpdateOption { + return func(rb RequestBuilder) { rb.Option("unpin", v) } +} + +// PinUpdate update a recursive pin.. +func (a *HttpApi) PinUpdate(ctx context.Context, from_path string, to_path string, opts ...PinUpdateOption) (*PinUpdateResponse, error) { + req := a.Request("pin/update", from_path, to_path) + for _, o := range opts { + o(req) + } + var resp PinUpdateResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// PinVerifyOption configures the pin/verify command. +type PinVerifyOption func(RequestBuilder) + +// PinVerifyVerbose sets the verbose option. +// Also write the hashes of non-broken pins. +func PinVerifyVerbose(v bool) PinVerifyOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// PinVerifyQuiet sets the quiet option. +// Write just hashes of broken pins. +func PinVerifyQuiet(v bool) PinVerifyOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// PinVerify verify that recursive pins are complete.. +func (a *HttpApi) PinVerify(ctx context.Context, opts ...PinVerifyOption) iter.Seq2[PinVerifyResponse, error] { + return func(yield func(PinVerifyResponse, error) bool) { + req := a.Request("pin/verify") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(PinVerifyResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(PinVerifyResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item PinVerifyResponse + if err := dec.Decode(&item); err != nil { + yield(PinVerifyResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_ping.go b/client/rpc/gen_ping.go new file mode 100644 index 00000000000..de0895c63c4 --- /dev/null +++ b/client/rpc/gen_ping.go @@ -0,0 +1,55 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type PingResponse struct { + Success bool `json:"Success,omitempty"` + Time string `json:"Time,omitempty"` + Text string `json:"Text,omitempty"` +} + +// PingOption configures the ping command. +type PingOption func(RequestBuilder) + +// PingCount sets the count option. +// Number of ping messages to send. Default: 10. +func PingCount(v int) PingOption { + return func(rb RequestBuilder) { rb.Option("count", v) } +} + +// Ping send echo request packets to IPFS hosts.. +func (a *HttpApi) Ping(ctx context.Context, peer_ID []string, opts ...PingOption) iter.Seq2[PingResponse, error] { + return func(yield func(PingResponse, error) bool) { + req := a.Request("ping").Arguments(peer_ID...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(PingResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(PingResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item PingResponse + if err := dec.Decode(&item); err != nil { + yield(PingResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_provide.go b/client/rpc/gen_provide.go new file mode 100644 index 00000000000..aa639983d53 --- /dev/null +++ b/client/rpc/gen_provide.go @@ -0,0 +1,208 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type ProvideStatResponse struct { + Sweep *ProvideStatResponseSweep `json:"Sweep,omitempty"` + Legacy *ProvideStatResponseLegacy `json:"Legacy,omitempty"` + FullRT bool `json:"FullRT,omitempty"` +} + +type ProvideStatResponseLegacy struct { + TotalReprovides uint64 `json:"TotalReprovides,omitempty"` + LastReprovideBatchSize uint64 `json:"LastReprovideBatchSize,omitempty"` + ReprovideInterval string `json:"ReprovideInterval,omitempty"` + AvgReprovideDuration string `json:"AvgReprovideDuration,omitempty"` + LastReprovideDuration string `json:"LastReprovideDuration,omitempty"` + LastRun string `json:"LastRun,omitempty"` +} + +type ProvideStatResponseSweep struct { + Closed bool `json:"closed"` + Connectivity ProvideStatResponseSweepConnectivity `json:"connectivity"` + Queues ProvideStatResponseSweepQueues `json:"queues"` + Schedule ProvideStatResponseSweepSchedule `json:"schedule"` + Workers ProvideStatResponseSweepWorkers `json:"workers"` + Timing ProvideStatResponseSweepTiming `json:"timing"` + Operations ProvideStatResponseSweepOperations `json:"operations"` + Network ProvideStatResponseSweepNetwork `json:"network"` +} + +type ProvideStatResponseSweepConnectivity struct { + Status string `json:"status"` + Since string `json:"since"` +} + +type ProvideStatResponseSweepNetwork struct { + Peers int `json:"peers"` + Reachable int `json:"reachable"` + CompleteKeyspaceCoverage bool `json:"complete_keyspace_coverage"` + AvgRegionSize float64 `json:"avg_region_size"` + AvgHolders float64 `json:"avg_holders"` + ReplicationFactor int `json:"replication_factor"` +} + +type ProvideStatResponseSweepOperations struct { + Ongoing ProvideStatResponseSweepOperationsOngoing `json:"ongoing"` + Past ProvideStatResponseSweepOperationsPast `json:"past"` +} + +type ProvideStatResponseSweepOperationsOngoing struct { + RegionProvides int `json:"region_provides"` + KeyProvides int `json:"key_provides"` + RegionReprovides int `json:"region_reprovides"` + KeyReprovides int `json:"key_reprovides"` +} + +type ProvideStatResponseSweepOperationsPast struct { + RecordsProvided int64 `json:"records_provided"` + KeysProvided int64 `json:"keys_provided"` + KeysFailed int64 `json:"keys_failed"` + KeysProvidedPerMinute float64 `json:"keys_provided_per_minute"` + KeysReprovidedPerMinute float64 `json:"keys_reprovided_per_minute"` + RegionReprovideDuration string `json:"reprovide_duration"` + AvgKeysPerReprovide float64 `json:"avg_keys_per_reprovide"` + RegionReprovidedLastCycle int64 `json:"regions_reprovided_last_cycle"` +} + +type ProvideStatResponseSweepQueues struct { + PendingKeyProvides int64 `json:"pending_key_provides"` + PendingRegionProvides int64 `json:"pending_region_provides"` + PendingRegionReprovides int64 `json:"pending_region_reprovides"` +} + +type ProvideStatResponseSweepSchedule struct { + Keys int64 `json:"keys"` + Regions int64 `json:"regions"` + AvgPrefixLength float64 `json:"avg_prefix_length"` + NextReprovideAt string `json:"next_reprovide_at"` + NextReprovidePrefix string `json:"next_reprovide_prefix"` +} + +type ProvideStatResponseSweepTiming struct { + Uptime string `json:"uptime"` + ReprovidesInterval string `json:"reprovides_interval"` + CycleStart string `json:"cycle_start"` + CurrentTimeOffset string `json:"current_time_offset"` + MaxReprovideDelay string `json:"max_reprovide_delay"` +} + +type ProvideStatResponseSweepWorkers struct { + Max int `json:"max"` + Active int `json:"active"` + ActivePeriodic int `json:"active_periodic"` + ActiveBurst int `json:"active_burst"` + DedicatedPeriodic int `json:"dedicated_periodic"` + DedicatedBurst int `json:"dedicated_burst"` + QueuedPeriodic int `json:"queued_periodic"` + QueuedBurst int `json:"queued_burst"` + MaxProvideConnsPerWorker int `json:"max_provide_conns_per_worker"` +} + +// ProvideClearOption configures the provide/clear command. +type ProvideClearOption func(RequestBuilder) + +// ProvideClearQuiet sets the quiet option. +// Do not write output. +func ProvideClearQuiet(v bool) ProvideClearOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// Experimental: ProvideClear is not yet stable. +// ProvideClear clear all CIDs from the provide queue.. +func (a *HttpApi) ProvideClear(ctx context.Context, opts ...ProvideClearOption) (*Response, error) { + req := a.Request("provide/clear") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// ProvideStatOption configures the provide/stat command. +type ProvideStatOption func(RequestBuilder) + +// ProvideStatLan sets the lan option. +// Show stats for LAN DHT only (for Sweep+Dual DHT only). +func ProvideStatLan(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("lan", v) } +} + +// ProvideStatAll sets the all option. +// Display all provide sweep stats. +func ProvideStatAll(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// ProvideStatCompact sets the compact option. +// Display stats in 2-column layout (requires --all). +func ProvideStatCompact(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("compact", v) } +} + +// ProvideStatConnectivity sets the connectivity option. +// Display DHT connectivity status. +func ProvideStatConnectivity(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("connectivity", v) } +} + +// ProvideStatNetwork sets the network option. +// Display network stats (peers, reachability, region size). +func ProvideStatNetwork(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("network", v) } +} + +// ProvideStatSchedule sets the schedule option. +// Display reprovide schedule (CIDs/regions scheduled, next reprovide time). +func ProvideStatSchedule(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("schedule", v) } +} + +// ProvideStatTimings sets the timings option. +// Display timing information (uptime, cycle start, reprovide interval). +func ProvideStatTimings(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("timings", v) } +} + +// ProvideStatWorkers sets the workers option. +// Display worker pool stats (active/available/queued workers). +func ProvideStatWorkers(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("workers", v) } +} + +// ProvideStatOperations sets the operations option. +// Display operation stats (ongoing/past provides, rates, errors). +func ProvideStatOperations(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("operations", v) } +} + +// ProvideStatQueues sets the queues option. +// Display provide and reprovide queue sizes. +func ProvideStatQueues(v bool) ProvideStatOption { + return func(rb RequestBuilder) { rb.Option("queues", v) } +} + +// Experimental: ProvideStat is not yet stable. +// ProvideStat show statistics about the provider system. +func (a *HttpApi) ProvideStat(ctx context.Context, opts ...ProvideStatOption) (*ProvideStatResponse, error) { + req := a.Request("provide/stat") + for _, o := range opts { + o(req) + } + var resp ProvideStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_pubsub.go b/client/rpc/gen_pubsub.go new file mode 100644 index 00000000000..9fb14f20937 --- /dev/null +++ b/client/rpc/gen_pubsub.go @@ -0,0 +1,119 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "io" + "iter" +) + +type PubsubLsResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type PubsubPeersResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type PubsubResetResponse struct { + Deleted int64 `json:"deleted"` +} + +type PubsubSubResponse struct { + From string `json:"from,omitempty"` + Data string `json:"data,omitempty"` + Seqno string `json:"seqno,omitempty"` + TopicIDs []string `json:"topicIDs,omitempty"` +} + +// Experimental: PubsubLs is not yet stable. +// PubsubLs list subscribed topics by name.. +func (a *HttpApi) PubsubLs(ctx context.Context) (*PubsubLsResponse, error) { + req := a.Request("pubsub/ls") + var resp PubsubLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: PubsubPeers is not yet stable. +// PubsubPeers list peers we are currently pubsubbing with.. +func (a *HttpApi) PubsubPeers(ctx context.Context, topic string) (*PubsubPeersResponse, error) { + req := a.Request("pubsub/peers", topic) + var resp PubsubPeersResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: PubsubPub is not yet stable. +// PubsubPub publish data to a given pubsub topic.. +func (a *HttpApi) PubsubPub(ctx context.Context, topic string, data io.Reader) (*Response, error) { + req := a.Request("pubsub/pub", topic) + req = req.FileBody(data).(RequestBuilder) + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} + +// PubsubResetOption configures the pubsub/reset command. +type PubsubResetOption func(RequestBuilder) + +// PubsubResetPeer sets the peer option. +// Only reset state for this peer ID. +func PubsubResetPeer(v string) PubsubResetOption { + return func(rb RequestBuilder) { rb.Option("peer", v) } +} + +// Experimental: PubsubReset is not yet stable. +// PubsubReset reset pubsub validator state.. +func (a *HttpApi) PubsubReset(ctx context.Context, opts ...PubsubResetOption) (*PubsubResetResponse, error) { + req := a.Request("pubsub/reset") + for _, o := range opts { + o(req) + } + var resp PubsubResetResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: PubsubSub is not yet stable. +// PubsubSub subscribe to messages on a given topic.. +func (a *HttpApi) PubsubSub(ctx context.Context, topic string) iter.Seq2[PubsubSubResponse, error] { + return func(yield func(PubsubSubResponse, error) bool) { + req := a.Request("pubsub/sub", topic) + resp, err := req.Send(ctx) + if err != nil { + yield(PubsubSubResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(PubsubSubResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item PubsubSubResponse + if err := dec.Decode(&item); err != nil { + yield(PubsubSubResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_refs.go b/client/rpc/gen_refs.go new file mode 100644 index 00000000000..283ee0a247f --- /dev/null +++ b/client/rpc/gen_refs.go @@ -0,0 +1,111 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type RefsLocalResponse struct { + Ref string `json:"Ref,omitempty"` + Err string `json:"Err,omitempty"` +} + +type RefsResponse struct { + Ref string `json:"Ref,omitempty"` + Err string `json:"Err,omitempty"` +} + +// RefsOption configures the refs command. +type RefsOption func(RequestBuilder) + +// RefsFormat sets the format option. +// Emit edges with given format. Available tokens: . Default: . +func RefsFormat(v string) RefsOption { + return func(rb RequestBuilder) { rb.Option("format", v) } +} + +// RefsEdges sets the edges option. +// Emit edge format: ` -> `. +func RefsEdges(v bool) RefsOption { + return func(rb RequestBuilder) { rb.Option("edges", v) } +} + +// RefsUnique sets the unique option. +// Omit duplicate refs from output. +func RefsUnique(v bool) RefsOption { + return func(rb RequestBuilder) { rb.Option("unique", v) } +} + +// RefsRecursive sets the recursive option. +// Recursively list links of child nodes. +func RefsRecursive(v bool) RefsOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// RefsMaxDepth sets the max-depth option. +// Only for recursive refs, limits fetch and listing to the given depth. Default: -1. +func RefsMaxDepth(v int) RefsOption { + return func(rb RequestBuilder) { rb.Option("max-depth", v) } +} + +// Refs list links (references) from an object.. +func (a *HttpApi) Refs(ctx context.Context, ipfs_path []string, opts ...RefsOption) iter.Seq2[RefsResponse, error] { + return func(yield func(RefsResponse, error) bool) { + req := a.Request("refs").Arguments(ipfs_path...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RefsResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RefsResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RefsResponse + if err := dec.Decode(&item); err != nil { + yield(RefsResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RefsLocal list all local references.. +func (a *HttpApi) RefsLocal(ctx context.Context) iter.Seq2[RefsLocalResponse, error] { + return func(yield func(RefsLocalResponse, error) bool) { + req := a.Request("refs/local") + resp, err := req.Send(ctx) + if err != nil { + yield(RefsLocalResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RefsLocalResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RefsLocalResponse + if err := dec.Decode(&item); err != nil { + yield(RefsLocalResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} diff --git a/client/rpc/gen_repo.go b/client/rpc/gen_repo.go new file mode 100644 index 00000000000..6044af15b35 --- /dev/null +++ b/client/rpc/gen_repo.go @@ -0,0 +1,218 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type RepoGcResponse struct { + Key string `json:"Key,omitempty"` + Error string `json:",omitempty"` +} + +type RepoLsResponse struct { + Ref string `json:"Ref,omitempty"` + Err string `json:"Err,omitempty"` +} + +type RepoStatResponse struct { + RepoSize uint64 `json:"RepoSize,omitempty"` + StorageMax uint64 `json:"StorageMax,omitempty"` + NumObjects uint64 `json:"NumObjects,omitempty"` + RepoPath string `json:"RepoPath,omitempty"` + Version string `json:"Version,omitempty"` +} + +type RepoVerifyResponse struct { + Msg string `json:"Msg,omitempty"` + Progress int `json:"Progress,omitempty"` +} + +type RepoVersionResponse struct { + Version string `json:"Version,omitempty"` +} + +// RepoGcOption configures the repo/gc command. +type RepoGcOption func(RequestBuilder) + +// RepoGcStreamErrors sets the stream-errors option. +// Stream errors. +func RepoGcStreamErrors(v bool) RepoGcOption { + return func(rb RequestBuilder) { rb.Option("stream-errors", v) } +} + +// RepoGcQuiet sets the quiet option. +// Write minimal output. +func RepoGcQuiet(v bool) RepoGcOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// RepoGcSilent sets the silent option. +// Write no output. +func RepoGcSilent(v bool) RepoGcOption { + return func(rb RequestBuilder) { rb.Option("silent", v) } +} + +// RepoGc perform a garbage collection sweep on the repo.. +func (a *HttpApi) RepoGc(ctx context.Context, opts ...RepoGcOption) iter.Seq2[RepoGcResponse, error] { + return func(yield func(RepoGcResponse, error) bool) { + req := a.Request("repo/gc") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RepoGcResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RepoGcResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RepoGcResponse + if err := dec.Decode(&item); err != nil { + yield(RepoGcResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RepoLs list all local references.. +func (a *HttpApi) RepoLs(ctx context.Context) iter.Seq2[RepoLsResponse, error] { + return func(yield func(RepoLsResponse, error) bool) { + req := a.Request("repo/ls") + resp, err := req.Send(ctx) + if err != nil { + yield(RepoLsResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RepoLsResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RepoLsResponse + if err := dec.Decode(&item); err != nil { + yield(RepoLsResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RepoStatOption configures the repo/stat command. +type RepoStatOption func(RequestBuilder) + +// RepoStatSizeOnly sets the size-only option. +// Only report RepoSize and StorageMax. +func RepoStatSizeOnly(v bool) RepoStatOption { + return func(rb RequestBuilder) { rb.Option("size-only", v) } +} + +// RepoStatHuman sets the human option. +// Print sizes in human readable format (e.g., 1K 234M 2G). +func RepoStatHuman(v bool) RepoStatOption { + return func(rb RequestBuilder) { rb.Option("human", v) } +} + +// RepoStat get stats for the currently used repo.. +func (a *HttpApi) RepoStat(ctx context.Context, opts ...RepoStatOption) (*RepoStatResponse, error) { + req := a.Request("repo/stat") + for _, o := range opts { + o(req) + } + var resp RepoStatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// RepoVerifyOption configures the repo/verify command. +type RepoVerifyOption func(RequestBuilder) + +// RepoVerifyDrop sets the drop option. +// Remove corrupt blocks from datastore (destructive operation). +func RepoVerifyDrop(v bool) RepoVerifyOption { + return func(rb RequestBuilder) { rb.Option("drop", v) } +} + +// RepoVerifyHeal sets the heal option. +// Remove corrupt blocks and re-fetch from network (destructive operation, implies --drop). +func RepoVerifyHeal(v bool) RepoVerifyOption { + return func(rb RequestBuilder) { rb.Option("heal", v) } +} + +// RepoVerifyHealTimeout sets the heal-timeout option. +// Maximum time to wait for each block heal (e.g., "30s"). Only applies with --heal. Default: 30s. +func RepoVerifyHealTimeout(v string) RepoVerifyOption { + return func(rb RequestBuilder) { rb.Option("heal-timeout", v) } +} + +// RepoVerify verify all blocks in repo are not corrupted.. +func (a *HttpApi) RepoVerify(ctx context.Context, opts ...RepoVerifyOption) iter.Seq2[RepoVerifyResponse, error] { + return func(yield func(RepoVerifyResponse, error) bool) { + req := a.Request("repo/verify") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RepoVerifyResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RepoVerifyResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RepoVerifyResponse + if err := dec.Decode(&item); err != nil { + yield(RepoVerifyResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RepoVersionOption configures the repo/version command. +type RepoVersionOption func(RequestBuilder) + +// RepoVersionQuiet sets the quiet option. +// Write minimal output. +func RepoVersionQuiet(v bool) RepoVersionOption { + return func(rb RequestBuilder) { rb.Option("quiet", v) } +} + +// RepoVersion show the repo version.. +func (a *HttpApi) RepoVersion(ctx context.Context, opts ...RepoVersionOption) (*RepoVersionResponse, error) { + req := a.Request("repo/version") + for _, o := range opts { + o(req) + } + var resp RepoVersionResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_resolve.go b/client/rpc/gen_resolve.go new file mode 100644 index 00000000000..1e520868c29 --- /dev/null +++ b/client/rpc/gen_resolve.go @@ -0,0 +1,45 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type ResolveResponse struct { + Path string `json:"Path,omitempty"` +} + +// ResolveOption configures the resolve command. +type ResolveOption func(RequestBuilder) + +// ResolveRecursive sets the recursive option. +// Resolve until the result is an IPFS name. Default: true. +func ResolveRecursive(v bool) ResolveOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// ResolveDhtRecordCount sets the dht-record-count option. +// Number of records to request for DHT resolution. +func ResolveDhtRecordCount(v int) ResolveOption { + return func(rb RequestBuilder) { rb.Option("dht-record-count", v) } +} + +// ResolveDhtTimeout sets the dht-timeout option. +// Max time to collect values during DHT resolution e.g. "30s". Pass 0 for no timeout. +func ResolveDhtTimeout(v string) ResolveOption { + return func(rb RequestBuilder) { rb.Option("dht-timeout", v) } +} + +// Resolve resolve the value of names to IPFS.. +func (a *HttpApi) Resolve(ctx context.Context, name string, opts ...ResolveOption) (*ResolveResponse, error) { + req := a.Request("resolve", name) + for _, o := range opts { + o(req) + } + var resp ResolveResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_routing.go b/client/rpc/gen_routing.go new file mode 100644 index 00000000000..5f94e96fbb0 --- /dev/null +++ b/client/rpc/gen_routing.go @@ -0,0 +1,253 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "io" + "iter" +) + +type RoutingFindpeerResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*RoutingFindpeerResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type RoutingFindpeerResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +type RoutingFindprovsResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*RoutingFindprovsResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type RoutingFindprovsResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +type RoutingGetResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*RoutingGetResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type RoutingGetResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +type RoutingProvideResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*RoutingProvideResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type RoutingProvideResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +type RoutingPutResponse struct { + ID string `json:"ID,omitempty"` + Type int `json:"Type,omitempty"` + Responses []*RoutingPutResponseResponses `json:"Responses,omitempty"` + Extra string `json:"Extra,omitempty"` +} + +type RoutingPutResponseResponses struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +// RoutingFindpeerOption configures the routing/findpeer command. +type RoutingFindpeerOption func(RequestBuilder) + +// RoutingFindpeerVerbose sets the verbose option. +// Print extra information. +func RoutingFindpeerVerbose(v bool) RoutingFindpeerOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// RoutingFindpeer find the multiaddresses associated with a Peer ID.. +func (a *HttpApi) RoutingFindpeer(ctx context.Context, peerID []string, opts ...RoutingFindpeerOption) iter.Seq2[RoutingFindpeerResponse, error] { + return func(yield func(RoutingFindpeerResponse, error) bool) { + req := a.Request("routing/findpeer").Arguments(peerID...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RoutingFindpeerResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RoutingFindpeerResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RoutingFindpeerResponse + if err := dec.Decode(&item); err != nil { + yield(RoutingFindpeerResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RoutingFindprovsOption configures the routing/findprovs command. +type RoutingFindprovsOption func(RequestBuilder) + +// RoutingFindprovsVerbose sets the verbose option. +// Print extra information. +func RoutingFindprovsVerbose(v bool) RoutingFindprovsOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// RoutingFindprovsNumProviders sets the num-providers option. +// The number of providers to find. Default: 20. +func RoutingFindprovsNumProviders(v int) RoutingFindprovsOption { + return func(rb RequestBuilder) { rb.Option("num-providers", v) } +} + +// RoutingFindprovs find peers that can provide a specific value, given a key.. +func (a *HttpApi) RoutingFindprovs(ctx context.Context, key []string, opts ...RoutingFindprovsOption) iter.Seq2[RoutingFindprovsResponse, error] { + return func(yield func(RoutingFindprovsResponse, error) bool) { + req := a.Request("routing/findprovs").Arguments(key...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RoutingFindprovsResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RoutingFindprovsResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RoutingFindprovsResponse + if err := dec.Decode(&item); err != nil { + yield(RoutingFindprovsResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// Experimental: RoutingGet is not yet stable. +// RoutingGet given a key, query the routing system for its best value.. +func (a *HttpApi) RoutingGet(ctx context.Context, key ...string) (*RoutingGetResponse, error) { + req := a.Request("routing/get").Arguments(key...) + var resp RoutingGetResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// RoutingProvideOption configures the routing/provide command. +type RoutingProvideOption func(RequestBuilder) + +// RoutingProvideVerbose sets the verbose option. +// Print extra information. +func RoutingProvideVerbose(v bool) RoutingProvideOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// RoutingProvideRecursive sets the recursive option. +// Recursively provide entire graph. +func RoutingProvideRecursive(v bool) RoutingProvideOption { + return func(rb RequestBuilder) { rb.Option("recursive", v) } +} + +// Experimental: RoutingProvide is not yet stable. +// RoutingProvide announce to the network that you are providing given values.. +func (a *HttpApi) RoutingProvide(ctx context.Context, key []string, opts ...RoutingProvideOption) iter.Seq2[RoutingProvideResponse, error] { + return func(yield func(RoutingProvideResponse, error) bool) { + req := a.Request("routing/provide").Arguments(key...) + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(RoutingProvideResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(RoutingProvideResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item RoutingProvideResponse + if err := dec.Decode(&item); err != nil { + yield(RoutingProvideResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// RoutingPutOption configures the routing/put command. +type RoutingPutOption func(RequestBuilder) + +// RoutingPutAllowOffline sets the allow-offline option. +// When offline, save the IPNS record to the local datastore without broadcasting to the network instead of simply failing. +func RoutingPutAllowOffline(v bool) RoutingPutOption { + return func(rb RequestBuilder) { rb.Option("allow-offline", v) } +} + +// Experimental: RoutingPut is not yet stable. +// RoutingPut write a key/value pair to the routing system.. +func (a *HttpApi) RoutingPut(ctx context.Context, key string, value_file io.Reader, opts ...RoutingPutOption) (*RoutingPutResponse, error) { + req := a.Request("routing/put", key) + req = req.FileBody(value_file).(RequestBuilder) + for _, o := range opts { + o(req) + } + var resp RoutingPutResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: RoutingReprovide is not yet stable. +// RoutingReprovide trigger reprovider.. +func (a *HttpApi) RoutingReprovide(ctx context.Context) (*Response, error) { + req := a.Request("routing/reprovide") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_shutdown.go b/client/rpc/gen_shutdown.go new file mode 100644 index 00000000000..c724ef9a8f0 --- /dev/null +++ b/client/rpc/gen_shutdown.go @@ -0,0 +1,21 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +// Shutdown shut down the IPFS daemon.. +func (a *HttpApi) Shutdown(ctx context.Context) (*Response, error) { + req := a.Request("shutdown") + resp, err := req.Send(ctx) + if err != nil { + return nil, err + } + if resp.Error != nil { + resp.Close() + return nil, resp.Error + } + return resp, nil +} diff --git a/client/rpc/gen_smoke_test.go b/client/rpc/gen_smoke_test.go new file mode 100644 index 00000000000..7dd8c9454bb --- /dev/null +++ b/client/rpc/gen_smoke_test.go @@ -0,0 +1,881 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "strings" + "testing" + + "github.com/ipfs/kubo/test/cli/harness" + "github.com/stretchr/testify/require" +) + +// TestGeneratedSmoke starts a daemon and calls every generated method with +// minimal arguments. It verifies that methods don't panic and that response +// deserialization works. Commands that need complex setup are skipped. +func TestGeneratedSmoke(t *testing.T) { + t.Parallel() + h := harness.NewT(t) + node := h.NewNode().Init().StartDaemon("--offline") + api, err := NewApi(node.APIAddr()) + require.NoError(t, err) + ctx := context.Background() + _ = strings.NewReader // ensure strings import is used + + testCID := node.IPFSAddStr("smoke test data") + + t.Run("Add", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.Add(ctx, strings.NewReader("test data")) { + _ = err + break + } + }) + }) + + t.Run("BitswapLedger", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BitswapLedger(ctx, "") + }) + }) + + t.Run("BitswapReprovide", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.BitswapReprovide(ctx) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("BitswapStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BitswapStat(ctx) + }) + }) + + t.Run("BitswapWantlist", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BitswapWantlist(ctx) + }) + }) + + t.Run("BlockGet", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.BlockGet(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("BlockPut", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BlockPut(ctx, strings.NewReader("test data")) + }) + }) + + t.Run("BlockRm", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BlockRm(ctx, []string{testCID}) + }) + }) + + t.Run("BlockStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BlockStat(ctx, testCID) + }) + }) + + t.Run("Bootstrap", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.Bootstrap(ctx) + }) + }) + + t.Run("BootstrapAdd", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BootstrapAdd(ctx, "") + }) + }) + + t.Run("BootstrapList", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BootstrapList(ctx) + }) + }) + + t.Run("BootstrapRm", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BootstrapRm(ctx, []string{""}) + }) + }) + + t.Run("BootstrapRmAll", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.BootstrapRmAll(ctx) + }) + }) + + t.Run("Cat", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.Cat(ctx, []string{testCID}) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("CidBase32", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.CidBase32(ctx, testCID) + }) + }) + + t.Run("CidBases", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.CidBases(ctx) + }) + }) + + t.Run("CidCodecs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.CidCodecs(ctx) + }) + }) + + t.Run("CidFormat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.CidFormat(ctx, []string{testCID}) + }) + }) + + t.Run("CidHashes", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.CidHashes(ctx) + }) + }) + + t.Run("Commands", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.Commands(ctx) + }) + }) + + t.Run("Config", func(t *testing.T) { + t.Skip("needs specific config key/value") + }) + + t.Run("ConfigProfileApply", func(t *testing.T) { + t.Skip("mutates config") + }) + + t.Run("ConfigReplace", func(t *testing.T) { + t.Skip("replaces entire config") + }) + + t.Run("ConfigShow", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.ConfigShow(ctx) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("DagExport", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.DagExport(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("DagGet", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.DagGet(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("DagImport", func(t *testing.T) { + t.Skip("needs valid CAR file") + }) + + t.Run("DagPut", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.DagPut(ctx, strings.NewReader("{}")) + }) + }) + + t.Run("DagResolve", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.DagResolve(ctx, testCID) + }) + }) + + t.Run("DagStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.DagStat(ctx, []string{testCID}) + }) + }) + + t.Run("DhtQuery", func(t *testing.T) { + t.Skip("needs online peer") + }) + + t.Run("DiagCmds", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.DiagCmds(ctx) + }) + }) + + t.Run("DiagCmdsClear", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.DiagCmdsClear(ctx) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("DiagCmdsSetTime", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.DiagCmdsSetTime(ctx, "") + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("DiagProfile", func(t *testing.T) { + t.Skip("runs profiler, slow") + }) + + t.Run("DiagSys", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.DiagSys(ctx) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("FilesChcid", func(t *testing.T) { + t.Skip("needs MFS path") + }) + + t.Run("FilesChmod", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.FilesChmod(ctx, "", testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("FilesCp", func(t *testing.T) { + t.Skip("needs MFS files") + }) + + t.Run("FilesFlush", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.FilesFlush(ctx, testCID) + }) + }) + + t.Run("FilesLs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.FilesLs(ctx, testCID) + }) + }) + + t.Run("FilesMkdir", func(t *testing.T) { + t.Skip("needs MFS path setup") + }) + + t.Run("FilesMv", func(t *testing.T) { + t.Skip("needs MFS files") + }) + + t.Run("FilesRead", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.FilesRead(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("FilesRm", func(t *testing.T) { + t.Skip("needs MFS files") + }) + + t.Run("FilesStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.FilesStat(ctx, testCID) + }) + }) + + t.Run("FilesTouch", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.FilesTouch(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("FilesWrite", func(t *testing.T) { + t.Skip("needs MFS file path") + }) + + t.Run("FilestoreDups", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.FilestoreDups(ctx) + }) + }) + + t.Run("FilestoreLs", func(t *testing.T) { + t.Skip("needs filestore content") + }) + + t.Run("FilestoreVerify", func(t *testing.T) { + t.Skip("needs filestore content") + }) + + t.Run("Get", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.Get(ctx, testCID) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("Id", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.Id(ctx, "") + }) + }) + + t.Run("KeyGen", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.KeyGen(ctx, "") + }) + }) + + t.Run("KeyImport", func(t *testing.T) { + t.Skip("needs valid key file") + }) + + t.Run("KeyList", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.KeyList(ctx) + }) + }) + + t.Run("KeyLs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.KeyLs(ctx) + }) + }) + + t.Run("KeyRename", func(t *testing.T) { + t.Skip("needs existing non-self key") + }) + + t.Run("KeyRm", func(t *testing.T) { + t.Skip("needs existing non-self key") + }) + + t.Run("KeySign", func(t *testing.T) { + t.Skip("needs key and data setup") + }) + + t.Run("KeyVerify", func(t *testing.T) { + t.Skip("needs key, signature, and data") + }) + + t.Run("LogLevel", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.LogLevel(ctx, "", "") + }) + }) + + t.Run("LogLs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.LogLs(ctx) + }) + }) + + t.Run("LogTail", func(t *testing.T) { + t.Skip("blocks waiting for log events") + }) + + t.Run("Ls", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.Ls(ctx, []string{testCID}) { + _ = err + break + } + }) + }) + + t.Run("Mount", func(t *testing.T) { + t.Skip("requires FUSE") + }) + + t.Run("MultibaseDecode", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.MultibaseDecode(ctx, strings.NewReader("test data")) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("MultibaseEncode", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.MultibaseEncode(ctx, strings.NewReader("test data")) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("MultibaseList", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.MultibaseList(ctx) + }) + }) + + t.Run("MultibaseTranscode", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.MultibaseTranscode(ctx, strings.NewReader("test data")) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("NameGet", func(t *testing.T) { + t.Skip("needs published IPNS record") + }) + + t.Run("NameInspect", func(t *testing.T) { + t.Skip("needs valid IPNS record file") + }) + + t.Run("NamePublish", func(t *testing.T) { + t.Skip("needs IPNS key setup") + }) + + t.Run("NamePubsubCancel", func(t *testing.T) { + t.Skip("needs active IPNS subscription") + }) + + t.Run("NamePubsubState", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.NamePubsubState(ctx) + }) + }) + + t.Run("NamePubsubSubs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.NamePubsubSubs(ctx) + }) + }) + + t.Run("NamePut", func(t *testing.T) { + t.Skip("needs valid IPNS record file") + }) + + t.Run("NameResolve", func(t *testing.T) { + t.Skip("needs published IPNS record") + }) + + t.Run("ObjectDiff", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.ObjectDiff(ctx, "", "") + }) + }) + + t.Run("ObjectPatchAddLink", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.ObjectPatchAddLink(ctx, testCID, "", testCID) + }) + }) + + t.Run("ObjectPatchRmLink", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.ObjectPatchRmLink(ctx, testCID, "") + }) + }) + + t.Run("P2pClose", func(t *testing.T) { + t.Skip("needs active p2p listeners") + }) + + t.Run("P2pForward", func(t *testing.T) { + t.Skip("needs p2p setup") + }) + + t.Run("P2pListen", func(t *testing.T) { + t.Skip("needs p2p setup") + }) + + t.Run("P2pLs", func(t *testing.T) { + t.Skip("needs active p2p listeners") + }) + + t.Run("P2pStreamClose", func(t *testing.T) { + t.Skip("needs active p2p streams") + }) + + t.Run("P2pStreamLs", func(t *testing.T) { + t.Skip("needs active p2p streams") + }) + + t.Run("PinAdd", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.PinAdd(ctx, []string{testCID}) { + _ = err + break + } + }) + }) + + t.Run("PinLs", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.PinLs(ctx, []string{testCID}) { + _ = err + break + } + }) + }) + + t.Run("PinRemoteAdd", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRemoteLs", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRemoteRm", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRemoteServiceAdd", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRemoteServiceLs", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRemoteServiceRm", func(t *testing.T) { + t.Skip("needs remote pinning service") + }) + + t.Run("PinRm", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.PinRm(ctx, []string{testCID}) + }) + }) + + t.Run("PinUpdate", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.PinUpdate(ctx, testCID, testCID) + }) + }) + + t.Run("PinVerify", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.PinVerify(ctx) { + _ = err + break + } + }) + }) + + t.Run("Ping", func(t *testing.T) { + t.Skip("needs online peer") + }) + + t.Run("ProvideClear", func(t *testing.T) { + require.NotPanics(t, func() { + resp, err := api.ProvideClear(ctx) + if err == nil && resp != nil { + resp.Close() + } + }) + }) + + t.Run("ProvideStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.ProvideStat(ctx) + }) + }) + + t.Run("PubsubLs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.PubsubLs(ctx) + }) + }) + + t.Run("PubsubPeers", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.PubsubPeers(ctx, "") + }) + }) + + t.Run("PubsubPub", func(t *testing.T) { + t.Skip("needs topic and subscriber") + }) + + t.Run("PubsubReset", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.PubsubReset(ctx) + }) + }) + + t.Run("PubsubSub", func(t *testing.T) { + t.Skip("blocks waiting for messages") + }) + + t.Run("Refs", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.Refs(ctx, []string{testCID}) { + _ = err + break + } + }) + }) + + t.Run("RefsLocal", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.RefsLocal(ctx) { + _ = err + break + } + }) + }) + + t.Run("RepoGc", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.RepoGc(ctx) { + _ = err + break + } + }) + }) + + t.Run("RepoLs", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.RepoLs(ctx) { + _ = err + break + } + }) + }) + + t.Run("RepoStat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.RepoStat(ctx) + }) + }) + + t.Run("RepoVerify", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.RepoVerify(ctx) { + _ = err + break + } + }) + }) + + t.Run("RepoVersion", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.RepoVersion(ctx) + }) + }) + + t.Run("Resolve", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.Resolve(ctx, "") + }) + }) + + t.Run("RoutingFindpeer", func(t *testing.T) { + t.Skip("needs online peer") + }) + + t.Run("RoutingFindprovs", func(t *testing.T) { + t.Skip("needs CID with providers") + }) + + t.Run("RoutingGet", func(t *testing.T) { + t.Skip("needs valid DHT key") + }) + + t.Run("RoutingProvide", func(t *testing.T) { + t.Skip("needs CID and network") + }) + + t.Run("RoutingPut", func(t *testing.T) { + t.Skip("needs valid DHT key/value pair") + }) + + t.Run("RoutingReprovide", func(t *testing.T) { + t.Skip("needs CID and network") + }) + + t.Run("Shutdown", func(t *testing.T) { + t.Skip("kills the daemon") + }) + + t.Run("StatsBitswap", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.StatsBitswap(ctx) + }) + }) + + t.Run("StatsBw", func(t *testing.T) { + t.Skip("blocks polling for bandwidth stats") + }) + + t.Run("StatsDht", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.StatsDht(ctx, "") { + _ = err + break + } + }) + }) + + t.Run("StatsProvide", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.StatsProvide(ctx) + }) + }) + + t.Run("StatsRepo", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.StatsRepo(ctx) + }) + }) + + t.Run("StatsReprovide", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.StatsReprovide(ctx) + }) + }) + + t.Run("SwarmAddrs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmAddrs(ctx) + }) + }) + + t.Run("SwarmAddrsAutonat", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmAddrsAutonat(ctx) + }) + }) + + t.Run("SwarmAddrsListen", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmAddrsListen(ctx) + }) + }) + + t.Run("SwarmAddrsLocal", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmAddrsLocal(ctx) + }) + }) + + t.Run("SwarmConnect", func(t *testing.T) { + t.Skip("needs peer address") + }) + + t.Run("SwarmDisconnect", func(t *testing.T) { + t.Skip("needs connected peer") + }) + + t.Run("SwarmFilters", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmFilters(ctx) + }) + }) + + t.Run("SwarmFiltersAdd", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmFiltersAdd(ctx, "") + }) + }) + + t.Run("SwarmFiltersRm", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmFiltersRm(ctx, "") + }) + }) + + t.Run("SwarmPeeringAdd", func(t *testing.T) { + require.NotPanics(t, func() { + for _, err := range api.SwarmPeeringAdd(ctx, "") { + _ = err + break + } + }) + }) + + t.Run("SwarmPeeringLs", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmPeeringLs(ctx) + }) + }) + + t.Run("SwarmPeeringRm", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmPeeringRm(ctx, "") + }) + }) + + t.Run("SwarmPeers", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmPeers(ctx) + }) + }) + + t.Run("SwarmResources", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.SwarmResources(ctx) + }) + }) + + t.Run("Version", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.Version(ctx) + }) + }) + + t.Run("VersionCheck", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.VersionCheck(ctx) + }) + }) + + t.Run("VersionDeps", func(t *testing.T) { + require.NotPanics(t, func() { + _, _ = api.VersionDeps(ctx) + }) + }) + +} diff --git a/client/rpc/gen_stats.go b/client/rpc/gen_stats.go new file mode 100644 index 00000000000..f2a32c8dde4 --- /dev/null +++ b/client/rpc/gen_stats.go @@ -0,0 +1,544 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type StatsBitswapResponse struct { + Wantlist []string `json:"Wantlist,omitempty"` + Peers []string `json:"Peers,omitempty"` + BlocksReceived uint64 `json:"BlocksReceived,omitempty"` + DataReceived uint64 `json:"DataReceived,omitempty"` + DupBlksReceived uint64 `json:"DupBlksReceived,omitempty"` + DupDataReceived uint64 `json:"DupDataReceived,omitempty"` + MessagesReceived uint64 `json:"MessagesReceived,omitempty"` + BlocksSent uint64 `json:"BlocksSent,omitempty"` + DataSent uint64 `json:"DataSent,omitempty"` +} + +type StatsBwResponse struct { + TotalIn int64 `json:"TotalIn,omitempty"` + TotalOut int64 `json:"TotalOut,omitempty"` + RateIn float64 `json:"RateIn,omitempty"` + RateOut float64 `json:"RateOut,omitempty"` +} + +type StatsDhtResponse struct { + Name string `json:"Name,omitempty"` + Buckets []StatsDhtResponseBuckets `json:"Buckets,omitempty"` +} + +type StatsDhtResponseBuckets struct { + LastRefresh string `json:"LastRefresh,omitempty"` + Peers []StatsDhtResponseBucketsPeers `json:"Peers,omitempty"` +} + +type StatsDhtResponseBucketsPeers struct { + ID string `json:"ID,omitempty"` + Connected bool `json:"Connected,omitempty"` + AgentVersion string `json:"AgentVersion,omitempty"` + LastUsefulAt string `json:"LastUsefulAt,omitempty"` + LastQueriedAt string `json:"LastQueriedAt,omitempty"` +} + +type StatsProvideResponse struct { + Sweep *StatsProvideResponseSweep `json:"Sweep,omitempty"` + Legacy *StatsProvideResponseLegacy `json:"Legacy,omitempty"` + FullRT bool `json:"FullRT,omitempty"` +} + +type StatsProvideResponseLegacy struct { + TotalReprovides uint64 `json:"TotalReprovides,omitempty"` + LastReprovideBatchSize uint64 `json:"LastReprovideBatchSize,omitempty"` + ReprovideInterval string `json:"ReprovideInterval,omitempty"` + AvgReprovideDuration string `json:"AvgReprovideDuration,omitempty"` + LastReprovideDuration string `json:"LastReprovideDuration,omitempty"` + LastRun string `json:"LastRun,omitempty"` +} + +type StatsProvideResponseSweep struct { + Closed bool `json:"closed"` + Connectivity StatsProvideResponseSweepConnectivity `json:"connectivity"` + Queues StatsProvideResponseSweepQueues `json:"queues"` + Schedule StatsProvideResponseSweepSchedule `json:"schedule"` + Workers StatsProvideResponseSweepWorkers `json:"workers"` + Timing StatsProvideResponseSweepTiming `json:"timing"` + Operations StatsProvideResponseSweepOperations `json:"operations"` + Network StatsProvideResponseSweepNetwork `json:"network"` +} + +type StatsProvideResponseSweepConnectivity struct { + Status string `json:"status"` + Since string `json:"since"` +} + +type StatsProvideResponseSweepNetwork struct { + Peers int `json:"peers"` + Reachable int `json:"reachable"` + CompleteKeyspaceCoverage bool `json:"complete_keyspace_coverage"` + AvgRegionSize float64 `json:"avg_region_size"` + AvgHolders float64 `json:"avg_holders"` + ReplicationFactor int `json:"replication_factor"` +} + +type StatsProvideResponseSweepOperations struct { + Ongoing StatsProvideResponseSweepOperationsOngoing `json:"ongoing"` + Past StatsProvideResponseSweepOperationsPast `json:"past"` +} + +type StatsProvideResponseSweepOperationsOngoing struct { + RegionProvides int `json:"region_provides"` + KeyProvides int `json:"key_provides"` + RegionReprovides int `json:"region_reprovides"` + KeyReprovides int `json:"key_reprovides"` +} + +type StatsProvideResponseSweepOperationsPast struct { + RecordsProvided int64 `json:"records_provided"` + KeysProvided int64 `json:"keys_provided"` + KeysFailed int64 `json:"keys_failed"` + KeysProvidedPerMinute float64 `json:"keys_provided_per_minute"` + KeysReprovidedPerMinute float64 `json:"keys_reprovided_per_minute"` + RegionReprovideDuration string `json:"reprovide_duration"` + AvgKeysPerReprovide float64 `json:"avg_keys_per_reprovide"` + RegionReprovidedLastCycle int64 `json:"regions_reprovided_last_cycle"` +} + +type StatsProvideResponseSweepQueues struct { + PendingKeyProvides int64 `json:"pending_key_provides"` + PendingRegionProvides int64 `json:"pending_region_provides"` + PendingRegionReprovides int64 `json:"pending_region_reprovides"` +} + +type StatsProvideResponseSweepSchedule struct { + Keys int64 `json:"keys"` + Regions int64 `json:"regions"` + AvgPrefixLength float64 `json:"avg_prefix_length"` + NextReprovideAt string `json:"next_reprovide_at"` + NextReprovidePrefix string `json:"next_reprovide_prefix"` +} + +type StatsProvideResponseSweepTiming struct { + Uptime string `json:"uptime"` + ReprovidesInterval string `json:"reprovides_interval"` + CycleStart string `json:"cycle_start"` + CurrentTimeOffset string `json:"current_time_offset"` + MaxReprovideDelay string `json:"max_reprovide_delay"` +} + +type StatsProvideResponseSweepWorkers struct { + Max int `json:"max"` + Active int `json:"active"` + ActivePeriodic int `json:"active_periodic"` + ActiveBurst int `json:"active_burst"` + DedicatedPeriodic int `json:"dedicated_periodic"` + DedicatedBurst int `json:"dedicated_burst"` + QueuedPeriodic int `json:"queued_periodic"` + QueuedBurst int `json:"queued_burst"` + MaxProvideConnsPerWorker int `json:"max_provide_conns_per_worker"` +} + +type StatsRepoResponse struct { + RepoSize uint64 `json:"RepoSize,omitempty"` + StorageMax uint64 `json:"StorageMax,omitempty"` + NumObjects uint64 `json:"NumObjects,omitempty"` + RepoPath string `json:"RepoPath,omitempty"` + Version string `json:"Version,omitempty"` +} + +type StatsReprovideResponse struct { + Sweep *StatsReprovideResponseSweep `json:"Sweep,omitempty"` + Legacy *StatsReprovideResponseLegacy `json:"Legacy,omitempty"` + FullRT bool `json:"FullRT,omitempty"` +} + +type StatsReprovideResponseLegacy struct { + TotalReprovides uint64 `json:"TotalReprovides,omitempty"` + LastReprovideBatchSize uint64 `json:"LastReprovideBatchSize,omitempty"` + ReprovideInterval string `json:"ReprovideInterval,omitempty"` + AvgReprovideDuration string `json:"AvgReprovideDuration,omitempty"` + LastReprovideDuration string `json:"LastReprovideDuration,omitempty"` + LastRun string `json:"LastRun,omitempty"` +} + +type StatsReprovideResponseSweep struct { + Closed bool `json:"closed"` + Connectivity StatsReprovideResponseSweepConnectivity `json:"connectivity"` + Queues StatsReprovideResponseSweepQueues `json:"queues"` + Schedule StatsReprovideResponseSweepSchedule `json:"schedule"` + Workers StatsReprovideResponseSweepWorkers `json:"workers"` + Timing StatsReprovideResponseSweepTiming `json:"timing"` + Operations StatsReprovideResponseSweepOperations `json:"operations"` + Network StatsReprovideResponseSweepNetwork `json:"network"` +} + +type StatsReprovideResponseSweepConnectivity struct { + Status string `json:"status"` + Since string `json:"since"` +} + +type StatsReprovideResponseSweepNetwork struct { + Peers int `json:"peers"` + Reachable int `json:"reachable"` + CompleteKeyspaceCoverage bool `json:"complete_keyspace_coverage"` + AvgRegionSize float64 `json:"avg_region_size"` + AvgHolders float64 `json:"avg_holders"` + ReplicationFactor int `json:"replication_factor"` +} + +type StatsReprovideResponseSweepOperations struct { + Ongoing StatsReprovideResponseSweepOperationsOngoing `json:"ongoing"` + Past StatsReprovideResponseSweepOperationsPast `json:"past"` +} + +type StatsReprovideResponseSweepOperationsOngoing struct { + RegionProvides int `json:"region_provides"` + KeyProvides int `json:"key_provides"` + RegionReprovides int `json:"region_reprovides"` + KeyReprovides int `json:"key_reprovides"` +} + +type StatsReprovideResponseSweepOperationsPast struct { + RecordsProvided int64 `json:"records_provided"` + KeysProvided int64 `json:"keys_provided"` + KeysFailed int64 `json:"keys_failed"` + KeysProvidedPerMinute float64 `json:"keys_provided_per_minute"` + KeysReprovidedPerMinute float64 `json:"keys_reprovided_per_minute"` + RegionReprovideDuration string `json:"reprovide_duration"` + AvgKeysPerReprovide float64 `json:"avg_keys_per_reprovide"` + RegionReprovidedLastCycle int64 `json:"regions_reprovided_last_cycle"` +} + +type StatsReprovideResponseSweepQueues struct { + PendingKeyProvides int64 `json:"pending_key_provides"` + PendingRegionProvides int64 `json:"pending_region_provides"` + PendingRegionReprovides int64 `json:"pending_region_reprovides"` +} + +type StatsReprovideResponseSweepSchedule struct { + Keys int64 `json:"keys"` + Regions int64 `json:"regions"` + AvgPrefixLength float64 `json:"avg_prefix_length"` + NextReprovideAt string `json:"next_reprovide_at"` + NextReprovidePrefix string `json:"next_reprovide_prefix"` +} + +type StatsReprovideResponseSweepTiming struct { + Uptime string `json:"uptime"` + ReprovidesInterval string `json:"reprovides_interval"` + CycleStart string `json:"cycle_start"` + CurrentTimeOffset string `json:"current_time_offset"` + MaxReprovideDelay string `json:"max_reprovide_delay"` +} + +type StatsReprovideResponseSweepWorkers struct { + Max int `json:"max"` + Active int `json:"active"` + ActivePeriodic int `json:"active_periodic"` + ActiveBurst int `json:"active_burst"` + DedicatedPeriodic int `json:"dedicated_periodic"` + DedicatedBurst int `json:"dedicated_burst"` + QueuedPeriodic int `json:"queued_periodic"` + QueuedBurst int `json:"queued_burst"` + MaxProvideConnsPerWorker int `json:"max_provide_conns_per_worker"` +} + +// StatsBitswapOption configures the stats/bitswap command. +type StatsBitswapOption func(RequestBuilder) + +// StatsBitswapVerbose sets the verbose option. +// Print extra information. +func StatsBitswapVerbose(v bool) StatsBitswapOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// StatsBitswapHuman sets the human option. +// Print sizes in human readable format (e.g., 1K 234M 2G). +func StatsBitswapHuman(v bool) StatsBitswapOption { + return func(rb RequestBuilder) { rb.Option("human", v) } +} + +// StatsBitswap show some diagnostic information on the bitswap agent.. +func (a *HttpApi) StatsBitswap(ctx context.Context, opts ...StatsBitswapOption) (*StatsBitswapResponse, error) { + req := a.Request("stats/bitswap") + for _, o := range opts { + o(req) + } + var resp StatsBitswapResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// StatsBwOption configures the stats/bw command. +type StatsBwOption func(RequestBuilder) + +// StatsBwPeer sets the peer option. +// Specify a peer to print bandwidth for. +func StatsBwPeer(v string) StatsBwOption { + return func(rb RequestBuilder) { rb.Option("peer", v) } +} + +// StatsBwProto sets the proto option. +// Specify a protocol to print bandwidth for. +func StatsBwProto(v string) StatsBwOption { + return func(rb RequestBuilder) { rb.Option("proto", v) } +} + +// StatsBwPoll sets the poll option. +// Print bandwidth at an interval. +func StatsBwPoll(v bool) StatsBwOption { + return func(rb RequestBuilder) { rb.Option("poll", v) } +} + +// StatsBwInterval sets the interval option. +// Time interval to wait between updating output, if 'poll' is true. This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are: "ns", "us" (or "ยตs"), "ms", "s", "m", "h". Default: 1s. +func StatsBwInterval(v string) StatsBwOption { + return func(rb RequestBuilder) { rb.Option("interval", v) } +} + +// StatsBw print IPFS bandwidth information.. +func (a *HttpApi) StatsBw(ctx context.Context, opts ...StatsBwOption) iter.Seq2[StatsBwResponse, error] { + return func(yield func(StatsBwResponse, error) bool) { + req := a.Request("stats/bw") + for _, o := range opts { + o(req) + } + resp, err := req.Send(ctx) + if err != nil { + yield(StatsBwResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(StatsBwResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item StatsBwResponse + if err := dec.Decode(&item); err != nil { + yield(StatsBwResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// StatsDht returns statistics about the node's DHT(s).. +func (a *HttpApi) StatsDht(ctx context.Context, dht ...string) iter.Seq2[StatsDhtResponse, error] { + return func(yield func(StatsDhtResponse, error) bool) { + req := a.Request("stats/dht").Arguments(dht...) + resp, err := req.Send(ctx) + if err != nil { + yield(StatsDhtResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(StatsDhtResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item StatsDhtResponse + if err := dec.Decode(&item); err != nil { + yield(StatsDhtResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// StatsProvideOption configures the stats/provide command. +type StatsProvideOption func(RequestBuilder) + +// StatsProvideLan sets the lan option. +// Show stats for LAN DHT only (for Sweep+Dual DHT only). +func StatsProvideLan(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("lan", v) } +} + +// StatsProvideAll sets the all option. +// Display all provide sweep stats. +func StatsProvideAll(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// StatsProvideCompact sets the compact option. +// Display stats in 2-column layout (requires --all). +func StatsProvideCompact(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("compact", v) } +} + +// StatsProvideConnectivity sets the connectivity option. +// Display DHT connectivity status. +func StatsProvideConnectivity(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("connectivity", v) } +} + +// StatsProvideNetwork sets the network option. +// Display network stats (peers, reachability, region size). +func StatsProvideNetwork(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("network", v) } +} + +// StatsProvideSchedule sets the schedule option. +// Display reprovide schedule (CIDs/regions scheduled, next reprovide time). +func StatsProvideSchedule(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("schedule", v) } +} + +// StatsProvideTimings sets the timings option. +// Display timing information (uptime, cycle start, reprovide interval). +func StatsProvideTimings(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("timings", v) } +} + +// StatsProvideWorkers sets the workers option. +// Display worker pool stats (active/available/queued workers). +func StatsProvideWorkers(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("workers", v) } +} + +// StatsProvideOperations sets the operations option. +// Display operation stats (ongoing/past provides, rates, errors). +func StatsProvideOperations(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("operations", v) } +} + +// StatsProvideQueues sets the queues option. +// Display provide and reprovide queue sizes. +func StatsProvideQueues(v bool) StatsProvideOption { + return func(rb RequestBuilder) { rb.Option("queues", v) } +} + +// Deprecated: StatsProvide may be removed in a future release. +// StatsProvide deprecated command, use 'ipfs provide stat' instead.. +func (a *HttpApi) StatsProvide(ctx context.Context, opts ...StatsProvideOption) (*StatsProvideResponse, error) { + req := a.Request("stats/provide") + for _, o := range opts { + o(req) + } + var resp StatsProvideResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// StatsRepoOption configures the stats/repo command. +type StatsRepoOption func(RequestBuilder) + +// StatsRepoSizeOnly sets the size-only option. +// Only report RepoSize and StorageMax. +func StatsRepoSizeOnly(v bool) StatsRepoOption { + return func(rb RequestBuilder) { rb.Option("size-only", v) } +} + +// StatsRepoHuman sets the human option. +// Print sizes in human readable format (e.g., 1K 234M 2G). +func StatsRepoHuman(v bool) StatsRepoOption { + return func(rb RequestBuilder) { rb.Option("human", v) } +} + +// StatsRepo get stats for the currently used repo.. +func (a *HttpApi) StatsRepo(ctx context.Context, opts ...StatsRepoOption) (*StatsRepoResponse, error) { + req := a.Request("stats/repo") + for _, o := range opts { + o(req) + } + var resp StatsRepoResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// StatsReprovideOption configures the stats/reprovide command. +type StatsReprovideOption func(RequestBuilder) + +// StatsReprovideLan sets the lan option. +// Show stats for LAN DHT only (for Sweep+Dual DHT only). +func StatsReprovideLan(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("lan", v) } +} + +// StatsReprovideAll sets the all option. +// Display all provide sweep stats. +func StatsReprovideAll(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// StatsReprovideCompact sets the compact option. +// Display stats in 2-column layout (requires --all). +func StatsReprovideCompact(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("compact", v) } +} + +// StatsReprovideConnectivity sets the connectivity option. +// Display DHT connectivity status. +func StatsReprovideConnectivity(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("connectivity", v) } +} + +// StatsReprovideNetwork sets the network option. +// Display network stats (peers, reachability, region size). +func StatsReprovideNetwork(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("network", v) } +} + +// StatsReprovideSchedule sets the schedule option. +// Display reprovide schedule (CIDs/regions scheduled, next reprovide time). +func StatsReprovideSchedule(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("schedule", v) } +} + +// StatsReprovideTimings sets the timings option. +// Display timing information (uptime, cycle start, reprovide interval). +func StatsReprovideTimings(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("timings", v) } +} + +// StatsReprovideWorkers sets the workers option. +// Display worker pool stats (active/available/queued workers). +func StatsReprovideWorkers(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("workers", v) } +} + +// StatsReprovideOperations sets the operations option. +// Display operation stats (ongoing/past provides, rates, errors). +func StatsReprovideOperations(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("operations", v) } +} + +// StatsReprovideQueues sets the queues option. +// Display provide and reprovide queue sizes. +func StatsReprovideQueues(v bool) StatsReprovideOption { + return func(rb RequestBuilder) { rb.Option("queues", v) } +} + +// Deprecated: StatsReprovide may be removed in a future release. +// StatsReprovide deprecated command, use 'ipfs provide stat' instead.. +func (a *HttpApi) StatsReprovide(ctx context.Context, opts ...StatsReprovideOption) (*StatsReprovideResponse, error) { + req := a.Request("stats/reprovide") + for _, o := range opts { + o(req) + } + var resp StatsReprovideResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_swarm.go b/client/rpc/gen_swarm.go new file mode 100644 index 00000000000..647e3d221f5 --- /dev/null +++ b/client/rpc/gen_swarm.go @@ -0,0 +1,327 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "encoding/json" + "iter" +) + +type SwarmAddrsAutonatResponse struct { + Reachability string `json:"reachability"` + Reachable []string `json:"reachable,omitempty"` + Unreachable []string `json:"unreachable,omitempty"` + Unknown []string `json:"unknown,omitempty"` +} + +type SwarmAddrsListenResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmAddrsLocalResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmAddrsResponse struct { + Addrs map[string][]string `json:"Addrs,omitempty"` +} + +type SwarmConnectResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmDisconnectResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmFiltersAddResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmFiltersResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmFiltersRmResponse struct { + Strings []string `json:"Strings,omitempty"` +} + +type SwarmPeeringAddResponse struct { + ID string `json:"ID,omitempty"` + Status string `json:"Status,omitempty"` +} + +type SwarmPeeringLsResponse struct { + Peers []SwarmPeeringLsResponsePeers `json:"Peers,omitempty"` +} + +type SwarmPeeringLsResponsePeers struct { + ID string `json:"ID,omitempty"` + Addrs []string `json:"Addrs,omitempty"` +} + +type SwarmPeeringRmResponse struct { + ID string `json:"ID,omitempty"` + Status string `json:"Status,omitempty"` +} + +type SwarmPeersResponse struct { + Peers []SwarmPeersResponsePeers `json:"Peers,omitempty"` +} + +type SwarmPeersResponsePeers struct { + Addr string `json:",omitempty"` + Peer string `json:",omitempty"` + Latency string `json:",omitempty"` + Muxer string `json:",omitempty"` + Direction int `json:",omitempty"` + Streams []SwarmPeersResponsePeersStreams `json:",omitempty"` + Identify SwarmPeersResponsePeersIdentify `json:"Identify,omitempty"` +} + +type SwarmPeersResponsePeersIdentify struct { + ID string `json:"ID,omitempty"` + PublicKey string `json:"PublicKey,omitempty"` + Addresses []string `json:"Addresses,omitempty"` + AgentVersion string `json:"AgentVersion,omitempty"` + Protocols []string `json:"Protocols,omitempty"` +} + +type SwarmPeersResponsePeersStreams struct { + Protocol string `json:"Protocol,omitempty"` +} + +type SwarmResourcesResponse struct { + System SwarmResourcesResponseSystem `json:"System,omitempty"` + Transient json.RawMessage `json:"Transient,omitempty"` + Services map[string]json.RawMessage `json:",omitempty"` + Protocols map[string]json.RawMessage `json:",omitempty"` + Peers map[string]json.RawMessage `json:",omitempty"` +} + +type SwarmResourcesResponseSystem struct { + Memory int64 `json:"Memory,omitempty"` + MemoryUsage int64 `json:"MemoryUsage,omitempty"` + FD int `json:"FD,omitempty"` + FDUsage int `json:"FDUsage,omitempty"` + Conns int `json:"Conns,omitempty"` + ConnsUsage int `json:"ConnsUsage,omitempty"` + ConnsInbound int `json:"ConnsInbound,omitempty"` + ConnsInboundUsage int `json:"ConnsInboundUsage,omitempty"` + ConnsOutbound int `json:"ConnsOutbound,omitempty"` + ConnsOutboundUsage int `json:"ConnsOutboundUsage,omitempty"` + Streams int `json:"Streams,omitempty"` + StreamsUsage int `json:"StreamsUsage,omitempty"` + StreamsInbound int `json:"StreamsInbound,omitempty"` + StreamsInboundUsage int `json:"StreamsInboundUsage,omitempty"` + StreamsOutbound int `json:"StreamsOutbound,omitempty"` + StreamsOutboundUsage int `json:"StreamsOutboundUsage,omitempty"` +} + +// SwarmAddrs list known addresses. Useful for debugging.. +func (a *HttpApi) SwarmAddrs(ctx context.Context) (*SwarmAddrsResponse, error) { + req := a.Request("swarm/addrs") + var resp SwarmAddrsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmAddrsAutonat show address reachability as determined by AutoNAT V2.. +func (a *HttpApi) SwarmAddrsAutonat(ctx context.Context) (*SwarmAddrsAutonatResponse, error) { + req := a.Request("swarm/addrs/autonat") + var resp SwarmAddrsAutonatResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmAddrsListen list interface listening addresses.. +func (a *HttpApi) SwarmAddrsListen(ctx context.Context) (*SwarmAddrsListenResponse, error) { + req := a.Request("swarm/addrs/listen") + var resp SwarmAddrsListenResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmAddrsLocalOption configures the swarm/addrs/local command. +type SwarmAddrsLocalOption func(RequestBuilder) + +// SwarmAddrsLocalId sets the id option. +// Show peer ID in addresses. +func SwarmAddrsLocalId(v bool) SwarmAddrsLocalOption { + return func(rb RequestBuilder) { rb.Option("id", v) } +} + +// SwarmAddrsLocal list local addresses.. +func (a *HttpApi) SwarmAddrsLocal(ctx context.Context, opts ...SwarmAddrsLocalOption) (*SwarmAddrsLocalResponse, error) { + req := a.Request("swarm/addrs/local") + for _, o := range opts { + o(req) + } + var resp SwarmAddrsLocalResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmConnect open connection to a given peer.. +func (a *HttpApi) SwarmConnect(ctx context.Context, address ...string) (*SwarmConnectResponse, error) { + req := a.Request("swarm/connect").Arguments(address...) + var resp SwarmConnectResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmDisconnect close connection to a given address.. +func (a *HttpApi) SwarmDisconnect(ctx context.Context, address ...string) (*SwarmDisconnectResponse, error) { + req := a.Request("swarm/disconnect").Arguments(address...) + var resp SwarmDisconnectResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmFilters manipulate address filters.. +func (a *HttpApi) SwarmFilters(ctx context.Context) (*SwarmFiltersResponse, error) { + req := a.Request("swarm/filters") + var resp SwarmFiltersResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmFiltersAdd add an address filter.. +func (a *HttpApi) SwarmFiltersAdd(ctx context.Context, address ...string) (*SwarmFiltersAddResponse, error) { + req := a.Request("swarm/filters/add").Arguments(address...) + var resp SwarmFiltersAddResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmFiltersRm remove an address filter.. +func (a *HttpApi) SwarmFiltersRm(ctx context.Context, address ...string) (*SwarmFiltersRmResponse, error) { + req := a.Request("swarm/filters/rm").Arguments(address...) + var resp SwarmFiltersRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmPeeringAdd add peers into the peering subsystem.. +func (a *HttpApi) SwarmPeeringAdd(ctx context.Context, address ...string) iter.Seq2[SwarmPeeringAddResponse, error] { + return func(yield func(SwarmPeeringAddResponse, error) bool) { + req := a.Request("swarm/peering/add").Arguments(address...) + resp, err := req.Send(ctx) + if err != nil { + yield(SwarmPeeringAddResponse{}, err) + return + } + defer resp.Close() + if resp.Error != nil { + yield(SwarmPeeringAddResponse{}, resp.Error) + return + } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item SwarmPeeringAddResponse + if err := dec.Decode(&item); err != nil { + yield(SwarmPeeringAddResponse{}, err) + return + } + if !yield(item, nil) { + return + } + } + } +} + +// SwarmPeeringLs list peers registered in the peering subsystem.. +func (a *HttpApi) SwarmPeeringLs(ctx context.Context) (*SwarmPeeringLsResponse, error) { + req := a.Request("swarm/peering/ls") + var resp SwarmPeeringLsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmPeeringRm remove a peer from the peering subsystem.. +func (a *HttpApi) SwarmPeeringRm(ctx context.Context, ID ...string) (*SwarmPeeringRmResponse, error) { + req := a.Request("swarm/peering/rm").Arguments(ID...) + var resp SwarmPeeringRmResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// SwarmPeersOption configures the swarm/peers command. +type SwarmPeersOption func(RequestBuilder) + +// SwarmPeersVerbose sets the verbose option. +// display all extra information. +func SwarmPeersVerbose(v bool) SwarmPeersOption { + return func(rb RequestBuilder) { rb.Option("verbose", v) } +} + +// SwarmPeersStreams sets the streams option. +// Also list information about open streams for each peer. +func SwarmPeersStreams(v bool) SwarmPeersOption { + return func(rb RequestBuilder) { rb.Option("streams", v) } +} + +// SwarmPeersLatency sets the latency option. +// Also list information about latency to each peer. +func SwarmPeersLatency(v bool) SwarmPeersOption { + return func(rb RequestBuilder) { rb.Option("latency", v) } +} + +// SwarmPeersDirection sets the direction option. +// Also list information about the direction of connection. +func SwarmPeersDirection(v bool) SwarmPeersOption { + return func(rb RequestBuilder) { rb.Option("direction", v) } +} + +// SwarmPeersIdentify sets the identify option. +// Also list information about peers identify. +func SwarmPeersIdentify(v bool) SwarmPeersOption { + return func(rb RequestBuilder) { rb.Option("identify", v) } +} + +// SwarmPeers list peers with open connections.. +func (a *HttpApi) SwarmPeers(ctx context.Context, opts ...SwarmPeersOption) (*SwarmPeersResponse, error) { + req := a.Request("swarm/peers") + for _, o := range opts { + o(req) + } + var resp SwarmPeersResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// Experimental: SwarmResources is not yet stable. +// SwarmResources get a summary of all resources accounted for by the libp2p Resource Manager.. +func (a *HttpApi) SwarmResources(ctx context.Context) (*SwarmResourcesResponse, error) { + req := a.Request("swarm/resources") + var resp SwarmResourcesResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/gen_version.go b/client/rpc/gen_version.go new file mode 100644 index 00000000000..f59db6fcdaa --- /dev/null +++ b/client/rpc/gen_version.go @@ -0,0 +1,102 @@ +// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +) + +type VersionCheckResponse struct { + UpdateAvailable bool `json:"UpdateAvailable,omitempty"` + RunningVersion string `json:"RunningVersion,omitempty"` + GreatestVersion string `json:"GreatestVersion,omitempty"` + PeersSampled int `json:"PeersSampled,omitempty"` + WithGreaterVersion int `json:"WithGreaterVersion,omitempty"` +} + +type VersionDepsResponse struct { + Path string `json:"Path,omitempty"` + Version string `json:"Version,omitempty"` + ReplacedBy string `json:"ReplacedBy,omitempty"` + Sum string `json:"Sum,omitempty"` +} + +type VersionResponse struct { + Version string `json:"Version,omitempty"` + Commit string `json:"Commit,omitempty"` + Repo string `json:"Repo,omitempty"` + System string `json:"System,omitempty"` + Golang string `json:"Golang,omitempty"` +} + +// VersionOption configures the version command. +type VersionOption func(RequestBuilder) + +// VersionNumber sets the number option. +// Only show the version number. +func VersionNumber(v bool) VersionOption { + return func(rb RequestBuilder) { rb.Option("number", v) } +} + +// VersionCommit sets the commit option. +// Show the commit hash. +func VersionCommit(v bool) VersionOption { + return func(rb RequestBuilder) { rb.Option("commit", v) } +} + +// VersionRepo sets the repo option. +// Show repo version. +func VersionRepo(v bool) VersionOption { + return func(rb RequestBuilder) { rb.Option("repo", v) } +} + +// VersionAll sets the all option. +// Show all version information. +func VersionAll(v bool) VersionOption { + return func(rb RequestBuilder) { rb.Option("all", v) } +} + +// Version show IPFS version information.. +func (a *HttpApi) Version(ctx context.Context, opts ...VersionOption) (*VersionResponse, error) { + req := a.Request("version") + for _, o := range opts { + o(req) + } + var resp VersionResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// VersionCheckOption configures the version/check command. +type VersionCheckOption func(RequestBuilder) + +// VersionCheckMinPercent sets the min-percent option. +// Percentage (1-100) of sampled peers with the new Kubo version needed to trigger an update warning. Default: 5. +func VersionCheckMinPercent(v int) VersionCheckOption { + return func(rb RequestBuilder) { rb.Option("min-percent", v) } +} + +// VersionCheck checks Kubo version against connected peers.. +func (a *HttpApi) VersionCheck(ctx context.Context, opts ...VersionCheckOption) (*VersionCheckResponse, error) { + req := a.Request("version/check") + for _, o := range opts { + o(req) + } + var resp VersionCheckResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +// VersionDeps shows information about dependencies used for build.. +func (a *HttpApi) VersionDeps(ctx context.Context) (*VersionDepsResponse, error) { + req := a.Request("version/deps") + var resp VersionDepsResponse + if err := req.Exec(ctx, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/client/rpc/key.go b/client/rpc/key.go index a38c0962a2b..c1c86580d7a 100644 --- a/client/rpc/key.go +++ b/client/rpc/key.go @@ -13,6 +13,8 @@ import ( "github.com/multiformats/go-multibase" ) +// Deprecated: use HttpApi.KeyGen, HttpApi.KeyLs, HttpApi.KeyRm, HttpApi.KeyRename, HttpApi.KeySign, HttpApi.KeyVerify instead. +// This type implements the legacy CoreAPI KeyAPI interface and will be removed in a future release. type KeyAPI HttpApi type key struct { diff --git a/client/rpc/name.go b/client/rpc/name.go index 023f0cde808..bd4ae9e2473 100644 --- a/client/rpc/name.go +++ b/client/rpc/name.go @@ -13,6 +13,8 @@ import ( caopts "github.com/ipfs/kubo/core/coreiface/options" ) +// Deprecated: use HttpApi.NamePublish, HttpApi.NameResolve instead. +// This type implements the legacy CoreAPI NameAPI interface and will be removed in a future release. type NameAPI HttpApi type ipnsEntry struct { diff --git a/client/rpc/object.go b/client/rpc/object.go index 5c9d323e87b..b1373e1f7ce 100644 --- a/client/rpc/object.go +++ b/client/rpc/object.go @@ -9,6 +9,8 @@ import ( caopts "github.com/ipfs/kubo/core/coreiface/options" ) +// Deprecated: use HttpApi.ObjectPatchAddLink, HttpApi.ObjectPatchRmLink, HttpApi.ObjectDiff instead. +// This type implements the legacy CoreAPI ObjectAPI interface and will be removed in a future release. type ObjectAPI HttpApi type objectOut struct { diff --git a/client/rpc/pin.go b/client/rpc/pin.go index 10a9f38b642..1aa11391e9a 100644 --- a/client/rpc/pin.go +++ b/client/rpc/pin.go @@ -13,6 +13,8 @@ import ( caopts "github.com/ipfs/kubo/core/coreiface/options" ) +// Deprecated: use HttpApi.PinAdd, HttpApi.PinLs, HttpApi.PinRm, HttpApi.PinUpdate, HttpApi.PinVerify instead. +// This type implements the legacy CoreAPI PinAPI interface and will be removed in a future release. type PinAPI HttpApi type pinRefKeyObject struct { diff --git a/client/rpc/pubsub.go b/client/rpc/pubsub.go index d12d7a5de21..476cb0acde8 100644 --- a/client/rpc/pubsub.go +++ b/client/rpc/pubsub.go @@ -12,6 +12,8 @@ import ( mbase "github.com/multiformats/go-multibase" ) +// Deprecated: use HttpApi.PubsubLs, HttpApi.PubsubPeers, HttpApi.PubsubPub, HttpApi.PubsubSub instead. +// This type implements the legacy CoreAPI PubSubAPI interface and will be removed in a future release. type PubsubAPI HttpApi func (api *PubsubAPI) Ls(ctx context.Context) ([]string, error) { diff --git a/client/rpc/routing.go b/client/rpc/routing.go index 693f155c6b0..31e3837eaec 100644 --- a/client/rpc/routing.go +++ b/client/rpc/routing.go @@ -12,6 +12,8 @@ import ( "github.com/libp2p/go-libp2p/core/routing" ) +// Deprecated: use HttpApi.RoutingGet, HttpApi.RoutingPut, HttpApi.RoutingFindpeer, HttpApi.RoutingFindprovs, HttpApi.RoutingProvide instead. +// This type implements the legacy CoreAPI RoutingAPI interface and will be removed in a future release. type RoutingAPI HttpApi func (api *RoutingAPI) Get(ctx context.Context, key string) ([]byte, error) { diff --git a/client/rpc/swarm.go b/client/rpc/swarm.go index d54d06604e8..c2026778c44 100644 --- a/client/rpc/swarm.go +++ b/client/rpc/swarm.go @@ -11,6 +11,8 @@ import ( "github.com/multiformats/go-multiaddr" ) +// Deprecated: use HttpApi.SwarmPeers, HttpApi.SwarmConnect, HttpApi.SwarmDisconnect, HttpApi.SwarmAddrs instead. +// This type implements the legacy CoreAPI SwarmAPI interface and will be removed in a future release. type SwarmAPI HttpApi func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error { diff --git a/client/rpc/unixfs.go b/client/rpc/unixfs.go index 316cc21a8ec..d9a9120c099 100644 --- a/client/rpc/unixfs.go +++ b/client/rpc/unixfs.go @@ -26,6 +26,8 @@ type addEvent struct { Size string `json:",omitempty"` } +// Deprecated: use HttpApi.Add, HttpApi.Cat, HttpApi.Get, HttpApi.Ls instead. +// This type implements the legacy CoreAPI UnixfsAPI interface and will be removed in a future release. type UnixfsAPI HttpApi func (api *UnixfsAPI) Add(ctx context.Context, f files.Node, opts ...caopts.UnixfsAddOption) (path.ImmutablePath, error) { diff --git a/core/commands/add.go b/core/commands/add.go index 2d47fa811ff..73b0facf748 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -801,5 +801,6 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#import } }, }, - Type: AddEvent{}, + Type: AddEvent{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } diff --git a/core/commands/cmdutils/utils.go b/core/commands/cmdutils/utils.go index e93e21e379c..5a68d7f5d39 100644 --- a/core/commands/cmdutils/utils.go +++ b/core/commands/cmdutils/utils.go @@ -97,3 +97,50 @@ func CloneAddrInfo(ai peer.AddrInfo) peer.AddrInfo { Addrs: slices.Clone(ai.Addrs), } } + +// ResponseKind describes how a command's HTTP response should be consumed +// by the generated RPC client. +type ResponseKind int + +const ( + // ResponseSingle means the command returns a single JSON object. + ResponseSingle ResponseKind = iota + // ResponseStream means the command returns newline-delimited JSON objects. + ResponseStream + // ResponseBinary means the command returns raw bytes (e.g., file data, tar). + ResponseBinary +) + +type responseKindKey struct{} + +// SetResponseKind annotates a command with its response kind for the RPC +// client generator. Use with CreateCmdExtras. +func SetResponseKind(kind ResponseKind) func(e *cmds.Extra) { + return func(e *cmds.Extra) { + e.SetValue(responseKindKey{}, kind) + } +} + +// GetResponseKind returns the ResponseKind for a command. If not explicitly +// set, it infers the kind: commands with a Type field default to +// ResponseSingle, commands without default to ResponseBinary. +func GetResponseKind(cmd *cmds.Command) ResponseKind { + if cmd.Extra != nil { + if val, found := cmd.Extra.GetValue(responseKindKey{}); found { + return val.(ResponseKind) + } + } + if cmd.Type != nil { + return ResponseSingle + } + return ResponseBinary +} + +// CreateCmdExtras builds an *cmds.Extra from a set of option functions. +func CreateCmdExtras(opts ...func(e *cmds.Extra)) *cmds.Extra { + e := new(cmds.Extra) + for _, o := range opts { + o(e) + } + return e +} diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index a256213ecd0..8a52afa996b 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -219,8 +219,9 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/ cmds.BoolOption(fastProvideWaitOptionName, "Block until the immediate provide completes before returning. Default: Import.FastProvideWait"), cmdutils.AllowBigBlockOption, }, - Type: CarImportOutput{}, - Run: dagImport, + Type: CarImportOutput{}, + Run: dagImport, + Extra: cmdutils.CreateCmdExtras(cmdutils.SetResponseKind(cmdutils.ResponseStream)), Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, event *CarImportOutput) error { silent, _ := req.Options[silentOptionName].(bool) diff --git a/core/commands/dht.go b/core/commands/dht.go index b246a78cc44..be4a5f8e9d5 100644 --- a/core/commands/dht.go +++ b/core/commands/dht.go @@ -119,7 +119,8 @@ var queryDhtCmd = &cmds.Command{ return printEvent(out, w, verbose, pfm) }), }, - Type: routing.QueryEvent{}, + Type: routing.QueryEvent{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var RemovedDHTCmd = &cmds.Command{ Status: cmds.Removed, diff --git a/core/commands/extra.go b/core/commands/extra.go index 0d7ca9b4b63..7ae4a502944 100644 --- a/core/commands/extra.go +++ b/core/commands/extra.go @@ -2,14 +2,11 @@ package commands import ( cmds "github.com/ipfs/go-ipfs-cmds" + "github.com/ipfs/kubo/core/commands/cmdutils" ) func CreateCmdExtras(opts ...func(e *cmds.Extra)) *cmds.Extra { - e := new(cmds.Extra) - for _, o := range opts { - o(e) - } - return e + return cmdutils.CreateCmdExtras(opts...) } type doesNotUseRepo struct{} @@ -65,3 +62,22 @@ func getBoolFlag(e *cmds.Extra, key any) (val bool, found bool) { val = ival.(bool) return val, found } + +// ResponseKind describes how a command's HTTP response should be consumed +// by the generated RPC client. +type ResponseKind = cmdutils.ResponseKind + +const ( + ResponseSingle = cmdutils.ResponseSingle + ResponseStream = cmdutils.ResponseStream + ResponseBinary = cmdutils.ResponseBinary +) + +// SetResponseKind annotates a command with its response kind for the RPC +// client generator. Use with CreateCmdExtras. +var SetResponseKind = cmdutils.SetResponseKind + +// GetResponseKind returns the ResponseKind for a command. If not explicitly +// set, it infers the kind: commands with a Type field default to +// ResponseSingle, commands without default to ResponseBinary. +var GetResponseKind = cmdutils.GetResponseKind diff --git a/core/commands/log.go b/core/commands/log.go index 0ebb1ac4379..54c493c4f25 100644 --- a/core/commands/log.go +++ b/core/commands/log.go @@ -279,4 +279,5 @@ This will only return 'info' logs from bitswap and skip 'debug'. }() return res.Emit(pipeReader) }, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } diff --git a/core/commands/ls.go b/core/commands/ls.go index 1f54753f1bf..2d91f816fde 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -233,7 +233,8 @@ The JSON output contains type information. return nil }), }, - Type: LsOutput{}, + Type: LsOutput{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } // formatMode converts os.FileMode to a 10-character Unix ls-style string. diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index cab868c3093..646d05f81d6 100644 --- a/core/commands/pin/pin.go +++ b/core/commands/pin/pin.go @@ -90,7 +90,8 @@ It may take some time. Pass '--progress' to track the progress. cmds.StringOption(pinNameOptionName, "n", "An optional name for created pin(s)."), cmds.BoolOption(pinProgressOptionName, "Show progress"), }, - Type: AddPinOutput{}, + Type: AddPinOutput{}, + Extra: cmdutils.CreateCmdExtras(cmdutils.SetResponseKind(cmdutils.ResponseStream)), Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) if err != nil { @@ -434,7 +435,8 @@ Example: return nil }, - Type: PinLsOutputWrapper{}, + Type: PinLsOutputWrapper{}, + Extra: cmdutils.CreateCmdExtras(cmdutils.SetResponseKind(cmdutils.ResponseStream)), Encoders: cmds.EncoderMap{ cmds.JSON: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out PinLsOutputWrapper) error { stream, _ := req.Options[pinStreamOptionName].(bool) @@ -712,7 +714,8 @@ var verifyPinCmd = &cmds.Command{ } return res.Emit(out) }, - Type: PinVerifyRes{}, + Type: PinVerifyRes{}, + Extra: cmdutils.CreateCmdExtras(cmdutils.SetResponseKind(cmdutils.ResponseStream)), Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *PinVerifyRes) error { quiet, _ := req.Options[pinQuietOptionName].(bool) diff --git a/core/commands/ping.go b/core/commands/ping.go index d9cd427e81d..22f17205a1b 100644 --- a/core/commands/ping.go +++ b/core/commands/ping.go @@ -150,7 +150,8 @@ trip latency information. Text: fmt.Sprintf("Average latency: %.2fms", averagems), }) }, - Type: PingResult{}, + Type: PingResult{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), PostRun: cmds.PostRunMap{ cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error { var ( diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index e2efd35e6bb..7e281a945d2 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -152,7 +152,8 @@ TOPIC AND DATA ENCODING return errors.New("--enc=lenpayload was removed, use --enc=json instead") }), }, - Type: pubsubMessage{}, + Type: pubsubMessage{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var PubsubPubCmd = &cmds.Command{ diff --git a/core/commands/refs.go b/core/commands/refs.go index 53c92c3df04..66545b15c3d 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -132,6 +132,7 @@ NOTE: Like most other commands, Kubo will try to fetch the blocks of the passed }, Encoders: refsEncoderMap, Type: RefWrapper{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var RefsLocalCmd = &cmds.Command{ @@ -166,6 +167,7 @@ Displays the hashes of all local objects. NOTE: This treats all local objects as }, Encoders: refsEncoderMap, Type: RefWrapper{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } func objectsForPaths(ctx context.Context, n iface.CoreAPI, paths []string) ([]cid.Cid, error) { diff --git a/core/commands/repo.go b/core/commands/repo.go index 14956ec7c5d..8e92ae6769d 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -120,7 +120,8 @@ order to reclaim hard disk space. return nil }, - Type: GcResult{}, + Type: GcResult{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, gcr *GcResult) error { quiet, _ := req.Options[repoQuietOptionName].(bool) @@ -547,7 +548,8 @@ repository before using these options. return res.Emit(&VerifyProgress{Msg: "verify complete, all blocks validated."}) }, - Type: &VerifyProgress{}, + Type: &VerifyProgress{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, obj *VerifyProgress) error { if strings.Contains(obj.Msg, "was corrupt") { diff --git a/core/commands/routing.go b/core/commands/routing.go index 629c3051527..0b4781a6fd9 100644 --- a/core/commands/routing.go +++ b/core/commands/routing.go @@ -134,7 +134,8 @@ var findProvidersRoutingCmd = &cmds.Command{ return printEvent(out, w, verbose, pfm) }), }, - Type: routing.QueryEvent{}, + Type: routing.QueryEvent{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } const ( @@ -265,7 +266,8 @@ var provideRefRoutingCmd = &cmds.Command{ return printEvent(out, w, verbose, pfm) }), }, - Type: routing.QueryEvent{}, + Type: routing.QueryEvent{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var reprovideRoutingCmd = &cmds.Command{ @@ -411,7 +413,8 @@ var findPeerRoutingCmd = &cmds.Command{ return printEvent(out, w, verbose, pfm) }), }, - Type: routing.QueryEvent{}, + Type: routing.QueryEvent{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var getValueRoutingCmd = &cmds.Command{ diff --git a/core/commands/stat.go b/core/commands/stat.go index 2b4485a9513..d4e49bf893a 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -155,7 +155,8 @@ Example: } } }, - Type: metrics.Stats{}, + Type: metrics.Stats{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), PostRun: cmds.PostRunMap{ cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error { polling, _ := res.Request().Options[statPollOptionName].(bool) diff --git a/core/commands/stat_dht.go b/core/commands/stat_dht.go index 4c63b135502..a937c5a1134 100644 --- a/core/commands/stat_dht.go +++ b/core/commands/stat_dht.go @@ -248,5 +248,6 @@ This interface is not stable and may change from release to release. return nil }), }, - Type: dhtStat{}, + Type: dhtStat{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } diff --git a/core/commands/swarm.go b/core/commands/swarm.go index a29acf0b914..eb762d7af73 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -150,7 +150,8 @@ var swarmPeeringAddCmd = &cmds.Command{ return nil }), }, - Type: peeringResult{}, + Type: peeringResult{}, + Extra: CreateCmdExtras(SetResponseKind(ResponseStream)), } var swarmPeeringLsCmd = &cmds.Command{ diff --git a/docs/changelogs/v0.41.md b/docs/changelogs/v0.41.md index 85856a01a9b..5158a4b3a88 100644 --- a/docs/changelogs/v0.41.md +++ b/docs/changelogs/v0.41.md @@ -10,6 +10,8 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team. - [Overview](#overview) - [๐Ÿ”ฆ Highlights](#-highlights) + - [Auto-generated HTTP RPC client (`client/rpc`)](#auto-generated-http-rpc-client-clientrpc) + - [๐Ÿ“ฆ๏ธ Dependency updates](#-dependency-updates) - [๐Ÿ“ Changelog](#-changelog) - [๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors](#-contributors) @@ -17,6 +19,35 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team. ### ๐Ÿ”ฆ Highlights +#### Auto-generated HTTP RPC client (`client/rpc`) + +You can now call any Kubo command from Go without manually wiring HTTP requests. +The `client/rpc` package includes typed methods for all Kubo commands, generated +directly from command definitions. When Kubo adds a command, the client updates +automatically. + +**What changed**: `HttpApi` now has methods like `PinAdd`, `DagStat`, `SwarmPeers`, +etc. for every HTTP-accessible command. Each method has typed options and response +structs, with streaming commands returning `iter.Seq2[T, error]`. + +```go +// before: manually construct requests +req := api.Request("pin/add", path) +req.Option("recursive", true) + +// after: typed method with functional options +for resp, err := range api.PinAdd(ctx, []string{path}, PinAddRecursive(true)) { + // handle resp.Pins, resp.Progress, resp.Bytes +} +``` + +**CI guard**: `make rpc_client_check` detects when commands change and fails +the PR if the generated client is stale. Run `make rpc_client` to regenerate. + +**Backward compatibility**: The old `CoreAPI` interface methods (`api.Pin().Add(...)`, +`api.Block().Get(...)`, etc.) still work but are deprecated. Migrate to the new +direct methods on `HttpApi` at your convenience. + #### ๐Ÿ“ฆ๏ธ Dependency updates - update `gateway-conformance` tests to [v0.11](https://github.com/ipfs/gateway-conformance/releases/tag/v0.11.0) diff --git a/tools/gen-rpc-client/generate.go b/tools/gen-rpc-client/generate.go new file mode 100644 index 00000000000..d8da9824f6d --- /dev/null +++ b/tools/gen-rpc-client/generate.go @@ -0,0 +1,373 @@ +package main + +import ( + "bytes" + "fmt" + "go/format" + "reflect" + "strings" + "text/template" + "unicode" + + cmds "github.com/ipfs/go-ipfs-cmds" +) + +// fileData holds all data needed to render one gen_*.go file. +type fileData struct { + GroupName string + Types []TypeInfo + Commands []CommandInfo + NeedsIO bool + NeedsJSON bool + NeedsIter bool +} + +// makeFuncMap returns the template function map with all real implementations. +func makeFuncMap() template.FuncMap { + return template.FuncMap{ + "responseTypeName": responseTypeName, + "optionTypes": renderOptionTypes, + "methodFunc": renderMethod, + "argParams": argParams, + "argValues": argValues, + "returnType": returnType, + "streamReturnType": streamReturnType, + "streamItemType": streamItemType, + "streamZero": streamZero, + "hasStructResponse": hasStructResponse, + "hasSliceResponse": hasSliceResponse, + "fileBodySetup": fileBodySetup, + "toLower": toLowerFirst, + "sanitizeDescription": sanitizeDescription, + "hasPrimitiveResponse": hasPrimitiveResponse, + } +} + +// parseTmpl parses a template string with the real function map. +func parseTmpl(name, src string) *template.Template { + return template.Must(template.New(name).Funcs(makeFuncMap()).Parse(src)) +} + +// generateFiles produces a map of filename -> content for all generated files. +func generateFiles(commands []CommandInfo) (map[string][]byte, error) { + groups := groupCommands(commands) + + files := make(map[string][]byte) + for groupName, cmds := range groups { + content, err := generateGroupFile(groupName, cmds) + if err != nil { + return nil, fmt.Errorf("generating %s: %w", groupName, err) + } + fileName := fmt.Sprintf("gen_%s.go", groupName) + files[fileName] = content + } + return files, nil +} + +// groupCommands groups commands by their first path segment. +func groupCommands(commands []CommandInfo) map[string][]CommandInfo { + groups := make(map[string][]CommandInfo) + for _, cmd := range commands { + groups[cmd.GroupName] = append(groups[cmd.GroupName], cmd) + } + return groups +} + +// generateGroupFile generates one gen_*.go file for a command group. +func generateGroupFile(groupName string, commands []CommandInfo) ([]byte, error) { + var allTypes []TypeInfo + needsIO := false + needsJSON := false + needsIter := false + + for _, cmd := range commands { + if cmd.ResponseType != nil { + types := reflectResponseType(cmd.GoName, cmd.ResponseType) + allTypes = append(allTypes, types...) + } + switch cmd.ResponseKind { + case ResponseStream: + needsJSON = true + needsIter = true + } + if cmd.HasFileArg { + needsIO = true + } + } + + allTypes = deduplicateTypes(allTypes) + sortTypes(allTypes) + + if needsJSONImport(allTypes) { + needsJSON = true + } + + data := fileData{ + GroupName: groupName, + Types: allTypes, + Commands: commands, + NeedsIO: needsIO, + NeedsJSON: needsJSON, + NeedsIter: needsIter, + } + + tmpl := parseTmpl("file", fileTemplateStr) + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, data); err != nil { + return nil, fmt.Errorf("executing template: %w", err) + } + + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return nil, fmt.Errorf("formatting generated code for %s: %w\n--- raw source ---\n%s", groupName, err, buf.String()) + } + return formatted, nil +} + +// renderOptionTypes renders the option type and funcs for a command. +func renderOptionTypes(cmd CommandInfo) string { + tmpl := parseTmpl("optTypes", optionTypesTemplateStr) + var buf bytes.Buffer + if err := tmpl.Execute(&buf, cmd); err != nil { + panic(fmt.Sprintf("optionTypes template: %v", err)) + } + return buf.String() +} + +// renderMethod renders the method func for a command based on its ResponseKind. +func renderMethod(cmd CommandInfo) string { + var tmplStr string + + switch cmd.ResponseKind { + case ResponseStream: + tmplStr = streamMethodTemplateStr + case ResponseBinary: + tmplStr = binaryMethodTemplateStr + default: // ResponseSingle + if cmd.ResponseType == nil { + tmplStr = voidMethodTemplateStr + } else if hasPrimitiveResponse(cmd) { + // primitives, maps, interfaces - return *Response for manual decoding + tmplStr = binaryMethodTemplateStr + } else { + tmplStr = singleMethodTemplateStr + } + } + + tmpl := parseTmpl("method", tmplStr) + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, cmd); err != nil { + panic(fmt.Sprintf("method template for %s: %v", cmd.Path, err)) + } + return buf.String() +} + +// argParams generates the function parameter list for positional arguments. +func argParams(cmd CommandInfo) string { + var parts []string + hasVariadic := false + for _, arg := range cmd.Arguments { + if arg.IsFile { + parts = append(parts, fmt.Sprintf(", %s io.Reader", sanitizeArgName(arg.Name))) + } else if arg.Variadic { + hasVariadic = true + // variadic args can't be in the middle, handle via options + } else { + parts = append(parts, fmt.Sprintf(", %s string", sanitizeArgName(arg.Name))) + } + } + // if we have variadic string args AND options, the variadic must come + // as a slice since Go only allows one variadic param at the end + if hasVariadic && len(cmd.Options) > 0 { + for _, arg := range cmd.Arguments { + if arg.Variadic && !arg.IsFile { + parts = append(parts, fmt.Sprintf(", %s []string", sanitizeArgName(arg.Name))) + } + } + } else if hasVariadic { + for _, arg := range cmd.Arguments { + if arg.Variadic && !arg.IsFile { + parts = append(parts, fmt.Sprintf(", %s ...string", sanitizeArgName(arg.Name))) + } + } + } + return strings.Join(parts, "") +} + +// argValues generates the argument values passed to Request(). +func argValues(cmd CommandInfo) string { + var stringArgs []string + hasVariadic := false + + for _, arg := range cmd.Arguments { + if arg.IsFile { + continue + } + if arg.Variadic { + hasVariadic = true + continue + } + stringArgs = append(stringArgs, sanitizeArgName(arg.Name)) + } + + result := "" + if len(stringArgs) > 0 { + result = ", " + strings.Join(stringArgs, ", ") + } + + // handle variadic: append via .Arguments() + if hasVariadic { + for _, arg := range cmd.Arguments { + if arg.Variadic && !arg.IsFile { + name := sanitizeArgName(arg.Name) + result += fmt.Sprintf(").Arguments(%s...", name) + } + } + } + + return result +} + +// returnType generates the return type for a single-response method. +func returnType(cmd CommandInfo) string { + rt := responseTypeName(cmd) + if rt == "" { + return "error" + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.Slice { + return rt + ", error" + } + return "*" + rt + ", error" +} + +// streamReturnType generates the return type for a streaming method. +func streamReturnType(cmd CommandInfo) string { + item := streamItemType(cmd) + return fmt.Sprintf("iter.Seq2[%s, error]", item) +} + +// streamItemType returns the type of each streamed item. +func streamItemType(cmd CommandInfo) string { + rt := responseTypeName(cmd) + if rt == "" { + return "json.RawMessage" + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.Slice { + elem := t.Elem() + for elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + if elem.Kind() == reflect.Struct { + return cmd.GoName + "Item" + } + } + if t.Kind() == reflect.Struct { + return cmd.GoName + "Response" + } + return "json.RawMessage" +} + +// streamZero returns the zero value expression for the stream item type. +func streamZero(cmd CommandInfo) string { + item := streamItemType(cmd) + if item == "json.RawMessage" { + return "nil" + } + return item + "{}" +} + +// hasStructResponse returns true if the response is a struct (not slice). +func hasStructResponse(cmd CommandInfo) bool { + if cmd.ResponseType == nil { + return false + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Kind() == reflect.Struct +} + +// hasSliceResponse returns true if the response is a slice. +func hasSliceResponse(cmd CommandInfo) bool { + if cmd.ResponseType == nil { + return false + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Kind() == reflect.Slice +} + +// hasPrimitiveResponse returns true if the response is a primitive, map, or other non-struct/non-slice type. +func hasPrimitiveResponse(cmd CommandInfo) bool { + if cmd.ResponseType == nil { + return false + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Kind() != reflect.Struct && t.Kind() != reflect.Slice +} + +// fileBodySetup generates the FileBody call for file arguments. +func fileBodySetup(cmd CommandInfo) string { + for _, arg := range cmd.Arguments { + if arg.IsFile { + return fmt.Sprintf("req = req.FileBody(%s).(RequestBuilder)", sanitizeArgName(arg.Name)) + } + } + return "" +} + +// sanitizeDescription cleans a description string for use in Go comments. +// Replaces newlines with spaces and trims trailing whitespace. +func sanitizeDescription(s string) string { + s = strings.ReplaceAll(s, "\n", " ") + s = strings.ReplaceAll(s, "\r", "") + return strings.TrimSpace(s) +} + +// sanitizeArgName converts argument names to valid Go identifiers. +func sanitizeArgName(name string) string { + name = strings.NewReplacer("-", "_", ".", "_", " ", "_").Replace(name) + switch name { + case "type", "func", "var", "const", "map", "range", "chan", "select", "default", "interface": + return name + "Arg" + } + return name +} + +// toLowerFirst lowercases the first letter of a string. +func toLowerFirst(s string) string { + if s == "" { + return s + } + r := []rune(s) + r[0] = unicode.ToLower(r[0]) + return string(r) +} + +// statusComment returns a deprecation/experimental comment prefix. +func statusComment(s cmds.Status) string { + switch s { + case cmds.Deprecated: + return "Deprecated" + case cmds.Experimental: + return "Experimental" + default: + return "" + } +} diff --git a/tools/gen-rpc-client/generate_test.go b/tools/gen-rpc-client/generate_test.go new file mode 100644 index 00000000000..0b10eac3167 --- /dev/null +++ b/tools/gen-rpc-client/generate_test.go @@ -0,0 +1,318 @@ +package main + +import ( + "os" + "os/exec" + "path/filepath" + "reflect" + "strings" + "testing" + + corecmds "github.com/ipfs/kubo/core/commands" +) + +func TestPathToGoName(t *testing.T) { + tests := []struct { + path string + want string + }{ + {"pin/add", "PinAdd"}, + {"pin/remote/add", "PinRemoteAdd"}, + {"version", "Version"}, + {"swarm/peers", "SwarmPeers"}, + {"stats/bw", "StatsBw"}, + {"dag/import", "DagImport"}, + } + for _, tt := range tests { + got := pathToGoName(tt.path) + if got != tt.want { + t.Errorf("pathToGoName(%q) = %q, want %q", tt.path, got, tt.want) + } + } +} + +func TestToPascalCase(t *testing.T) { + tests := []struct { + input string + want string + }{ + {"find-provs", "FindProvs"}, + {"bw", "Bw"}, + {"add", "Add"}, + {"cid-base", "CidBase"}, + {"repo-dir", "RepoDir"}, + {"resolve-type", "ResolveType"}, + {"num_providers", "NumProviders"}, + } + for _, tt := range tests { + got := toPascalCase(tt.input) + if got != tt.want { + t.Errorf("toPascalCase(%q) = %q, want %q", tt.input, got, tt.want) + } + } +} + +func TestGroupName(t *testing.T) { + tests := []struct { + path string + want string + }{ + {"pin/add", "pin"}, + {"version", "version"}, + {"pin/remote/add", "pin"}, + {"dag/stat", "dag"}, + } + for _, tt := range tests { + got := groupName(tt.path) + if got != tt.want { + t.Errorf("groupName(%q) = %q, want %q", tt.path, got, tt.want) + } + } +} + +func TestSanitizeArgName(t *testing.T) { + tests := []struct { + input string + want string + }{ + {"ipfs-path", "ipfs_path"}, + {"object data", "object_data"}, + {"type", "typeArg"}, + {"key.name", "key_name"}, + {"normal", "normal"}, + } + for _, tt := range tests { + got := sanitizeArgName(tt.input) + if got != tt.want { + t.Errorf("sanitizeArgName(%q) = %q, want %q", tt.input, got, tt.want) + } + } +} + +func TestSanitizeDescription(t *testing.T) { + got := sanitizeDescription("line one\nline two\nline three") + want := "line one line two line three" + if got != want { + t.Errorf("sanitizeDescription = %q, want %q", got, want) + } +} + +func TestWalkCommandTree(t *testing.T) { + commands := walkCommandTree(corecmds.Root, "") + + if len(commands) == 0 { + t.Fatal("walkCommandTree returned no commands") + } + + // check some commands that must be present + found := make(map[string]bool) + for _, cmd := range commands { + found[cmd.Path] = true + } + + mustExist := []string{ + "pin/add", "pin/ls", "pin/rm", + "block/get", "block/put", "block/stat", + "version", "id", "cat", + "swarm/peers", "swarm/connect", + } + for _, path := range mustExist { + if !found[path] { + t.Errorf("expected command %q not found in walk results", path) + } + } + + // verify no removed commands leak through + for _, cmd := range commands { + if cmd.GoName == "" { + t.Errorf("command %q has empty GoName", cmd.Path) + } + if cmd.GroupName == "" { + t.Errorf("command %q has empty GroupName", cmd.Path) + } + } +} + +func TestWalkExcludesGlobalOptions(t *testing.T) { + commands := walkCommandTree(corecmds.Root, "") + + for _, cmd := range commands { + for _, opt := range cmd.Options { + if isGlobalOption(opt.Name) { + t.Errorf("command %q includes global option %q", cmd.Path, opt.Name) + } + } + } +} + +func TestReflectResponseType(t *testing.T) { + type Simple struct { + Name string `json:"Name,omitempty"` + Size int `json:"Size,omitempty"` + } + + types := reflectResponseType("Test", reflect.TypeOf(Simple{})) + if len(types) == 0 { + t.Fatal("reflectResponseType returned no types") + } + if types[0].Name != "TestResponse" { + t.Errorf("type name = %q, want %q", types[0].Name, "TestResponse") + } + if len(types[0].Fields) != 2 { + t.Errorf("field count = %d, want 2", len(types[0].Fields)) + } + + fieldNames := make(map[string]bool) + for _, f := range types[0].Fields { + fieldNames[f.Name] = true + } + if !fieldNames["Name"] || !fieldNames["Size"] { + t.Errorf("expected fields Name and Size, got %v", fieldNames) + } +} + +func TestReflectResponseTypeNil(t *testing.T) { + types := reflectResponseType("Test", nil) + if types != nil { + t.Errorf("expected nil for nil input, got %v", types) + } +} + +func TestGenerateFiles(t *testing.T) { + commands := walkCommandTree(corecmds.Root, "") + files, err := generateFiles(commands) + if err != nil { + t.Fatalf("generateFiles failed: %v", err) + } + + if len(files) == 0 { + t.Fatal("generateFiles produced no files") + } + + // every file should have the generated header + for name, content := range files { + if !strings.HasPrefix(name, "gen_") { + t.Errorf("file %q does not start with gen_", name) + } + if !strings.HasSuffix(name, ".go") { + t.Errorf("file %q does not end with .go", name) + } + if !strings.Contains(string(content), "Code generated by tools/gen-rpc-client; DO NOT EDIT.") { + t.Errorf("file %q missing generation header", name) + } + if !strings.Contains(string(content), "package rpc") { + t.Errorf("file %q missing package declaration", name) + } + } + + // verify well-known files exist + for _, name := range []string{"gen_pin.go", "gen_block.go", "gen_version.go", "gen_swarm.go"} { + if _, ok := files[name]; !ok { + t.Errorf("expected file %q not generated", name) + } + } +} + +func TestGenerateAndCompile(t *testing.T) { + if testing.Short() { + t.Skip("skipping compilation test in short mode") + } + + commands := walkCommandTree(corecmds.Root, "") + files, err := generateFiles(commands) + if err != nil { + t.Fatalf("generateFiles failed: %v", err) + } + + // write generated files to client/rpc in a temp copy, then compile + tmpDir := t.TempDir() + + // copy existing non-generated client/rpc files + repoRoot := findRepoRoot(t) + rpcDir := filepath.Join(repoRoot, "client", "rpc") + entries, err := os.ReadDir(rpcDir) + if err != nil { + t.Fatalf("reading %s: %v", rpcDir, err) + } + + outDir := filepath.Join(tmpDir, "client", "rpc") + if err := os.MkdirAll(outDir, 0o755); err != nil { + t.Fatal(err) + } + + for _, e := range entries { + if e.IsDir() { + continue + } + // skip existing gen_ files and test files + if strings.HasPrefix(e.Name(), "gen_") || strings.HasSuffix(e.Name(), "_test.go") { + continue + } + data, err := os.ReadFile(filepath.Join(rpcDir, e.Name())) + if err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(outDir, e.Name()), data, 0o644); err != nil { + t.Fatal(err) + } + } + + // copy auth subpackage + authSrc := filepath.Join(rpcDir, "auth") + if _, err := os.Stat(authSrc); err == nil { + authDst := filepath.Join(outDir, "auth") + if err := os.MkdirAll(authDst, 0o755); err != nil { + t.Fatal(err) + } + authEntries, err := os.ReadDir(authSrc) + if err != nil { + t.Fatal(err) + } + for _, e := range authEntries { + if e.IsDir() || strings.HasSuffix(e.Name(), "_test.go") { + continue + } + data, err := os.ReadFile(filepath.Join(authSrc, e.Name())) + if err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(authDst, e.Name()), data, 0o644); err != nil { + t.Fatal(err) + } + } + } + + // write generated files + for name, content := range files { + if err := os.WriteFile(filepath.Join(outDir, name), content, 0o644); err != nil { + t.Fatal(err) + } + } + + // try to compile the package using "go build" pointing at the real module + cmd := exec.Command("go", "build", "./client/rpc/...") + cmd.Dir = repoRoot + cmd.Env = append(os.Environ(), "GOFLAGS=-mod=mod") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("go build failed: %v\n%s", err, out) + } +} + +func findRepoRoot(t *testing.T) string { + t.Helper() + dir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + for { + if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { + return dir + } + parent := filepath.Dir(dir) + if parent == dir { + t.Fatal("could not find repo root (no go.mod)") + } + dir = parent + } +} diff --git a/tools/gen-rpc-client/main.go b/tools/gen-rpc-client/main.go new file mode 100644 index 00000000000..0daffffcacf --- /dev/null +++ b/tools/gen-rpc-client/main.go @@ -0,0 +1,113 @@ +// Command gen-rpc-client generates typed Go client methods for the Kubo HTTP +// RPC API by walking the command tree defined in core/commands. +// +// Usage: +// +// go run ./tools/gen-rpc-client -output ./client/rpc/ +// go run ./tools/gen-rpc-client -check ./client/rpc/ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + "strings" + + corecmds "github.com/ipfs/kubo/core/commands" +) + +func main() { + outputDir := flag.String("output", "", "directory to write generated files to") + checkDir := flag.String("check", "", "directory to compare generated files against (exits 1 if stale)") + flag.Parse() + + if *outputDir == "" && *checkDir == "" { + fmt.Fprintln(os.Stderr, "usage: gen-rpc-client -output or gen-rpc-client -check ") + os.Exit(2) + } + + commands := walkCommandTree(corecmds.Root, "") + files, err := generateFiles(commands) + if err != nil { + fmt.Fprintf(os.Stderr, "generation failed: %v\n", err) + os.Exit(1) + } + + // generate smoke test alongside client files + smokeContent, err := generateSmokeTest(commands) + if err != nil { + fmt.Fprintf(os.Stderr, "smoke test generation failed: %v\n", err) + os.Exit(1) + } + files["gen_smoke_test.go"] = smokeContent + + if *checkDir != "" { + ok, err := checkGenerated(files, *checkDir) + if err != nil { + fmt.Fprintf(os.Stderr, "check failed: %v\n", err) + os.Exit(1) + } + if !ok { + fmt.Fprintln(os.Stderr, "generated RPC client is out of date, run: make rpc_client") + os.Exit(1) + } + fmt.Println("generated RPC client is up to date") + return + } + + if err := writeFiles(files, *outputDir); err != nil { + fmt.Fprintf(os.Stderr, "write failed: %v\n", err) + os.Exit(1) + } + for name := range files { + fmt.Println("wrote", filepath.Join(*outputDir, name)) + } +} + +// checkGenerated compares generated content against existing files on disk. +func checkGenerated(files map[string][]byte, dir string) (bool, error) { + ok := true + for name, want := range files { + path := filepath.Join(dir, name) + got, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, " missing: %s\n", name) + ok = false + continue + } + return false, err + } + if string(got) != string(want) { + fmt.Fprintf(os.Stderr, " stale: %s\n", name) + ok = false + } + } + + // check for gen_ files on disk that we no longer generate + entries, err := os.ReadDir(dir) + if err != nil { + return false, err + } + for _, e := range entries { + if strings.HasPrefix(e.Name(), "gen_") && strings.HasSuffix(e.Name(), ".go") { + if _, exists := files[e.Name()]; !exists { + fmt.Fprintf(os.Stderr, " orphan: %s\n", e.Name()) + ok = false + } + } + } + return ok, nil +} + +// writeFiles writes generated files to disk. +func writeFiles(files map[string][]byte, dir string) error { + for name, content := range files { + path := filepath.Join(dir, name) + if err := os.WriteFile(path, content, 0o644); err != nil { + return fmt.Errorf("writing %s: %w", path, err) + } + } + return nil +} diff --git a/tools/gen-rpc-client/reflect.go b/tools/gen-rpc-client/reflect.go new file mode 100644 index 00000000000..bd3fe55306c --- /dev/null +++ b/tools/gen-rpc-client/reflect.go @@ -0,0 +1,304 @@ +package main + +import ( + "fmt" + "reflect" + "sort" + "strings" +) + +// FieldInfo describes one field of a generated response struct. +type FieldInfo struct { + Name string // Go field name + Type string // Go type expression + JSONTag string // json struct tag value +} + +// TypeInfo describes a generated response struct. +type TypeInfo struct { + Name string // e.g. "PinAddResponse" + Fields []FieldInfo // exported fields +} + +// knownTypeMap maps specific Go types to simpler types for the generated +// client. Keys use the full package path + "." + type name. +var knownTypeMap = map[string]string{} + +// knownTypePatterns maps type name suffixes (last pkg segment + name) to +// simpler types. This handles cases where the full package path varies. +var knownTypePatterns = map[string]string{ + "Cid": "string", + "ID": "string", + "Multiaddr": "string", + "Path": "string", + "ImmutablePath": "string", + "Duration": "string", + "FileMode": "string", +} + +// knownFullPaths maps full "pkgpath.TypeName" to simpler types. +var knownFullPaths = map[string]string{ + "github.com/ipfs/go-cid.Cid": "string", + "github.com/libp2p/go-libp2p/core/peer.ID": "string", + "github.com/multiformats/go-multiaddr.Multiaddr": "string", + "github.com/libp2p/go-libp2p/core/protocol.ID": "string", + "github.com/ipfs/boxo/path.Path": "string", + "github.com/ipfs/boxo/path.ImmutablePath": "string", + "math/big.Int": "json.Number", + "time.Duration": "string", + "os.FileMode": "string", + "github.com/multiformats/go-multicodec.Code": "uint64", + "github.com/multiformats/go-multibase.Encoding": "int", + "time.Time": "string", +} + +// reflectResponseType extracts TypeInfo for a command's response type. +// It returns nil if the type cannot be represented as a struct. +func reflectResponseType(goName string, t reflect.Type) []TypeInfo { + if t == nil { + return nil + } + + // dereference pointer + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + // for slices of structs, generate the element type + if t.Kind() == reflect.Slice { + elem := t.Elem() + for elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + if elem.Kind() == reflect.Struct { + types := reflectStruct(goName+"Item", elem, nil) + // also generate a type alias for the slice + return types + } + return nil + } + + if t.Kind() == reflect.Chan { + // channel types (like <-chan any) don't have useful structure + return nil + } + + if t.Kind() != reflect.Struct { + return nil + } + + return reflectStruct(goName+"Response", t, nil) +} + +// reflectStruct extracts fields from a struct type, recursing into +// embedded/nested structs. Returns all generated types (main + nested). +func reflectStruct(name string, t reflect.Type, seen map[reflect.Type]bool) []TypeInfo { + if seen == nil { + seen = make(map[reflect.Type]bool) + } + if seen[t] { + return nil + } + seen[t] = true + + var fields []FieldInfo + var nested []TypeInfo + + for i := range t.NumField() { + f := t.Field(i) + + // skip unexported fields (but process embedded) + if !f.IsExported() && !f.Anonymous { + continue + } + + // embedded struct: flatten its fields + if f.Anonymous { + ft := f.Type + for ft.Kind() == reflect.Ptr { + ft = ft.Elem() + } + if ft.Kind() == reflect.Struct { + embeddedTypes := reflectStruct(name, ft, seen) + if len(embeddedTypes) > 0 { + fields = append(fields, embeddedTypes[0].Fields...) + nested = append(nested, embeddedTypes[1:]...) + } + } + continue + } + + jsonTag := jsonFieldTag(f) + if jsonTag == "-" { + continue + } + + goType := resolveGoType(name, f.Name, f.Type, seen, &nested) + fields = append(fields, FieldInfo{ + Name: f.Name, + Type: goType, + JSONTag: jsonTag, + }) + } + + result := []TypeInfo{{Name: name, Fields: fields}} + result = append(result, nested...) + return result +} + +// resolveGoType converts a reflect.Type to a Go type string for generated code. +func resolveGoType(parentName, fieldName string, t reflect.Type, seen map[reflect.Type]bool, nested *[]TypeInfo) string { + // check known type mappings by full package path + if t.PkgPath() != "" { + fullKey := t.PkgPath() + "." + t.Name() + if mapped, ok := knownFullPaths[fullKey]; ok { + return mapped + } + } + + switch t.Kind() { + case reflect.Ptr: + inner := resolveGoType(parentName, fieldName, t.Elem(), seen, nested) + return "*" + inner + + case reflect.Slice: + elem := t.Elem() + inner := resolveGoType(parentName, fieldName, elem, seen, nested) + return "[]" + inner + + case reflect.Map: + kType := resolveGoType(parentName, fieldName+"Key", t.Key(), seen, nested) + vType := resolveGoType(parentName, fieldName+"Val", t.Elem(), seen, nested) + return "map[" + kType + "]" + vType + + case reflect.Struct: + nestedName := parentName + fieldName + types := reflectStruct(nestedName, t, seen) + if len(types) > 0 { + *nested = append(*nested, types...) + return types[0].Name + } + return "json.RawMessage" + + case reflect.Interface: + return "json.RawMessage" + + case reflect.Bool: + return "bool" + case reflect.Int: + return "int" + case reflect.Int8: + return "int8" + case reflect.Int16: + return "int16" + case reflect.Int32: + return "int32" + case reflect.Int64: + return "int64" + case reflect.Uint: + return "uint" + case reflect.Uint8: + return "uint8" + case reflect.Uint16: + return "uint16" + case reflect.Uint32: + return "uint32" + case reflect.Uint64: + return "uint64" + case reflect.Float32: + return "float32" + case reflect.Float64: + return "float64" + case reflect.String: + return "string" + + default: + return "json.RawMessage" + } +} + +// typeName returns "pkg.Name" for a named type, or empty string. +func typeName(t reflect.Type) string { + if t.PkgPath() == "" { + return "" + } + pkg := t.PkgPath() + if i := strings.LastIndex(pkg, "/"); i >= 0 { + pkg = pkg[i+1:] + } + return pkg + "." + t.Name() +} + +// jsonFieldTag extracts the JSON tag name for a struct field. +// Returns "FieldName,omitempty" if no tag is present. +func jsonFieldTag(f reflect.StructField) string { + tag := f.Tag.Get("json") + if tag == "" { + return f.Name + ",omitempty" + } + return tag +} + +// needsJSONImport checks if any type in the list uses json.RawMessage or json.Number. +func needsJSONImport(types []TypeInfo) bool { + for _, t := range types { + for _, f := range t.Fields { + if strings.Contains(f.Type, "json.") { + return true + } + } + } + return false +} + +// deduplicateTypes removes duplicate TypeInfo entries by name, keeping the +// first occurrence. +func deduplicateTypes(types []TypeInfo) []TypeInfo { + seen := make(map[string]bool) + var result []TypeInfo + for _, t := range types { + if seen[t.Name] { + continue + } + seen[t.Name] = true + result = append(result, t) + } + return result +} + +// sortTypes sorts types alphabetically by name. +func sortTypes(types []TypeInfo) { + sort.Slice(types, func(i, j int) bool { + return types[i].Name < types[j].Name + }) +} + +// responseTypeName returns the Go type name for a command's response. +// For structs it returns "*GoNameResponse", for slices "[]GoNameItem". +func responseTypeName(cmd CommandInfo) string { + if cmd.ResponseType == nil { + return "" + } + + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + if t.Kind() == reflect.Slice { + elem := t.Elem() + for elem.Kind() == reflect.Ptr { + elem = elem.Elem() + } + if elem.Kind() == reflect.Struct { + return fmt.Sprintf("[]%sItem", cmd.GoName) + } + return fmt.Sprintf("[]%s", resolveGoType("", "", elem, nil, nil)) + } + + if t.Kind() == reflect.Struct { + return cmd.GoName + "Response" + } + + return resolveGoType("", "", t, nil, nil) +} diff --git a/tools/gen-rpc-client/smoke.go b/tools/gen-rpc-client/smoke.go new file mode 100644 index 00000000000..14ee85ec978 --- /dev/null +++ b/tools/gen-rpc-client/smoke.go @@ -0,0 +1,309 @@ +package main + +import ( + "bytes" + "fmt" + "go/format" + "reflect" + "strings" + "text/template" +) + +// skipReasons maps command paths to reasons they cannot be smoke-tested. +// Commands in this map get t.Skip(...) in the generated test. +var skipReasons = map[string]string{ + // destructive + "shutdown": "kills the daemon", + + // needs peer / network + "swarm/connect": "needs peer address", + "swarm/disconnect": "needs connected peer", + "routing/findpeer": "needs online peer", + "routing/findprovs": "needs CID with providers", + "routing/get": "needs valid DHT key", + "routing/put": "needs valid DHT key/value pair", + "routing/provide": "needs CID and network", + "routing/reprovide": "needs CID and network", + "dht/findpeer": "needs online peer", + "dht/findprovs": "needs CID with providers", + "dht/get": "needs valid DHT key", + "dht/put": "needs valid DHT key/value pair", + "dht/provide": "needs CID and network", + "dht/query": "needs online peer", + "ping": "needs online peer", + + // remote pinning service + "pin/remote/add": "needs remote pinning service", + "pin/remote/ls": "needs remote pinning service", + "pin/remote/rm": "needs remote pinning service", + "pin/remote/service/add": "needs remote pinning service", + "pin/remote/service/ls": "needs remote pinning service", + "pin/remote/service/rm": "needs remote pinning service", + + // config mutation + "config": "needs specific config key/value", + "config/replace": "replaces entire config", + "config/profile/apply": "mutates config", + + // name operations + "name/publish": "needs IPNS key setup", + "name/resolve": "needs published IPNS record", + "name/get": "needs published IPNS record", + "name/inspect": "needs valid IPNS record file", + "name/put": "needs valid IPNS record file", + "name/pubsub/cancel": "needs active IPNS subscription", + + // pubsub + "pubsub/pub": "needs topic and subscriber", + "pubsub/sub": "blocks waiting for messages", + + // p2p + "p2p/forward": "needs p2p setup", + "p2p/listen": "needs p2p setup", + "p2p/close": "needs active p2p listeners", + "p2p/ls": "needs active p2p listeners", + "p2p/stream/close": "needs active p2p streams", + "p2p/stream/ls": "needs active p2p streams", + + // key operations needing existing keys + "key/import": "needs valid key file", + "key/rename": "needs existing non-self key", + "key/rm": "needs existing non-self key", + "key/sign": "needs key and data setup", + "key/verify": "needs key, signature, and data", + + // filesystem / mount + "mount": "requires FUSE", + + // MFS operations needing state + "files/cp": "needs MFS files", + "files/mv": "needs MFS files", + "files/rm": "needs MFS files", + "files/write": "needs MFS file path", + "files/mkdir": "needs MFS path setup", + "files/chcid": "needs MFS path", + + // filestore + "filestore/ls": "needs filestore content", + "filestore/verify": "needs filestore content", + + // profiling + "diag/profile": "runs profiler, slow", + + // streaming that blocks + "stats/bw": "blocks polling for bandwidth stats", + "log/tail": "blocks waiting for log events", + + // dag/import needs a valid CAR file + "dag/import": "needs valid CAR file", +} + +// smokeTestArgs generates the argument expressions for a smoke test call. +// It mirrors the logic in argParams but produces test values instead of param names. +func smokeTestArgs(cmd CommandInfo) string { + var parts []string + hasVariadic := false + + for _, arg := range cmd.Arguments { + if arg.IsFile { + parts = append(parts, smokeFileValue(cmd)) + } else if arg.Variadic { + hasVariadic = true + } else { + parts = append(parts, smokeStringValue(arg)) + } + } + + // variadic args: slice if options present, spread if not + if hasVariadic && len(cmd.Options) > 0 { + for _, arg := range cmd.Arguments { + if arg.Variadic && !arg.IsFile { + parts = append(parts, smokeSliceValue(arg)) + } + } + } else if hasVariadic { + for _, arg := range cmd.Arguments { + if arg.Variadic && !arg.IsFile { + parts = append(parts, smokeStringValue(arg)) + } + } + } + + if len(parts) == 0 { + return "" + } + return ", " + strings.Join(parts, ", ") +} + +// smokeStringValue returns a test value for a string argument. +func smokeStringValue(arg ArgInfo) string { + name := strings.ToLower(arg.Name) + if strings.Contains(name, "path") || strings.Contains(name, "cid") || + strings.Contains(name, "ref") || strings.Contains(name, "root") { + return "testCID" + } + return `""` +} + +// smokeSliceValue returns a test value for a variadic arg passed as []string. +func smokeSliceValue(arg ArgInfo) string { + name := strings.ToLower(arg.Name) + if strings.Contains(name, "path") || strings.Contains(name, "cid") || + strings.Contains(name, "ref") || strings.Contains(name, "root") || + strings.Contains(name, "key") { + return "[]string{testCID}" + } + return `[]string{""}` +} + +// smokeFileValue returns a test value for a file argument. +func smokeFileValue(cmd CommandInfo) string { + // dag/put expects JSON + if cmd.Path == "dag/put" { + return `strings.NewReader("{}")` + } + return `strings.NewReader("test data")` +} + +// smokeReturnKind describes how to handle the return value in a test. +type smokeReturnKind int + +const ( + smokeReturnVoid smokeReturnKind = iota // returns error + smokeReturnStruct // returns *T, error + smokeReturnSlice // returns []T, error + smokeReturnBinary // returns *Response, error + smokeReturnStream // returns iter.Seq2[T, error] +) + +func classifyReturn(cmd CommandInfo) smokeReturnKind { + if cmd.ResponseKind == ResponseStream { + return smokeReturnStream + } + if cmd.ResponseKind == ResponseBinary { + return smokeReturnBinary + } + // ResponseSingle + if cmd.ResponseType == nil { + return smokeReturnVoid + } + if hasPrimitiveResponse(cmd) { + return smokeReturnBinary + } + t := cmd.ResponseType + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.Slice { + return smokeReturnSlice + } + return smokeReturnStruct +} + +// smokeSubtest generates one t.Run subtest for a command. +func smokeSubtest(cmd CommandInfo) string { + var b strings.Builder + + args := smokeTestArgs(cmd) + + // check skip + if reason, ok := skipReasons[cmd.Path]; ok { + fmt.Fprintf(&b, "\tt.Run(%q, func(t *testing.T) {\n", cmd.GoName) + fmt.Fprintf(&b, "\t\tt.Skip(%q)\n", reason) + fmt.Fprintf(&b, "\t})\n") + return b.String() + } + + fmt.Fprintf(&b, "\tt.Run(%q, func(t *testing.T) {\n", cmd.GoName) + fmt.Fprintf(&b, "\t\trequire.NotPanics(t, func() {\n") + + switch classifyReturn(cmd) { + case smokeReturnVoid: + fmt.Fprintf(&b, "\t\t\t_ = api.%s(ctx%s)\n", cmd.GoName, args) + + case smokeReturnStruct: + fmt.Fprintf(&b, "\t\t\t_, _ = api.%s(ctx%s)\n", cmd.GoName, args) + + case smokeReturnSlice: + fmt.Fprintf(&b, "\t\t\t_, _ = api.%s(ctx%s)\n", cmd.GoName, args) + + case smokeReturnBinary: + fmt.Fprintf(&b, "\t\t\tresp, err := api.%s(ctx%s)\n", cmd.GoName, args) + fmt.Fprintf(&b, "\t\t\tif err == nil && resp != nil {\n") + fmt.Fprintf(&b, "\t\t\t\tresp.Close()\n") + fmt.Fprintf(&b, "\t\t\t}\n") + + case smokeReturnStream: + fmt.Fprintf(&b, "\t\t\tfor _, err := range api.%s(ctx%s) {\n", cmd.GoName, args) + fmt.Fprintf(&b, "\t\t\t\t_ = err\n") + fmt.Fprintf(&b, "\t\t\t\tbreak\n") + fmt.Fprintf(&b, "\t\t\t}\n") + } + + fmt.Fprintf(&b, "\t\t})\n") + fmt.Fprintf(&b, "\t})\n") + return b.String() +} + +// smokeTestTemplate is the template for gen_smoke_test.go. +const smokeTestTemplateStr = `// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" + "strings" + "testing" + + "github.com/ipfs/kubo/test/cli/harness" + "github.com/stretchr/testify/require" +) + +// TestGeneratedSmoke starts a daemon and calls every generated method with +// minimal arguments. It verifies that methods don't panic and that response +// deserialization works. Commands that need complex setup are skipped. +func TestGeneratedSmoke(t *testing.T) { + t.Parallel() + h := harness.NewT(t) + node := h.NewNode().Init().StartDaemon("--offline") + api, err := NewApi(node.APIAddr()) + require.NoError(t, err) + ctx := context.Background() + _ = strings.NewReader // ensure strings import is used + + testCID := node.IPFSAddStr("smoke test data") + +{{range .Commands}} +{{smokeSubtest .}} +{{end}} +} +` + +// generateSmokeTest produces the gen_smoke_test.go content. +func generateSmokeTest(commands []CommandInfo) ([]byte, error) { + funcMap := template.FuncMap{ + "smokeSubtest": smokeSubtest, + } + + tmpl, err := template.New("smoke").Funcs(funcMap).Parse(smokeTestTemplateStr) + if err != nil { + return nil, fmt.Errorf("parsing smoke template: %w", err) + } + + data := struct { + Commands []CommandInfo + }{ + Commands: commands, + } + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, data); err != nil { + return nil, fmt.Errorf("executing smoke template: %w", err) + } + + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return nil, fmt.Errorf("formatting smoke test: %w\n--- raw source ---\n%s", err, buf.String()) + } + return formatted, nil +} diff --git a/tools/gen-rpc-client/templates.go b/tools/gen-rpc-client/templates.go new file mode 100644 index 00000000000..27a192bb64b --- /dev/null +++ b/tools/gen-rpc-client/templates.go @@ -0,0 +1,192 @@ +package main + +import "text/template" + +// allFuncMap contains all template functions. Functions that depend on +// generate.go are registered as stubs here and replaced at execution time. +// This is needed because template.Must runs at init() before other funcs +// are available. +var allFuncMap = template.FuncMap{ + "responseTypeName": func(CommandInfo) string { return "" }, + "optionTypes": func(CommandInfo) string { return "" }, + "methodFunc": func(CommandInfo) string { return "" }, + "argParams": func(CommandInfo) string { return "" }, + "argValues": func(CommandInfo) string { return "" }, + "returnType": func(CommandInfo) string { return "" }, + "streamReturnType": func(CommandInfo) string { return "" }, + "streamItemType": func(CommandInfo) string { return "" }, + "streamZero": func(CommandInfo) string { return "" }, + "hasStructResponse": func(CommandInfo) bool { return false }, + "hasSliceResponse": func(CommandInfo) bool { return false }, + "fileBodySetup": func(CommandInfo) string { return "" }, + "toLower": func(string) string { return "" }, + "sanitizeDescription": func(string) string { return "" }, + "hasPrimitiveResponse": func(CommandInfo) bool { return false }, +} + +// fileTemplateStr is the main template for one gen_*.go file. +const fileTemplateStr = `// Code generated by tools/gen-rpc-client; DO NOT EDIT. + +package rpc + +import ( + "context" +{{- if .NeedsIO}} + "io" +{{- end}} +{{- if .NeedsJSON}} + "encoding/json" +{{- end}} +{{- if .NeedsIter}} + "iter" +{{- end}} +) + +{{range .Types}} +{{- if .Fields}} +type {{.Name}} struct { +{{- range .Fields}} + {{.Name}} {{.Type}} ` + "`" + `json:"{{.JSONTag}}"` + "`" + ` +{{- end}} +} +{{end}} +{{end}} + +{{- range .Commands}} +{{optionTypes .}} +{{methodFunc .}} +{{end}} +` + +// optionTypesTemplateStr generates the option type and option funcs for a command. +const optionTypesTemplateStr = ` +{{- if .Options}} +// {{.GoName}}Option configures the {{.Path}} command. +type {{.GoName}}Option func(RequestBuilder) +{{range .Options}} +// {{$.GoName}}{{.GoName}} sets the {{.Name}} option. +{{- if .Description}} +// {{sanitizeDescription .Description}} +{{- end}} +func {{$.GoName}}{{.GoName}}(v {{.Type}}) {{$.GoName}}Option { + return func(rb RequestBuilder) { rb.Option("{{.Name}}", v) } +} +{{end}} +{{- end}} +` + +// singleMethodTemplateStr generates a method for a single-response command. +const singleMethodTemplateStr = ` +{{- if eq .Status 2}} +// Deprecated: {{.GoName}} may be removed in a future release. +{{- end}} +{{- if eq .Status 1}} +// Experimental: {{.GoName}} is not yet stable. +{{- end}} +{{- if .Tagline}} +// {{.GoName}} {{toLower .Tagline}}. +{{- end}} +func (a *HttpApi) {{.GoName}}(ctx context.Context{{argParams .}}{{if .Options}}, opts ...{{.GoName}}Option{{end}}) ({{returnType .}}) { + req := a.Request("{{.Path}}"{{argValues .}}) +{{- if .HasFileArg}} + {{fileBodySetup .}} +{{- end}} +{{- if .Options}} + for _, o := range opts { o(req) } +{{- end}} +{{- if hasStructResponse .}} + var resp {{responseTypeName .}} + if err := req.Exec(ctx, &resp); err != nil { return nil, err } + return &resp, nil +{{- else if hasSliceResponse .}} + var resp {{responseTypeName .}} + if err := req.Exec(ctx, &resp); err != nil { return nil, err } + return resp, nil +{{- else}} + return req.Exec(ctx, nil) +{{- end}} +} +` + +// streamMethodTemplateStr generates a method for a streaming command. +const streamMethodTemplateStr = ` +{{- if eq .Status 2}} +// Deprecated: {{.GoName}} may be removed in a future release. +{{- end}} +{{- if eq .Status 1}} +// Experimental: {{.GoName}} is not yet stable. +{{- end}} +{{- if .Tagline}} +// {{.GoName}} {{toLower .Tagline}}. +{{- end}} +func (a *HttpApi) {{.GoName}}(ctx context.Context{{argParams .}}{{if .Options}}, opts ...{{.GoName}}Option{{end}}) {{streamReturnType .}} { + return func(yield func({{streamItemType .}}, error) bool) { + req := a.Request("{{.Path}}"{{argValues .}}) +{{- if .HasFileArg}} + {{fileBodySetup .}} +{{- end}} +{{- if .Options}} + for _, o := range opts { o(req) } +{{- end}} + resp, err := req.Send(ctx) + if err != nil { yield({{streamZero .}}, err); return } + defer resp.Close() + if resp.Error != nil { yield({{streamZero .}}, resp.Error); return } + dec := json.NewDecoder(resp.Output) + for dec.More() { + var item {{streamItemType .}} + if err := dec.Decode(&item); err != nil { yield({{streamZero .}}, err); return } + if !yield(item, nil) { return } + } + } +} +` + +// binaryMethodTemplateStr generates a method for a binary-output command. +const binaryMethodTemplateStr = ` +{{- if eq .Status 2}} +// Deprecated: {{.GoName}} may be removed in a future release. +{{- end}} +{{- if eq .Status 1}} +// Experimental: {{.GoName}} is not yet stable. +{{- end}} +{{- if .Tagline}} +// {{.GoName}} {{toLower .Tagline}}. +{{- end}} +func (a *HttpApi) {{.GoName}}(ctx context.Context{{argParams .}}{{if .Options}}, opts ...{{.GoName}}Option{{end}}) (*Response, error) { + req := a.Request("{{.Path}}"{{argValues .}}) +{{- if .HasFileArg}} + {{fileBodySetup .}} +{{- end}} +{{- if .Options}} + for _, o := range opts { o(req) } +{{- end}} + resp, err := req.Send(ctx) + if err != nil { return nil, err } + if resp.Error != nil { resp.Close(); return nil, resp.Error } + return resp, nil +} +` + +// voidMethodTemplateStr generates a method for a command with no response body. +const voidMethodTemplateStr = ` +{{- if eq .Status 2}} +// Deprecated: {{.GoName}} may be removed in a future release. +{{- end}} +{{- if eq .Status 1}} +// Experimental: {{.GoName}} is not yet stable. +{{- end}} +{{- if .Tagline}} +// {{.GoName}} {{toLower .Tagline}}. +{{- end}} +func (a *HttpApi) {{.GoName}}(ctx context.Context{{argParams .}}{{if .Options}}, opts ...{{.GoName}}Option{{end}}) error { + req := a.Request("{{.Path}}"{{argValues .}}) +{{- if .HasFileArg}} + {{fileBodySetup .}} +{{- end}} +{{- if .Options}} + for _, o := range opts { o(req) } +{{- end}} + return req.Exec(ctx, nil) +} +` diff --git a/tools/gen-rpc-client/walk.go b/tools/gen-rpc-client/walk.go new file mode 100644 index 00000000000..458e686dfac --- /dev/null +++ b/tools/gen-rpc-client/walk.go @@ -0,0 +1,224 @@ +package main + +import ( + "fmt" + "reflect" + "sort" + "strings" + "unicode" + + cmds "github.com/ipfs/go-ipfs-cmds" + "github.com/ipfs/kubo/core/commands/cmdutils" +) + +// CommandInfo holds the extracted metadata for one HTTP-accessible command. +type CommandInfo struct { + Path string // e.g. "pin/add" + GoName string // e.g. "PinAdd" + GroupName string // e.g. "pin" + GroupGoName string // e.g. "Pin" + Arguments []ArgInfo // positional args + Options []OptInfo // command options (excludes global opts) + ResponseKind ResponseKind // how to consume the HTTP response + ResponseType reflect.Type // nil for Binary / void + HasFileArg bool // true if any argument is ArgFile + Status cmds.Status + Tagline string +} + +// ResponseKind mirrors cmdutils.ResponseKind. +type ResponseKind = cmdutils.ResponseKind + +const ( + ResponseSingle = cmdutils.ResponseSingle + ResponseStream = cmdutils.ResponseStream + ResponseBinary = cmdutils.ResponseBinary +) + +// ArgInfo describes a positional argument. +type ArgInfo struct { + Name string + IsFile bool // ArgFile vs ArgString + Required bool + Variadic bool +} + +// OptInfo describes a command option. +type OptInfo struct { + Name string // primary name (first in Names()) + GoName string // PascalCase + Type string // Go type: "bool", "int", "int64", "uint64", "float64", "string", "[]string" + Default any + Description string +} + +// walkCommandTree recursively collects CommandInfo for all HTTP-accessible +// commands under root. The prefix is prepended to the command path (pass "" +// for the root). +func walkCommandTree(root *cmds.Command, prefix string) []CommandInfo { + var result []CommandInfo + + for name, sub := range root.Subcommands { + path := name + if prefix != "" { + path = prefix + "/" + name + } + + // skip commands that can't be called over HTTP + if sub.Run != nil && !sub.NoRemote && sub.Status != cmds.Removed { + info := extractCommandInfo(path, sub) + result = append(result, info) + } + + // always recurse into subcommands + result = append(result, walkCommandTree(sub, path)...) + } + + sort.Slice(result, func(i, j int) bool { + return result[i].Path < result[j].Path + }) + return result +} + +// extractCommandInfo builds a CommandInfo from a command definition. +func extractCommandInfo(path string, cmd *cmds.Command) CommandInfo { + info := CommandInfo{ + Path: path, + GoName: pathToGoName(path), + GroupName: groupName(path), + GroupGoName: toPascalCase(groupName(path)), + ResponseKind: cmdutils.GetResponseKind(cmd), + Status: cmd.Status, + Tagline: cmd.Helptext.Tagline, + } + + if cmd.Type != nil { + info.ResponseType = reflect.TypeOf(cmd.Type) + if info.ResponseType.Kind() == reflect.Ptr { + info.ResponseType = info.ResponseType.Elem() + } + } + + // arguments + for _, arg := range cmd.Arguments { + a := ArgInfo{ + Name: arg.Name, + IsFile: arg.Type == cmds.ArgFile, + Required: arg.Required, + Variadic: arg.Variadic, + } + if a.IsFile { + info.HasFileArg = true + } + info.Arguments = append(info.Arguments, a) + } + + // options (skip global options that come from the framework) + for _, opt := range cmd.Options { + name := opt.Names()[0] + if isGlobalOption(name) { + continue + } + info.Options = append(info.Options, OptInfo{ + Name: name, + GoName: toPascalCase(name), + Type: optionGoType(opt), + Default: opt.Default(), + Description: opt.Description(), + }) + } + + return info +} + +// globalOptions lists option names provided by the framework or the root +// command that every command inherits. We skip these in generated code. +var globalOptions = map[string]struct{}{ + "encoding": {}, + "stream-channels": {}, + "timeout": {}, + "api": {}, + "api-auth": {}, + "offline": {}, + "repo-dir": {}, + "config-file": {}, + "config": {}, + "debug": {}, + "help": {}, + "local": {}, + "cid-base": {}, + "upgrade-cidv0-in-output": {}, +} + +func isGlobalOption(name string) bool { + _, ok := globalOptions[name] + return ok +} + +// optionGoType returns the Go type string for a cmds.Option. +func optionGoType(opt cmds.Option) string { + switch opt.Type() { + case reflect.Bool: + return "bool" + case reflect.Int: + return "int" + case reflect.Int64: + return "int64" + case reflect.Uint: + return "uint" + case reflect.Uint64: + return "uint64" + case reflect.Float64: + return "float64" + case reflect.String: + return "string" + case reflect.Array, reflect.Slice: + return "[]string" + default: + return "string" + } +} + +// pathToGoName converts "pin/add" to "PinAdd". +func pathToGoName(path string) string { + parts := strings.Split(path, "/") + var b strings.Builder + for _, p := range parts { + b.WriteString(toPascalCase(p)) + } + return b.String() +} + +// toPascalCase converts "find-provs" to "FindProvs", "bw" to "Bw", etc. +func toPascalCase(s string) string { + var b strings.Builder + upper := true + for _, r := range s { + if r == '-' || r == '_' { + upper = true + continue + } + if upper { + b.WriteRune(unicode.ToUpper(r)) + upper = false + } else { + b.WriteRune(r) + } + } + return b.String() +} + +// groupName returns the first path segment. +func groupName(path string) string { + if i := strings.IndexByte(path, '/'); i >= 0 { + return path[:i] + } + return path +} + +func formatDefault(v any) string { + if v == nil { + return "" + } + return fmt.Sprint(v) +}