From f97c0a92f9ec7c521a06c74219d15f2589d54993 Mon Sep 17 00:00:00 2001 From: simlecode <69969590+simlecode@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:37:24 +0800 Subject: [PATCH] feat: add rpc command --- cmd/main.go | 2 + cmd/rpc.go | 115 +++++++++++++++++++++++++++++++++++++++++++++ pkg/repo/fsrepo.go | 2 +- 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 cmd/rpc.go diff --git a/cmd/main.go b/cmd/main.go index e7a2e45805..9c01e3f536 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -140,6 +140,7 @@ TOOL COMMANDS version - Show venus version information seed - Seal sectors for genesis miner fetch - Fetch proving parameters + rpc - Interact with the jsonrpc api `, }, Options: []cmds.Option{ @@ -165,6 +166,7 @@ var rootSubcmdsLocal = map[string]*cmds.Command{ "version": versionCmd, "seed": seedCmd, "cid": cidCmd, + "rpc": rpcCmd, } // all top level commands, available on daemon. set during init() to avoid configuration loops. diff --git a/cmd/rpc.go b/cmd/rpc.go new file mode 100644 index 0000000000..a9ba17ef2a --- /dev/null +++ b/cmd/rpc.go @@ -0,0 +1,115 @@ +package cmd + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" + + "github.com/filecoin-project/venus/app/paths" + "github.com/filecoin-project/venus/pkg/repo" + "github.com/filecoin-project/venus/venus-shared/api" + v1 "github.com/filecoin-project/venus/venus-shared/api/chain/v1" + cmds "github.com/ipfs/go-ipfs-cmds" + "golang.org/x/xerrors" +) + +var rpcCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "Interactive JsonPRC shell", + }, + Arguments: []cmds.Argument{ + cmds.StringArg("method", true, false, "method name"), + cmds.StringArg("params", false, false, "method params"), + }, + Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { + repoDir, _ := req.Options[OptionRepoDir].(string) + repoDir, err := paths.GetRepoPath(repoDir) + if err != nil { + return err + } + addr, err := repo.APIAddrFromRepoPath(repoDir) + if err != nil { + return err + } + token, err := repo.APITokenFromRepoPath(repoDir) + if err != nil { + return err + } + + ai := api.NewAPIInfo(addr, token) + addr, err = ai.DialArgs(api.VerString(v1.MajorVersion)) + if err != nil { + return err + } + + u, err := url.Parse(addr) + if err != nil { + return xerrors.Errorf("parsing api URL: %w", err) + } + + switch u.Scheme { + case "ws": + u.Scheme = "http" + case "wss": + u.Scheme = "https" + } + + addr = u.String() + + if len(req.Arguments) < 1 { + return re.Emit("method name is required.") + } + methodName := req.Arguments[0] + params := "[]" + if len(req.Arguments) > 1 { + params = req.Arguments[1] + } + + res, err := send(addr, methodName, params, ai.AuthHeader()) + if err != nil { + return err + } + + return printOneString(re, res) + }, +} + +func send(addr, method, params string, headers http.Header) (string, error) { + jreq, err := json.Marshal(struct { + Jsonrpc string `json:"jsonrpc"` + ID int `json:"id"` + Method string `json:"method"` + Params json.RawMessage `json:"params"` + }{ + Jsonrpc: "2.0", + Method: "Filecoin." + method, + Params: json.RawMessage(params), + ID: 0, + }) + if err != nil { + return "", err + } + + req, err := http.NewRequest("POST", addr, bytes.NewReader(jreq)) + if err != nil { + return "", err + } + req.Header = headers + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + + rb, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + if err := resp.Body.Close(); err != nil { + return "", err + } + + return string(rb), nil +} diff --git a/pkg/repo/fsrepo.go b/pkg/repo/fsrepo.go index a690d9fa7e..de27018be8 100644 --- a/pkg/repo/fsrepo.go +++ b/pkg/repo/fsrepo.go @@ -628,7 +628,7 @@ func apiTokenFromFile(repoPath string) (string, error) { tokenFile := filepath.Join(repoPath, apiToken) token, err := os.ReadFile(tokenFile) if err != nil { - return "", errors.Wrap(err, "failed to read API file") + return "", errors.Wrap(err, "failed to read token file") } return strings.TrimSpace(string(token)), nil