Separate ws command handlers into separate funcs.

This commit is contained in:
Josh Rickmar 2013-11-04 13:50:24 -05:00
parent 53e1c2d6bd
commit 1f087adf15

View file

@ -305,6 +305,7 @@ func jsonRPCRead(w http.ResponseWriter, r *http.Request, s *rpcServer) {
} }
type commandHandler func(*rpcServer, btcjson.Cmd, chan []byte) (interface{}, error) type commandHandler func(*rpcServer, btcjson.Cmd, chan []byte) (interface{}, error)
type wsCommandHandler func(*rpcServer, *btcjson.Message, chan []byte, chan *btcjson.Reply) error
var handlers = map[string]commandHandler{ var handlers = map[string]commandHandler{
"addnode": handleAddNode, "addnode": handleAddNode,
@ -325,6 +326,14 @@ var handlers = map[string]commandHandler{
"stop": handleStop, "stop": handleStop,
} }
var wsHandlers = map[string]wsCommandHandler{
"getcurrentnet": handleGetCurrentNet,
"getbestblock": handleGetBestBlock,
"rescan": handleRescan,
"notifynewtxs": handleNotifyNewTxs,
"notifyspent": handleNotifySpent,
}
// handleDecodeRawTransaction handles decoderawtransaction commands. // handleDecodeRawTransaction handles decoderawtransaction commands.
func handleAddNode(s *rpcServer, cmd btcjson.Cmd, func handleAddNode(s *rpcServer, cmd btcjson.Cmd,
walletNotification chan []byte) (interface{}, error) { walletNotification chan []byte) (interface{}, error) {
@ -723,93 +732,91 @@ func jsonRead(body []byte, s *rpcServer, walletNotification chan []byte) (reply
return reply, err return reply, err
} }
func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, body []byte, s *rpcServer) error { // handleGetCurrentNet implements the getcurrentnet command extension
var message btcjson.Message // for websocket connections.
err := json.Unmarshal(body, &message) func handleGetCurrentNet(s *rpcServer, message *btcjson.Message,
if err != nil { walletNotification chan []byte, replychan chan *btcjson.Reply) error {
reply := btcjson.Reply{
Result: nil,
Error: &btcjson.ErrParse,
Id: nil,
}
log.Tracef("RPCS: reply: %v", reply)
replychan <- &reply
return fmt.Errorf("RPCS: Error unmarshalling json message: %v", err)
}
log.Tracef("RPCS: received: %v", message)
var rawReply btcjson.Reply
defer func() {
replychan <- &rawReply
close(replychan)
}()
// Deal with commands
switch message.Method {
case "getcurrentnet":
var net btcwire.BitcoinNet var net btcwire.BitcoinNet
if cfg.TestNet3 { if cfg.TestNet3 {
net = btcwire.TestNet3 net = btcwire.TestNet3
} else { } else {
net = btcwire.MainNet net = btcwire.MainNet
} }
rawReply = btcjson.Reply{
rawReply := &btcjson.Reply{
Result: float64(net), Result: float64(net),
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return nil
}
// handleGetBestBlock implements the getbestblock command extension
// for websocket connections.
func handleGetBestBlock(s *rpcServer, message *btcjson.Message,
walletNotification chan []byte, replychan chan *btcjson.Reply) error {
case "getbestblock":
// All other "get block" commands give either the height, the // All other "get block" commands give either the height, the
// hash, or both but require the block SHA. This gets both for // hash, or both but require the block SHA. This gets both for
// the best block. // the best block.
sha, height, err := s.server.db.NewestSha() sha, height, err := s.server.db.NewestSha()
if err != nil { if err != nil {
log.Errorf("RPCS: Error getting newest block: %v", err) log.Errorf("RPCS: Error getting newest block: %v", err)
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrBestBlockHash, Error: &btcjson.ErrBestBlockHash,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return err return err
} }
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: map[string]interface{}{ Result: map[string]interface{}{
"hash": sha.String(), "hash": sha.String(),
"height": height, "height": height,
}, },
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return nil
}
// handleRescan implements the rescan command extension for websocket
// connections.
func handleRescan(s *rpcServer, message *btcjson.Message,
walletNotification chan []byte, replychan chan *btcjson.Reply) error {
case "rescan":
minblock, maxblock := int64(0), btcdb.AllShas minblock, maxblock := int64(0), btcdb.AllShas
params, ok := message.Params.([]interface{}) params, ok := message.Params.([]interface{})
if !ok || len(params) < 2 { if !ok || len(params) < 2 {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
fminblock, ok := params[0].(float64) fminblock, ok := params[0].(float64)
if !ok { if !ok {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
minblock = int64(fminblock) minblock = int64(fminblock)
iaddrs, ok := params[1].([]interface{}) iaddrs, ok := params[1].([]interface{})
if !ok { if !ok {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
@ -818,21 +825,23 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
for i := range iaddrs { for i := range iaddrs {
addr, ok := iaddrs[i].(string) addr, ok := iaddrs[i].(string)
if !ok { if !ok {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
addrhash, _, err := btcutil.DecodeAddress(addr) addrhash, _, err := btcutil.DecodeAddress(addr)
if err != nil { if err != nil {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
@ -842,11 +851,12 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
if len(params) > 2 { if len(params) > 2 {
fmaxblock, ok := params[2].(float64) fmaxblock, ok := params[2].(float64)
if !ok { if !ok {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
maxblock = int64(fmaxblock) maxblock = int64(fmaxblock)
@ -890,7 +900,7 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
return err return err
} }
if ok := addrHashes[string(txaddrhash)]; ok { if ok := addrHashes[string(txaddrhash)]; ok {
reply := btcjson.Reply{ reply := &btcjson.Reply{
Result: struct { Result: struct {
Sender string `json:"sender"` Sender string `json:"sender"`
Receiver string `json:"receiver"` Receiver string `json:"receiver"`
@ -915,7 +925,7 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
Error: nil, Error: nil,
Id: &message.Id, Id: &message.Id,
} }
replychan <- &reply replychan <- reply
} }
} }
} }
@ -928,31 +938,40 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
} }
} }
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: nil, Error: nil,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
log.Debug("RPCS: Finished rescan") log.Debug("RPCS: Finished rescan")
return nil
}
// handleNotifyNewTxs implements the notifynewtxs command extension for
// websocket connections.
func handleNotifyNewTxs(s *rpcServer, message *btcjson.Message,
walletNotification chan []byte, replychan chan *btcjson.Reply) error {
case "notifynewtxs":
params, ok := message.Params.([]interface{}) params, ok := message.Params.([]interface{})
if !ok || len(params) != 1 { if !ok || len(params) != 1 {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
addr, ok := params[0].(string) addr, ok := params[0].(string)
if !ok { if !ok {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
addrhash, _, err := btcutil.DecodeAddress(addr) addrhash, _, err := btcutil.DecodeAddress(addr)
@ -961,39 +980,49 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
Code: btcjson.ErrInvalidParams.Code, Code: btcjson.ErrInvalidParams.Code,
Message: "Cannot decode address", Message: "Cannot decode address",
} }
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &jsonError, Error: &jsonError,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
s.ws.requests.AddTxRequest(walletNotification, string(addrhash), message.Id) s.ws.requests.AddTxRequest(walletNotification, string(addrhash), message.Id)
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: nil, Error: nil,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return nil
}
// handleNotifySpent implements the notifyspent command extension for
// websocket connections.
func handleNotifySpent(s *rpcServer, message *btcjson.Message,
walletNotification chan []byte, replychan chan *btcjson.Reply) error {
case "notifyspent":
params, ok := message.Params.([]interface{}) params, ok := message.Params.([]interface{})
if !ok || len(params) != 2 { if !ok || len(params) != 2 {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
hashBE, ok1 := params[0].(string) hashBE, ok1 := params[0].(string)
index, ok2 := params[1].(float64) index, ok2 := params[1].(float64)
if !ok1 || !ok2 { if !ok1 || !ok2 {
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrInvalidParams, Error: &btcjson.ErrInvalidParams,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
hash, err := btcwire.NewShaHashFromStr(hashBE) hash, err := btcwire.NewShaHashFromStr(hashBE)
@ -1002,30 +1031,82 @@ func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, b
Code: btcjson.ErrInvalidParams.Code, Code: btcjson.ErrInvalidParams.Code,
Message: "Hash string cannot be parsed.", Message: "Hash string cannot be parsed.",
} }
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &jsonError, Error: &jsonError,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return ErrBadParamsField return ErrBadParamsField
} }
op := btcwire.NewOutPoint(hash, uint32(index)) op := btcwire.NewOutPoint(hash, uint32(index))
s.ws.requests.AddSpentRequest(walletNotification, op, message.Id) s.ws.requests.AddSpentRequest(walletNotification, op, message.Id)
rawReply = btcjson.Reply{ rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: nil, Error: nil,
Id: &message.Id, Id: &message.Id,
} }
replychan <- rawReply
return nil
}
default: func jsonWSRead(walletNotification chan []byte, replychan chan *btcjson.Reply, body []byte, s *rpcServer) error {
rawReply = btcjson.Reply{ var message btcjson.Message
err := json.Unmarshal(body, &message)
if err != nil {
reply := btcjson.Reply{
Result: nil,
Error: &btcjson.ErrParse,
Id: nil,
}
log.Tracef("RPCS: reply: %v", reply)
replychan <- &reply
return fmt.Errorf("RPCS: Error unmarshalling json message: %v", err)
}
log.Tracef("RPCS: received: %v", message)
defer func() {
close(replychan)
}()
wsHandler, ok := wsHandlers[message.Method]
if !ok {
rawReply := &btcjson.Reply{
Result: nil, Result: nil,
Error: &btcjson.ErrMethodNotFound, Error: &btcjson.ErrMethodNotFound,
Id: &message.Id, Id: &message.Id,
} }
} replychan <- rawReply
return btcjson.ErrMethodNotFound return btcjson.ErrMethodNotFound
}
if err := wsHandler(s, &message, walletNotification, replychan); err != nil {
if jsonErr, ok := err.(btcjson.Error); ok {
rawReply := &btcjson.Reply{
Error: &jsonErr,
Id: &message.Id,
}
replychan <- rawReply
err = errors.New(jsonErr.Message)
} else {
// In the case where we did not have a btcjson
// error to begin with, make a new one to send,
// but this really should not happen.
rawJSONError := btcjson.Error{
Code: btcjson.ErrInternal.Code,
Message: err.Error(),
}
rawReply := &btcjson.Reply{
Error: &rawJSONError,
Id: &message.Id,
}
replychan <- rawReply
}
}
return err
} }
// getDifficultyRatio returns the proof-of-work difficulty as a multiple of the // getDifficultyRatio returns the proof-of-work difficulty as a multiple of the