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