support for go-ethereum/rpc

This commit is contained in:
Adrià Cidre 2018-05-11 07:55:55 +02:00
parent 8cbd6ec442
commit aa8eb8f5f7
No known key found for this signature in database
GPG Key ID: D246A27D58A92CAB
7 changed files with 119 additions and 195 deletions

View File

@ -25,13 +25,12 @@ func (a *Account) CreatePrivateChannel(name, password string) (*Channel, error)
}
func (a *Account) createAndJoin(name, password string) (*Channel, error) {
symkeyResponse, err := shhGenerateSymKeyFromPasswordRequest(a.conn, []string{password})
symKey, err := shhGenerateSymKeyFromPasswordRequest(a.conn, password)
if err != nil {
return nil, err
}
symKey := symkeyResponse.Key
topicID, err := a.calculatePublicChannelTopicID(name, symkeyResponse.ID)
topicID, err := a.calculatePublicChannelTopicID(name)
if err != nil {
return nil, err
}
@ -41,13 +40,11 @@ func (a *Account) createAndJoin(name, password string) (*Channel, error) {
// Join joins a status channel
func (a *Account) Join(channelName, topicID, symKey string) (*Channel, error) {
newMessageFilterResponse, err := newShhMessageFilterFormatRequest(a.conn, []string{topicID}, symKey)
filterID, err := newShhMessageFilterFormatRequest(a.conn, []string{topicID}, symKey)
if err != nil {
return nil, err
}
filterID := newMessageFilterResponse.FilterID
ch := &Channel{
account: a,
name: channelName,
@ -60,13 +57,13 @@ func (a *Account) Join(channelName, topicID, symKey string) (*Channel, error) {
return ch, nil
}
func (a *Account) calculatePublicChannelTopicID(name string, symkey int) (topicID string, err error) {
func (a *Account) calculatePublicChannelTopicID(name string) (topicID string, err error) {
p := "0x" + hex.EncodeToString([]byte(name))
web3ShaResponse, err := web3Sha3Request(a.conn, symkey, []string{p})
hash, err := web3Sha3Request(a.conn, p)
if err != nil {
return
}
topicID = web3ShaResponse.Result[0:10]
topicID = hash[0:10]
return
}

14
chan.go
View File

@ -83,10 +83,10 @@ func (c *Channel) Publish(body string) error {
visibility = c.visibility
}
now := time.Now().Unix()
now := time.Now().Unix() * 1000
format := `["%s",["%s","text/plain","%s",%d,%d]]`
msg := fmt.Sprintf(format, StandardMessageType, body, visibility, now*100, now*100)
msg := fmt.Sprintf(format, StandardMessageType, body, visibility, now*100, now)
println("[ SENDING ] : " + msg)
return c.SendPostRawMsg(msg)
@ -116,7 +116,7 @@ func (c *Channel) ContactUpdateRequest(username, image string) error {
// SendPostRawMsg sends a shh_post message with the given body.
func (c *Channel) SendPostRawMsg(body string) error {
param := shhPostParam{
msg := Message{
Signature: c.account.Address,
SymKeyID: c.ChannelKey,
Payload: rawrChatMessage(body),
@ -126,7 +126,7 @@ func (c *Channel) SendPostRawMsg(body string) error {
PowTime: 1,
}
_, err := shhPostRequest(c.account.conn, []*shhPostParam{&param})
_, err := shhPostRequest(c.account.conn, &msg)
if err != nil {
log.Println(err.Error())
}
@ -183,13 +183,13 @@ func (c *Channel) PubKey() string {
}
func (c *Channel) pollMessages() (msg *Msg) {
res, err := shhGetFilterMessagesRequest(c.account.conn, []string{c.filterID})
res, err := shhGetFilterMessagesRequest(c.account.conn, c.filterID)
if err != nil {
log.Fatalf("Error when sending request to server: %s", err)
return
}
switch vv := res.Result.(type) {
switch vv := res.(type) {
case []interface{}:
for _, u := range vv {
msg, err = messageFromEnvelope(u)
@ -206,7 +206,7 @@ func (c *Channel) pollMessages() (msg *Msg) {
return nil
}
default:
log.Println(res.Result, "is of a type I don't know how to handle")
log.Println(res, "is of a type I don't know how to handle")
}
return
}

View File

@ -1,10 +1,5 @@
package sdk
import (
"encoding/json"
"errors"
)
type shhRequest struct {
ID int `json:"id"`
JSONRPC string `json:"jsonrpc"`
@ -17,25 +12,10 @@ type generateSymKeyFromPasswordResponse struct {
ID int `json:"id"`
}
func shhGenerateSymKeyFromPasswordRequest(sdk *SDK, params []string) (res *generateSymKeyFromPasswordResponse, err error) {
func shhGenerateSymKeyFromPasswordRequest(sdk *SDK, password string) (string, error) {
// `{"jsonrpc":"2.0","id":2950,"method":"shh_generateSymKeyFromPassword","params":["%s"]}`
req := shhRequest{
ID: 2950,
JSONRPC: "2.0",
Method: "shh_generateSymKeyFromPassword",
}
for _, p := range params {
req.Params = append(req.Params, p)
}
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
var resp string
return resp, sdk.call("shh_generateSymKeyFromPassword", password, &resp)
}
type shhFilterFormatParam struct {
@ -49,53 +29,27 @@ type newMessageFilterResponse struct {
FilterID string `json:"result"`
}
func newShhMessageFilterFormatRequest(sdk *SDK, topics []string, symKey string) (res newMessageFilterResponse, err error) {
func newShhMessageFilterFormatRequest(sdk *SDK, topics []string, symKey string) (string, error) {
// `{"jsonrpc":"2.0","id":2,"method":"shh_newMessageFilter","params":[{"allowP2P":true,"topics":["%s"],"type":"sym","symKeyID":"%s"}]}`
req := shhRequest{
ID: 2,
JSONRPC: "2.0",
Method: "shh_newMessageFilter",
}
req.Params = append(req.Params, &shhFilterFormatParam{
var res string
params := &shhFilterFormatParam{
AllowP2P: true,
Topics: topics,
Type: "sym",
SymKeyID: symKey,
})
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
return res, sdk.call("shh_newMessageFilter", params, &res)
}
type web3ShaResponse struct {
Result string `json:"result"`
}
func web3Sha3Request(sdk *SDK, id int, params []string) (res *web3ShaResponse, err error) {
func web3Sha3Request(sdk *SDK, data string) (string, error) {
// `{"jsonrpc":"2.0","method":"web3_sha3","params":["%s"],"id":%d}`
req := shhRequest{
ID: id,
JSONRPC: "2.0",
Method: "web3_sha3",
}
for _, p := range params {
req.Params = append(req.Params, p)
}
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
var res string
return res, sdk.call("web3_sha3", data, &res)
}
type statusLoginParam struct {
@ -104,31 +58,19 @@ type statusLoginParam struct {
}
type loginResponse struct {
Result struct {
AddressKeyID string `json:"address_key_id"`
} `json:"result"`
}
func statusLoginRequest(sdk *SDK, address, password string) (res loginResponse, err error) {
func statusLoginRequest(sdk *SDK, address, password string) (*loginResponse, error) {
// `{"jsonrpc":"2.0","method":"status_login","params":[{"address":"%s","password":"%s"}]}`
req := shhRequest{
JSONRPC: "2.0",
Method: "status_login",
}
var res loginResponse
req.Params = append(req.Params, &statusLoginParam{
params := &statusLoginParam{
Address: address,
Password: password,
})
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
return &res, sdk.call("status_login", params, &res)
}
type statusSignupParam struct {
@ -136,67 +78,41 @@ type statusSignupParam struct {
}
type signupResponse struct {
Result struct {
Address string `json:"address"`
Pubkey string `json:"pubkey"`
Mnemonic string `json:"mnemonic"`
} `json:"result"`
}
func statusSignupRequest(sdk *SDK, password string) (res signupResponse, err error) {
func statusSignupRequest(sdk *SDK, password string) (*signupResponse, error) {
// `{"jsonrpc":"2.0","method":"status_signup","params":[{"password":"%s"}]}`
req := shhRequest{
JSONRPC: "2.0",
Method: "status_signup",
}
var res signupResponse
req.Params = append(req.Params, &statusSignupParam{
params := &statusSignupParam{
Password: password,
})
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
return &res, sdk.call("status_signup", params, &res)
}
type getFilterMessagesResponse struct {
Result interface{} `json:"result"`
}
func shhGetFilterMessagesRequest(sdk *SDK, filters []string) (res *getFilterMessagesResponse, err error) {
func shhGetFilterMessagesRequest(sdk *SDK, filter string) (interface{}, error) {
// `{"jsonrpc":"2.0","id":2968,"method":"shh_getFilterMessages","params":["%s"]}`
req := shhRequest{
ID: 2968,
JSONRPC: "2.0",
Method: "shh_getFilterMessages",
}
for _, f := range filters {
req.Params = append(req.Params, f)
}
var res interface{}
body, err := json.Marshal(req)
if err != nil {
return
}
sdk.call(string(body), &res)
return
return res, sdk.call("shh_getFilterMessages", filter, &res)
}
type shhPostParam struct {
type Message struct {
Signature string `json:"sig"`
SymKeyID string `json:"symKeyID"`
Payload string `json:"payload"`
Topic string `json:"topic"`
TTL int `json:"ttl"`
TTL uint32 `json:"ttl"`
PowTarget float64 `json:"powTarget"`
PowTime int `json:"powTime"`
PowTime uint32 `json:"powTime"`
}
// error response {"jsonrpc":"2.0","id":633,"error":{"code":-32000,"message":"message rejected, PoW too low"}}
@ -209,30 +125,7 @@ type shhPostResponse struct {
Error *sshPostError `json:"error"`
}
func shhPostRequest(sdk *SDK, params []*shhPostParam) (res *shhPostResponse, err error) {
// `{"jsonrpc":"2.0","id":633,"method":"shh_post","params":[{"sig":"%s","symKeyID":"%s","payload":"%s","topic":"%s","ttl":10,"powTarget":%g,"powTime":1}]}`
req := shhRequest{
ID: 633,
JSONRPC: "2.0",
Method: "shh_post",
}
for _, p := range params {
req.Params = append(req.Params, p)
}
body, err := json.Marshal(req)
if err != nil {
return
}
err = sdk.call(string(body), &res)
if err != nil {
return res, err
}
if res.Error != nil {
return res, errors.New(res.Error.Message)
}
return
func shhPostRequest(sdk *SDK, msg *Message) (string, error) {
var res string
return res, sdk.call("shh_post", msg, &res)
}

View File

@ -2,30 +2,46 @@ package main
import (
"fmt"
"log"
"time"
"github.com/ethereum/go-ethereum/rpc"
"github.com/status-im/status-go-sdk"
)
func main() {
client := sdk.New("localhost:30303")
rpcClient, err := rpc.Dial("http://localhost:8545")
checkErr(err)
addr, _, _, err := client.Signup("password")
remoteClient := &remoteClient{rpcClient}
client := sdk.New(remoteClient)
a, err := client.SignupAndLogin("password")
checkErr(err)
ch, err := a.JoinPublicChannel("supu")
if err != nil {
return
checkErr(err)
}
if err := client.Login(addr, "password"); err != nil {
panic(err)
}
fmt.Printf("%+v\n", ch)
ch, err := client.JoinPublicChannel("supu")
if err != nil {
panic("Couldn't connect to status")
}
for range time.Tick(10 * time.Second) {
for range time.Tick(3 * time.Second) {
message := fmt.Sprintf("PING : %d", time.Now().Unix())
_ = ch.Publish(message)
}
}
type remoteClient struct {
c *rpc.Client
}
func (rc *remoteClient) Call(req *sdk.Request, res interface{}) error {
return rc.c.Call(res, req.Method, req.Params)
}
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}

View File

@ -7,35 +7,45 @@ import (
"strings"
"time"
"github.com/ethereum/go-ethereum/rpc"
"github.com/status-im/status-go-sdk"
)
type remoteClient struct {
c *rpc.Client
}
func (rc *remoteClient) Call(req *sdk.Request, res interface{}) error {
return rc.c.Call(res, req.Method, req.Params)
}
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
func main() {
client := sdk.New("localhost:30303")
rpcClient, err := rpc.Dial("http://localhost:8545")
checkErr(err)
addr, _, _, err := client.Signup("password")
if err != nil {
return
}
remoteClient := &remoteClient{rpcClient}
client := sdk.New(remoteClient)
if err := client.Login(addr, "password"); err != nil {
panic(err)
}
a, err := client.SignupAndLogin("password")
checkErr(err)
ch, err := client.JoinPublicChannel("supu")
if err != nil {
panic("Couldn't connect to status")
}
ch, err := a.JoinPublicChannel("supu")
checkErr(err)
_, _ = ch.Subscribe(func(m *sdk.Msg) {
log.Println("Message from ", m.From, " with body: ", m.Text)
log.Println("Message from ", m.From, " with body: ", m.Raw)
if strings.Contains(m.Text, "PING :") {
if strings.Contains(m.Raw, "PING :") {
time.Sleep(5 * time.Second)
message := fmt.Sprintf("PONG : %d", time.Now().Unix())
_ = ch.Publish(message)
}
})
runtime.Goexit()

7
msg.go
View File

@ -53,6 +53,7 @@ func supportedMessage(msgType string) bool {
// Msg is a structure used by Subscribers and Publish().
type Msg struct {
From string `json:"from"`
PubKey string `json:"sig"`
ChannelName string `json:"channel"`
Channel *Channel `json:"-"`
Raw string `json:"-"`
@ -77,7 +78,11 @@ func unrawrChatMessage(message string) ([]byte, error) {
func messageFromEnvelope(u interface{}) (msg *Msg, err error) {
payload := u.(map[string]interface{})["payload"]
return messageFromPayload(payload.(string))
msg, err = messageFromPayload(payload.(string))
if pubkey, ok := u.(map[string]interface{})["sig"]; ok {
msg.PubKey = pubkey.(string)
}
return
}
func messageFromPayload(payload string) (*Msg, error) {

29
sdk.go
View File

@ -1,13 +1,12 @@
package sdk
import (
"encoding/json"
"log"
)
// RPCClient is a client to manage all rpc calls
type RPCClient interface {
Call(request interface{}) (response interface{}, err error)
Call(req *Request, res interface{}) error
}
// SDK is a set of tools to interact with status node
@ -33,7 +32,7 @@ func (c *SDK) Login(addr, pwd string) (a *Account, err error) {
}
return &Account{
conn: c,
Address: res.Result.AddressKeyID,
Address: res.AddressKeyID,
}, err
}
@ -45,9 +44,9 @@ func (c *SDK) Signup(pwd string) (a *Account, err error) {
}
return &Account{
conn: c,
Address: res.Result.Address,
PubKey: res.Result.Pubkey,
Mnemonic: res.Result.Mnemonic,
Address: res.Address,
PubKey: res.Pubkey,
Mnemonic: res.Mnemonic,
}, err
}
@ -63,18 +62,22 @@ func (c *SDK) SignupAndLogin(password string) (a *Account, err error) {
return
}
type Request struct {
Method string `json:"method"`
Params interface{} `json:"params"`
}
// NewMessageFilterResponse NewMessageFilter json response
type NewMessageFilterResponse struct {
Result string `json:"result"`
}
func (c *SDK) call(cmd string, res interface{}) error {
log.Println("[ REQUEST ] : " + cmd)
body, err := c.RPCClient.Call(cmd)
if err != nil {
return err
func (c *SDK) call(method string, params interface{}, result interface{}) error {
log.Println("[ REQUEST ] : " + method)
req := &Request{
Method: method,
Params: params,
}
log.Println("[ RESPONSE ] : " + body.(string))
return json.Unmarshal([]byte(body.(string)), &res)
return c.RPCClient.Call(req, result)
}