Merge pull request #78 from farazdagi/feature/restart-rpc

node_manager: start/stop RPC server methods added
This commit is contained in:
Victor Farazdagi 2016-12-11 17:27:13 +03:00 committed by GitHub
commit 4322d71714
5 changed files with 126 additions and 5 deletions

View File

@ -216,6 +216,20 @@ func StartNode(datadir *C.char) *C.char {
return C.CString(string(outBytes)) return C.CString(string(outBytes))
} }
//export StopNodeRPCServer
func StopNodeRPCServer() *C.char {
_, err := geth.NodeManagerInstance().StopNodeRPCServer()
return makeJSONErrorResponse(err)
}
//export StartNodeRPCServer
func StartNodeRPCServer() *C.char {
_, err := geth.NodeManagerInstance().StartNodeRPCServer()
return makeJSONErrorResponse(err)
}
//export InitJail //export InitJail
func InitJail(js *C.char) { func InitJail(js *C.char) {
jail.Init(C.GoString(js)) jail.Init(C.GoString(js))
@ -287,3 +301,18 @@ func RemoveWhisperFilter(idFilter int) {
func ClearWhisperFilters() { func ClearWhisperFilters() {
geth.ClearWhisperFilters() geth.ClearWhisperFilters()
} }
func makeJSONErrorResponse(err error) *C.char {
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := geth.JSONError{
Error: errString,
}
outBytes, _ := json.Marshal(&out)
return C.CString(string(outBytes))
}

View File

@ -35,6 +35,10 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
name string name string
fn func(t *testing.T) bool fn func(t *testing.T) bool
}{ }{
{
"restart node RPC",
testRestartNodeRPC,
},
{ {
"create main and child accounts", "create main and child accounts",
testCreateChildAccount, testCreateChildAccount,
@ -86,6 +90,50 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
done <- struct{}{} done <- struct{}{}
} }
func testRestartNodeRPC(t *testing.T) bool {
// stop RPC
stopNodeRPCServerResponse := geth.JSONError{}
rawResponse := StopNodeRPCServer()
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &stopNodeRPCServerResponse); err != nil {
t.Errorf("cannot decode StopNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
return false
}
if stopNodeRPCServerResponse.Error != "" {
t.Errorf("unexpected error: %s", stopNodeRPCServerResponse.Error)
return false
}
// start again RPC
startNodeRPCServerResponse := geth.JSONError{}
rawResponse = StartNodeRPCServer()
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &startNodeRPCServerResponse); err != nil {
t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
return false
}
if startNodeRPCServerResponse.Error != "" {
t.Errorf("unexpected error: %s", startNodeRPCServerResponse.Error)
return false
}
// start when we have RPC already running
startNodeRPCServerResponse = geth.JSONError{}
rawResponse = StartNodeRPCServer()
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &startNodeRPCServerResponse); err != nil {
t.Errorf("cannot decode StartNodeRPCServer reponse (%s): %v", C.GoString(rawResponse), err)
return false
}
expectedError := "HTTP RPC already running on localhost:8545"
if startNodeRPCServerResponse.Error != expectedError {
t.Errorf("expected error not thrown: %s", expectedError)
return false
}
return true
}
func testCreateChildAccount(t *testing.T) bool { func testCreateChildAccount(t *testing.T) bool {
geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests) geth.Logout() // to make sure that we start with empty account (which might get populated during previous tests)

View File

@ -79,6 +79,7 @@ var (
type Node struct { type Node struct {
geth *node.Node // reference to the running Geth node geth *node.Node // reference to the running Geth node
started chan struct{} // channel to wait for node to start started chan struct{} // channel to wait for node to start
config *node.Config
} }
// Inited checks whether status node has been properly initialized // Inited checks whether status node has been properly initialized
@ -135,6 +136,7 @@ func MakeNode(dataDir string, rpcPort int) *Node {
return &Node{ return &Node{
geth: stack, geth: stack,
started: make(chan struct{}), started: make(chan struct{}),
config: config,
} }
} }

View File

@ -14,6 +14,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
@ -21,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
@ -35,9 +37,10 @@ type SelectedExtKey struct {
// NodeManager manages Status node (which abstracts contained geth node) // NodeManager manages Status node (which abstracts contained geth node)
type NodeManager struct { type NodeManager struct {
node *Node // reference to Status node node *Node // reference to Status node
services *NodeServiceStack // default stack of services running on geth node services *NodeServiceStack // default stack of services running on geth node
SelectedAccount *SelectedExtKey // account that was processed during the last call to SelectAccount() api *node.PrivateAdminAPI // exposes collection of administrative API methods
SelectedAccount *SelectedExtKey // account that was processed during the last call to SelectAccount()
} }
// NodeServiceStack contains "standard" node services (which are always available) // NodeServiceStack contains "standard" node services (which are always available)
@ -58,6 +61,7 @@ var (
ErrInvalidJailedRequestQueue = errors.New("jailed request queue is not properly initialized") ErrInvalidJailedRequestQueue = errors.New("jailed request queue is not properly initialized")
ErrNodeMakeFailure = errors.New("error creating p2p node") ErrNodeMakeFailure = errors.New("error creating p2p node")
ErrNodeStartFailure = errors.New("error starting p2p node") ErrNodeStartFailure = errors.New("error starting p2p node")
ErrInvalidNodeAPI = errors.New("no node API connected")
) )
var ( var (
@ -128,7 +132,9 @@ func (m *NodeManager) RunNode() {
glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient) glog.V(logger.Warn).Infoln("cannot get RPC client service:", ErrInvalidClient)
} }
// @TODO Remove after LES supports discover out of box // expose API
m.api = node.NewPrivateAdminAPI(m.node.geth)
m.populateStaticPeers() m.populateStaticPeers()
m.onNodeStarted() // node started, notify listeners m.onNodeStarted() // node started, notify listeners
@ -164,6 +170,42 @@ func (m *NodeManager) StartNode() {
}() }()
} }
func (m *NodeManager) RestartNode() error {
if m == nil || !m.NodeInited() {
return ErrInvalidGethNode
}
return m.node.geth.Restart()
}
func (m *NodeManager) StartNodeRPCServer() (bool, error) {
if m == nil || !m.NodeInited() {
return false, ErrInvalidGethNode
}
if m.api == nil {
return false, ErrInvalidNodeAPI
}
config := m.node.config
modules := strings.Join(config.HTTPModules, ",")
return m.api.StartRPC(&config.HTTPHost, rpc.NewHexNumber(config.HTTPPort), &config.HTTPCors, &modules)
}
// StopNodeRPCServer stops HTTP RPC service attached to node
func (m *NodeManager) StopNodeRPCServer() (bool, error) {
if m == nil || !m.NodeInited() {
return false, ErrInvalidGethNode
}
if m.api == nil {
return false, ErrInvalidNodeAPI
}
return m.api.StopRPC()
}
// HasNode checks whether manager has initialized node attached // HasNode checks whether manager has initialized node attached
func (m *NodeManager) NodeInited() bool { func (m *NodeManager) NodeInited() bool {
if m == nil || !m.node.Inited() { if m == nil || !m.node.Inited() {

View File

@ -193,7 +193,7 @@ func TestJailRPCSend(t *testing.T) {
return return
} }
if balance < 90 || balance > 100 { if balance < 100 {
t.Error("wrong balance (there should be lots of test Ether on that account)") t.Error("wrong balance (there should be lots of test Ether on that account)")
return return
} }