mirror of
https://github.com/status-im/status-go.git
synced 2025-01-09 14:16:21 +00:00
2d964bfe9f
The main goal of this change is to remove async operations from node manager. Additionally all of the signals from node manager are moved to status backend. All of the async operation now will have the following behaviour: - If node in the correct state exit immediatly without error - If node not in the correct state exit immediatly with error - In all other cases spawn a goroutine with wanted operation - All the progress regarding that operation will be reported by using signals - Signals should be handled in once place, which is StatusBackend There are 2 potentially breaking changes: - Empty event field will be ommited when Envelope is sent to a client - All errors will be delivered to a client as an Envelope, previously some errors (NodeExists, NoRunningNode) were delivered synchronously Signed-off-by: Dmitry Shulyak <yashulyak@gmail.com>
179 lines
4.8 KiB
Go
179 lines
4.8 KiB
Go
package debug
|
|
|
|
import (
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/status-im/status-go/geth/api"
|
|
"github.com/status-im/status-go/geth/common"
|
|
"github.com/status-im/status-go/geth/params"
|
|
)
|
|
|
|
// command contains the result of a parsed command line and
|
|
// is able to execute it on the command set.
|
|
type command struct {
|
|
funcName string
|
|
args []interface{}
|
|
}
|
|
|
|
// newCommand parses a command line and returns the command
|
|
// for further usage.
|
|
func newCommand(commandLine string) (*command, error) {
|
|
expr, err := parser.ParseExpr(commandLine)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch expr := expr.(type) {
|
|
case *ast.CallExpr:
|
|
f, ok := expr.Fun.(*ast.Ident)
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid expression: %q", commandLine)
|
|
}
|
|
return &command{
|
|
funcName: f.Name,
|
|
args: exprsToArgs(expr.Args),
|
|
}, nil
|
|
default:
|
|
return nil, fmt.Errorf("invalid command line: %q", commandLine)
|
|
}
|
|
}
|
|
|
|
// execute calls the method on the passed command set value.
|
|
func (c *command) execute(commandSetValue reflect.Value) (replies []string, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
err = fmt.Errorf("invalid API call: %v", r)
|
|
}
|
|
}()
|
|
method := commandSetValue.MethodByName(c.funcName)
|
|
if !method.IsValid() {
|
|
return nil, fmt.Errorf("command %q not found", c.funcName)
|
|
}
|
|
argsV := make([]reflect.Value, len(c.args))
|
|
for i, arg := range c.args {
|
|
argsV[i] = reflect.ValueOf(arg)
|
|
}
|
|
repliesV := method.Call(argsV)
|
|
replies = make([]string, len(repliesV))
|
|
for i, replyV := range repliesV {
|
|
replies[i] = fmt.Sprintf("%v", replyV)
|
|
}
|
|
return replies, nil
|
|
}
|
|
|
|
// exprsToArgs converts the argument expressions to arguments.
|
|
func exprsToArgs(exprs []ast.Expr) []interface{} {
|
|
args := make([]interface{}, len(exprs))
|
|
for i, expr := range exprs {
|
|
switch expr := expr.(type) {
|
|
case *ast.BasicLit:
|
|
switch expr.Kind {
|
|
case token.INT:
|
|
args[i], _ = strconv.ParseInt(expr.Value, 10, 64) // nolint: gas
|
|
case token.FLOAT:
|
|
args[i], _ = strconv.ParseFloat(expr.Value, 64) // nolint: gas
|
|
case token.CHAR:
|
|
args[i] = expr.Value[1]
|
|
case token.STRING:
|
|
r := strings.NewReplacer("\\n", "\n", "\\t", "\t", "\\\"", "\"")
|
|
args[i] = strings.Trim(r.Replace(expr.Value), `"`)
|
|
}
|
|
case *ast.Ident:
|
|
switch expr.Name {
|
|
case "true":
|
|
args[i] = true
|
|
case "false":
|
|
args[i] = false
|
|
default:
|
|
args[i] = expr.Name
|
|
}
|
|
default:
|
|
args[i] = fmt.Sprintf("[unknown: %#v]", expr)
|
|
}
|
|
}
|
|
return args
|
|
}
|
|
|
|
// commandSet implements the set of commands the debugger unterstands.
|
|
// In the beginning a subset of the Status API, may later grow to
|
|
// utility commands.
|
|
//
|
|
// Direct invocation of commands on the Status API sometimes sadly
|
|
// is not possible due to non-low-level arguments. Here this wrapper
|
|
// helps.
|
|
type commandSet struct {
|
|
statusAPI *api.StatusAPI
|
|
}
|
|
|
|
// newCommandSet creates the command set for the passed Status API
|
|
// instance.
|
|
func newCommandSet(statusAPI *api.StatusAPI) *commandSet {
|
|
return &commandSet{
|
|
statusAPI: statusAPI,
|
|
}
|
|
}
|
|
|
|
// StartNode loads the configuration out of the passed string and
|
|
// starts a node with it.
|
|
func (cs *commandSet) StartNode(config string) error {
|
|
nodeConfig, err := params.LoadNodeConfig(config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return cs.statusAPI.StartNode(nodeConfig)
|
|
}
|
|
|
|
// StopNode starts the stopped node.
|
|
func (cs *commandSet) StopNode() error {
|
|
return cs.statusAPI.StopNode()
|
|
}
|
|
|
|
// ResetChainData removes chain data from data directory.
|
|
func (cs *commandSet) ResetChainData() error {
|
|
return cs.statusAPI.ResetChainData()
|
|
}
|
|
|
|
// CallRPC calls status node via RPC.
|
|
func (cs *commandSet) CallRPC(inputJSON string) string {
|
|
return cs.statusAPI.CallRPC(inputJSON)
|
|
}
|
|
|
|
// CreateAccount creates an internal geth account.
|
|
func (cs *commandSet) CreateAccount(password string) (string, string, string, error) {
|
|
return cs.statusAPI.CreateAccount(password)
|
|
}
|
|
|
|
// CreateChildAccount creates a sub-account.
|
|
func (cs *commandSet) CreateChildAccount(parentAddress, password string) (string, string, error) {
|
|
return cs.statusAPI.CreateChildAccount(parentAddress, password)
|
|
}
|
|
|
|
// RecoverAccount re-creates the master key using the given details.
|
|
func (cs *commandSet) RecoverAccount(password, mnemonic string) (string, string, error) {
|
|
return cs.statusAPI.RecoverAccount(password, mnemonic)
|
|
}
|
|
|
|
// SelectAccount selects the addressed account.
|
|
func (cs *commandSet) SelectAccount(address, password string) error {
|
|
return cs.statusAPI.SelectAccount(address, password)
|
|
}
|
|
|
|
// Logout clears the Whisper identities.
|
|
func (cs *commandSet) Logout() error {
|
|
return cs.statusAPI.Logout()
|
|
}
|
|
|
|
// CompleteTransaction instructs API to complete sending of a given transaction.
|
|
func (cs *commandSet) CompleteTransaction(id, password string) (string, error) {
|
|
txHash, err := cs.statusAPI.CompleteTransaction(common.QueuedTxID(id), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return txHash.String(), nil
|
|
}
|