forked from cerc-io/plugeth
added shh API
This commit is contained in:
parent
bd38428f33
commit
7e41d7ac51
@ -13,7 +13,8 @@ const (
|
|||||||
MergedApiName = "merged"
|
MergedApiName = "merged"
|
||||||
MinerApiName = "miner"
|
MinerApiName = "miner"
|
||||||
NetApiName = "net"
|
NetApiName = "net"
|
||||||
txPoolApiName = "txpool"
|
ShhApiName = "shh"
|
||||||
|
TxPoolApiName = "txpool"
|
||||||
PersonalApiName = "personal"
|
PersonalApiName = "personal"
|
||||||
Web3ApiName = "web3"
|
Web3ApiName = "web3"
|
||||||
)
|
)
|
||||||
@ -21,7 +22,8 @@ const (
|
|||||||
var (
|
var (
|
||||||
// List with all API's which are offered over the IPC interface by default
|
// List with all API's which are offered over the IPC interface by default
|
||||||
DefaultIpcApis = strings.Join([]string{
|
DefaultIpcApis = strings.Join([]string{
|
||||||
AdminApiName, EthApiName, DebugApiName, MinerApiName, NetApiName, txPoolApiName, PersonalApiName, Web3ApiName,
|
AdminApiName, EthApiName, DebugApiName, MinerApiName, NetApiName,
|
||||||
|
ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName,
|
||||||
}, ",")
|
}, ",")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
171
rpc/api/shh.go
Normal file
171
rpc/api/shh.go
Normal file
@ -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
|
||||||
|
}
|
158
rpc/api/shh_args.go
Normal file
158
rpc/api/shh_args.go
Normal file
@ -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
|
||||||
|
}
|
30
rpc/api/ssh_js.go
Normal file
30
rpc/api/ssh_js.go
Normal file
@ -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
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||
|
`
|
@ -56,7 +56,7 @@ func (self *txPoolApi) Execute(req *shared.Request) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *txPoolApi) Name() string {
|
func (self *txPoolApi) Name() string {
|
||||||
return txPoolApiName
|
return TxPoolApiName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *txPoolApi) Status(req *shared.Request) (interface{}, error) {
|
func (self *txPoolApi) Status(req *shared.Request) (interface{}, error) {
|
||||||
|
@ -31,7 +31,9 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
|
|||||||
apis[i] = NewMinerApi(eth, codec)
|
apis[i] = NewMinerApi(eth, codec)
|
||||||
case NetApiName:
|
case NetApiName:
|
||||||
apis[i] = NewNetApi(xeth, eth, codec)
|
apis[i] = NewNetApi(xeth, eth, codec)
|
||||||
case txPoolApiName:
|
case ShhApiName:
|
||||||
|
apis[i] = NewShhApi(xeth, eth, codec)
|
||||||
|
case TxPoolApiName:
|
||||||
apis[i] = NewTxPoolApi(xeth, eth, codec)
|
apis[i] = NewTxPoolApi(xeth, eth, codec)
|
||||||
case PersonalApiName:
|
case PersonalApiName:
|
||||||
apis[i] = NewPersonalApi(xeth, eth, codec)
|
apis[i] = NewPersonalApi(xeth, eth, codec)
|
||||||
@ -55,7 +57,9 @@ func Javascript(name string) string {
|
|||||||
return Miner_JS
|
return Miner_JS
|
||||||
case NetApiName:
|
case NetApiName:
|
||||||
return Net_JS
|
return Net_JS
|
||||||
case txPoolApiName:
|
case ShhApiName:
|
||||||
|
return Shh_JS
|
||||||
|
case TxPoolApiName:
|
||||||
return TxPool_JS
|
return TxPool_JS
|
||||||
case PersonalApiName:
|
case PersonalApiName:
|
||||||
return Personal_JS
|
return Personal_JS
|
||||||
|
Loading…
Reference in New Issue
Block a user