added admin API
This commit is contained in:
committed by
Bas van Kervel
parent
08d72a9245
commit
cc9ae39933
228
rpc/api/admin.go
Normal file
228
rpc/api/admin.go
Normal file
@ -0,0 +1,228 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||
"github.com/ethereum/go-ethereum/xeth"
|
||||
)
|
||||
|
||||
const (
|
||||
AdminVersion = "1.0.0"
|
||||
importBatchSize = 2500
|
||||
)
|
||||
|
||||
var (
|
||||
// mapping between methods and handlers
|
||||
AdminMapping = map[string]adminhandler{
|
||||
// "admin_startRPC": (*adminApi).StartRPC,
|
||||
// "admin_stopRPC": (*adminApi).StopRPC,
|
||||
"admin_addPeer": (*adminApi).AddPeer,
|
||||
"admin_peers": (*adminApi).Peers,
|
||||
"admin_nodeInfo": (*adminApi).NodeInfo,
|
||||
"admin_exportChain": (*adminApi).ExportChain,
|
||||
"admin_importChain": (*adminApi).ImportChain,
|
||||
"admin_verbosity": (*adminApi).Verbosity,
|
||||
"admin_syncStatus": (*adminApi).SyncStatus,
|
||||
"admin_setSolc": (*adminApi).SetSolc,
|
||||
}
|
||||
)
|
||||
|
||||
// admin callback handler
|
||||
type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
|
||||
|
||||
// admin api provider
|
||||
type adminApi struct {
|
||||
xeth *xeth.XEth
|
||||
ethereum *eth.Ethereum
|
||||
methods map[string]adminhandler
|
||||
codec codec.ApiCoder
|
||||
}
|
||||
|
||||
// create a new admin api instance
|
||||
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *adminApi {
|
||||
return &adminApi{
|
||||
xeth: xeth,
|
||||
ethereum: ethereum,
|
||||
methods: AdminMapping,
|
||||
codec: coder.New(nil),
|
||||
}
|
||||
}
|
||||
|
||||
// collection with supported methods
|
||||
func (self *adminApi) Methods() []string {
|
||||
methods := make([]string, len(self.methods))
|
||||
i := 0
|
||||
for k := range self.methods {
|
||||
methods[i] = k
|
||||
i++
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
// Execute given request
|
||||
func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
|
||||
if callback, ok := self.methods[req.Method]; ok {
|
||||
return callback(self, req)
|
||||
}
|
||||
|
||||
return nil, &shared.NotImplementedError{req.Method}
|
||||
}
|
||||
|
||||
func (self *adminApi) Name() string {
|
||||
return AdminApiName
|
||||
}
|
||||
|
||||
func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
|
||||
args := new(AddPeerArgs)
|
||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
return nil, shared.NewDecodeParamError(err.Error())
|
||||
}
|
||||
|
||||
err := self.ethereum.AddPeer(args.Url)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
|
||||
return self.ethereum.PeersInfo(), nil
|
||||
}
|
||||
|
||||
func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
|
||||
return false, nil
|
||||
// Enable when http rpc interface is refactored to prevent import cycles
|
||||
// args := new(StartRpcArgs)
|
||||
// if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
// return nil, shared.NewDecodeParamError(err.Error())
|
||||
// }
|
||||
//
|
||||
// cfg := rpc.RpcConfig{
|
||||
// ListenAddress: args.Address,
|
||||
// ListenPort: args.Port,
|
||||
// }
|
||||
//
|
||||
// err := rpc.Start(self.xeth, cfg)
|
||||
// if err == nil {
|
||||
// return true, nil
|
||||
// }
|
||||
// return false, err
|
||||
}
|
||||
|
||||
func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
|
||||
return false, nil
|
||||
// Enable when http rpc interface is refactored to prevent import cycles
|
||||
// rpc.Stop()
|
||||
// return true, nil
|
||||
}
|
||||
|
||||
func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
|
||||
return self.ethereum.NodeInfo(), nil
|
||||
}
|
||||
|
||||
func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
|
||||
for _, b := range bs {
|
||||
if !chain.HasBlock(b.Hash()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
|
||||
args := new(ImportExportChainArgs)
|
||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
return nil, shared.NewDecodeParamError(err.Error())
|
||||
}
|
||||
|
||||
fh, err := os.Open(args.Filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer fh.Close()
|
||||
stream := rlp.NewStream(fh, 0)
|
||||
|
||||
// Run actual the import.
|
||||
blocks := make(types.Blocks, importBatchSize)
|
||||
n := 0
|
||||
for batch := 0; ; batch++ {
|
||||
|
||||
i := 0
|
||||
for ; i < importBatchSize; i++ {
|
||||
var b types.Block
|
||||
if err := stream.Decode(&b); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return false, fmt.Errorf("at block %d: %v", n, err)
|
||||
}
|
||||
blocks[i] = &b
|
||||
n++
|
||||
}
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
// Import the batch.
|
||||
if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) {
|
||||
continue
|
||||
}
|
||||
if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil {
|
||||
return false, fmt.Errorf("invalid block %d: %v", n, err)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
|
||||
args := new(ImportExportChainArgs)
|
||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
return nil, shared.NewDecodeParamError(err.Error())
|
||||
}
|
||||
|
||||
fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer fh.Close()
|
||||
if err := self.ethereum.ChainManager().Export(fh); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
|
||||
args := new(VerbosityArgs)
|
||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
return nil, shared.NewDecodeParamError(err.Error())
|
||||
}
|
||||
|
||||
glog.SetV(args.Level)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (self *adminApi) SyncStatus(req *shared.Request) (interface{}, error) {
|
||||
pending, cached := self.ethereum.Downloader().Stats()
|
||||
return map[string]interface{}{"available": pending, "waitingForImport": cached}, nil
|
||||
}
|
||||
|
||||
func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
|
||||
args := new(SetSolcArgs)
|
||||
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||
return nil, shared.NewDecodeParamError(err.Error())
|
||||
}
|
||||
|
||||
solc, err := self.xeth.SetSolc(args.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return solc.Info(), nil
|
||||
}
|
Reference in New Issue
Block a user