mirror of https://github.com/ethereum/go-ethereum
parent
bd38428f33
commit
7e41d7ac51
@ -0,0 +1,171 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/eth" |
||||||
|
"github.com/ethereum/go-ethereum/rpc/codec" |
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared" |
||||||
|
"github.com/ethereum/go-ethereum/xeth" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
// mapping between methods and handlers
|
||||||
|
shhMapping = map[string]shhhandler{ |
||||||
|
"shh_version": (*shhApi).Version, |
||||||
|
"shh_post": (*shhApi).Post, |
||||||
|
"shh_hasIdentity": (*shhApi).HasIdentity, |
||||||
|
"shh_newIdentity": (*shhApi).NewIdentity, |
||||||
|
"shh_newFilter": (*shhApi).NewFilter, |
||||||
|
"shh_uninstallFilter": (*shhApi).UninstallFilter, |
||||||
|
"shh_getFilterChanges": (*shhApi).GetFilterChanges, |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
func newWhisperOfflineError(method string) error { |
||||||
|
return shared.NewNotAvailableError(method, "whisper offline") |
||||||
|
} |
||||||
|
|
||||||
|
// net callback handler
|
||||||
|
type shhhandler func(*shhApi, *shared.Request) (interface{}, error) |
||||||
|
|
||||||
|
// shh api provider
|
||||||
|
type shhApi struct { |
||||||
|
xeth *xeth.XEth |
||||||
|
ethereum *eth.Ethereum |
||||||
|
methods map[string]shhhandler |
||||||
|
codec codec.ApiCoder |
||||||
|
} |
||||||
|
|
||||||
|
// create a new whisper api instance
|
||||||
|
func NewShhApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *shhApi { |
||||||
|
return &shhApi{ |
||||||
|
xeth: xeth, |
||||||
|
ethereum: eth, |
||||||
|
methods: shhMapping, |
||||||
|
codec: coder.New(nil), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// collection with supported methods
|
||||||
|
func (self *shhApi) 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 *shhApi) Execute(req *shared.Request) (interface{}, error) { |
||||||
|
if callback, ok := self.methods[req.Method]; ok { |
||||||
|
return callback(self, req) |
||||||
|
} |
||||||
|
|
||||||
|
return nil, shared.NewNotImplementedError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) Name() string { |
||||||
|
return ShhApiName |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) Version(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
return w.Version(), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) Post(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
args := new(WhisperMessageArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
err := w.Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl) |
||||||
|
if err != nil { |
||||||
|
return false, err |
||||||
|
} |
||||||
|
|
||||||
|
return true, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) HasIdentity(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
args := new(WhisperIdentityArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return w.HasIdentity(args.Identity), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) NewIdentity(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
return w.NewIdentity(), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) NewFilter(req *shared.Request) (interface{}, error) { |
||||||
|
args := new(WhisperFilterArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
id := self.xeth.NewWhisperFilter(args.To, args.From, args.Topics) |
||||||
|
return newHexNum(big.NewInt(int64(id)).Bytes()), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) UninstallFilter(req *shared.Request) (interface{}, error) { |
||||||
|
args := new(FilterIdArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return self.xeth.UninstallWhisperFilter(args.Id), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) GetFilterChanges(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
// Retrieve all the new messages arrived since the last request
|
||||||
|
args := new(FilterIdArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return self.xeth.WhisperMessagesChanged(args.Id), nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *shhApi) GetMessages(req *shared.Request) (interface{}, error) { |
||||||
|
w := self.xeth.Whisper() |
||||||
|
if w == nil { |
||||||
|
return nil, newWhisperOfflineError(req.Method) |
||||||
|
} |
||||||
|
|
||||||
|
// Retrieve all the cached messages matching a specific, existing filter
|
||||||
|
args := new(FilterIdArgs) |
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return self.xeth.WhisperMessages(args.Id), nil |
||||||
|
} |
@ -0,0 +1,158 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"math/big" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rpc/shared" |
||||||
|
) |
||||||
|
|
||||||
|
type WhisperMessageArgs struct { |
||||||
|
Payload string |
||||||
|
To string |
||||||
|
From string |
||||||
|
Topics []string |
||||||
|
Priority uint32 |
||||||
|
Ttl uint32 |
||||||
|
} |
||||||
|
|
||||||
|
func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) { |
||||||
|
var obj []struct { |
||||||
|
Payload string |
||||||
|
To string |
||||||
|
From string |
||||||
|
Topics []string |
||||||
|
Priority interface{} |
||||||
|
Ttl interface{} |
||||||
|
} |
||||||
|
|
||||||
|
if err = json.Unmarshal(b, &obj); err != nil { |
||||||
|
return shared.NewDecodeParamError(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
if len(obj) < 1 { |
||||||
|
return shared.NewInsufficientParamsError(len(obj), 1) |
||||||
|
} |
||||||
|
args.Payload = obj[0].Payload |
||||||
|
args.To = obj[0].To |
||||||
|
args.From = obj[0].From |
||||||
|
args.Topics = obj[0].Topics |
||||||
|
|
||||||
|
var num *big.Int |
||||||
|
if num, err = numString(obj[0].Priority); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
args.Priority = uint32(num.Int64()) |
||||||
|
|
||||||
|
if num, err = numString(obj[0].Ttl); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
args.Ttl = uint32(num.Int64()) |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type WhisperIdentityArgs struct { |
||||||
|
Identity string |
||||||
|
} |
||||||
|
|
||||||
|
func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) { |
||||||
|
var obj []interface{} |
||||||
|
if err := json.Unmarshal(b, &obj); err != nil { |
||||||
|
return shared.NewDecodeParamError(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
if len(obj) < 1 { |
||||||
|
return shared.NewInsufficientParamsError(len(obj), 1) |
||||||
|
} |
||||||
|
|
||||||
|
argstr, ok := obj[0].(string) |
||||||
|
if !ok { |
||||||
|
return shared.NewInvalidTypeError("arg0", "not a string") |
||||||
|
} |
||||||
|
|
||||||
|
args.Identity = argstr |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
type WhisperFilterArgs struct { |
||||||
|
To string |
||||||
|
From string |
||||||
|
Topics [][]string |
||||||
|
} |
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a
|
||||||
|
// JSON message blob into a WhisperFilterArgs structure.
|
||||||
|
func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { |
||||||
|
// Unmarshal the JSON message and sanity check
|
||||||
|
var obj []struct { |
||||||
|
To interface{} `json:"to"` |
||||||
|
From interface{} `json:"from"` |
||||||
|
Topics interface{} `json:"topics"` |
||||||
|
} |
||||||
|
if err := json.Unmarshal(b, &obj); err != nil { |
||||||
|
return shared.NewDecodeParamError(err.Error()) |
||||||
|
} |
||||||
|
if len(obj) < 1 { |
||||||
|
return shared.NewInsufficientParamsError(len(obj), 1) |
||||||
|
} |
||||||
|
// Retrieve the simple data contents of the filter arguments
|
||||||
|
if obj[0].To == nil { |
||||||
|
args.To = "" |
||||||
|
} else { |
||||||
|
argstr, ok := obj[0].To.(string) |
||||||
|
if !ok { |
||||||
|
return shared.NewInvalidTypeError("to", "is not a string") |
||||||
|
} |
||||||
|
args.To = argstr |
||||||
|
} |
||||||
|
if obj[0].From == nil { |
||||||
|
args.From = "" |
||||||
|
} else { |
||||||
|
argstr, ok := obj[0].From.(string) |
||||||
|
if !ok { |
||||||
|
return shared.NewInvalidTypeError("from", "is not a string") |
||||||
|
} |
||||||
|
args.From = argstr |
||||||
|
} |
||||||
|
// Construct the nested topic array
|
||||||
|
if obj[0].Topics != nil { |
||||||
|
// Make sure we have an actual topic array
|
||||||
|
list, ok := obj[0].Topics.([]interface{}) |
||||||
|
if !ok { |
||||||
|
return shared.NewInvalidTypeError("topics", "is not an array") |
||||||
|
} |
||||||
|
// Iterate over each topic and handle nil, string or array
|
||||||
|
topics := make([][]string, len(list)) |
||||||
|
for idx, field := range list { |
||||||
|
switch value := field.(type) { |
||||||
|
case nil: |
||||||
|
topics[idx] = []string{} |
||||||
|
|
||||||
|
case string: |
||||||
|
topics[idx] = []string{value} |
||||||
|
|
||||||
|
case []interface{}: |
||||||
|
topics[idx] = make([]string, len(value)) |
||||||
|
for i, nested := range value { |
||||||
|
switch value := nested.(type) { |
||||||
|
case nil: |
||||||
|
topics[idx][i] = "" |
||||||
|
|
||||||
|
case string: |
||||||
|
topics[idx][i] = value |
||||||
|
|
||||||
|
default: |
||||||
|
return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", idx, i), "is not a string") |
||||||
|
} |
||||||
|
} |
||||||
|
default: |
||||||
|
return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", idx), "not a string or array") |
||||||
|
} |
||||||
|
} |
||||||
|
args.Topics = topics |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
package api |
||||||
|
|
||||||
|
const Shh_JS = ` |
||||||
|
web3._extend({ |
||||||
|
property: 'shh', |
||||||
|
methods: |
||||||
|
[ |
||||||
|
new web3._extend.Method({ |
||||||
|
name: 'post', |
||||||
|
call: 'shh_post', |
||||||
|
params: 6, |
||||||
|
inputFormatter: [web3._extend.formatters.formatInputString, |
||||||
|
web3._extend.formatters.formatInputString, |
||||||
|
web3._extend.formatters.formatInputString, |
||||||
|
, |
||||||
|
, web3._extend.formatters.formatInputInt |
||||||
|
, web3._extend.formatters.formatInputInt], |
||||||
|
outputFormatter: web3._extend.formatters.formatOutputBool |
||||||
|
}), |
||||||
|
], |
||||||
|
properties: |
||||||
|
[ |
||||||
|
new web3._extend.Property({ |
||||||
|
name: 'version', |
||||||
|
getter: 'shh_version', |
||||||
|
outputFormatter: web3._extend.formatters.formatOutputInt |
||||||
|
}) |
||||||
|
] |
||||||
|
}); |
||||||
|
` |
Loading…
Reference in new issue