Skip to content

Commit

Permalink
Add package level RPC functions without requiring client or wallet
Browse files Browse the repository at this point in the history
Signed-off-by: Yilun <[email protected]>
  • Loading branch information
yilunzhang committed Apr 10, 2020
1 parent 5168238 commit a095f4a
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 271 deletions.
69 changes: 35 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,27 @@ fmt.Println("Receive message from", msg.Src + ":", string(msg.Payload))
msg.Reply([]byte("response"))
```

Get 100 subscribers of specified topic starting from 0 offset, including those
in tx pool (fetch meta):

```go
subscribers, err := client.GetSubscribers("topic", 0, 100, true, true)
fmt.Println(subscribers.Subscribers, subscribers.SubscribersInTxPool)
```

Get subscribers count for specified topic:

```go
count, err := client.GetSubscribersCount("topic")
```

Get subscription:

```go
subscription, err := client.GetSubscription("topic", "identifier.publickey")
fmt.Printf("%+v\n", subscription) // &{Meta:meta ExpiresAt:100000}
```

## Multiclient

Multiclient creates multiple client instances by adding identifier prefix
Expand Down Expand Up @@ -213,7 +234,7 @@ Create wallet SDK:

```go
account, err := NewAccount(nil)
w, err := NewWallet(account, &nkn.WalletConfig{Password: "password"})
wallet, err := NewWallet(account, &nkn.WalletConfig{Password: "password"})
```

By default the wallet will use RPC server provided by `nkn.org`. Any NKN full
Expand All @@ -224,14 +245,14 @@ conf := &WalletConfig{
Password: "password",
SeedRPCServerAddr: NewStringArray("https://ip:port", "https://ip:port", ...),
}
w, err := NewWallet(account, conf)
wallet, err := NewWallet(account, conf)
```

Export wallet to JSON string, where sensitive contents are encrypted by password
provided in config:

```go
walletJSON, err := w.ToJSON()
walletJSON, err := wallet.ToJSON()
```

Load wallet from JSON string, note that the password needs to be the same as the
Expand All @@ -244,19 +265,19 @@ walletFromJSON, err := nkn.WalletFromJSON(walletJSON, &nkn.WalletConfig{Password
Verify whether an address is a valid NKN wallet address:

```go
err := nkn.VerifyWalletAddress(w.Address())
err := nkn.VerifyWalletAddress(wallet.Address())
```

Verify password of the wallet:

```go
ok := w.VerifyPassword("password")
ok := wallet.VerifyPassword("password")
```

Query asset balance for this wallet:

```go
balance, err := w.Balance()
balance, err := wallet.Balance()
if err == nil {
log.Println("asset balance:", balance.String())
} else {
Expand All @@ -267,13 +288,13 @@ if err == nil {
Query asset balance for address:

```go
balance, err := w.BalanceByAddress("NKNxxxxx")
balance, err := wallet.BalanceByAddress("NKNxxxxx")
```

Transfer asset to some address:

```go
txnHash, err := w.Transfer(account.WalletAddress(), "100", "0")
txnHash, err := wallet.Transfer(account.WalletAddress(), "100", "0")
```

Open nano pay channel to specified address:
Expand All @@ -282,7 +303,7 @@ Open nano pay channel to specified address:
// you can pass channel duration (in unit of blocks) after address and txn fee
// after expired new channel (with new id) will be created under-the-hood
// this means that receiver need to claim old channel and reset amount calculation
np, err := w.NewNanoPay(address, "0", 4320)
np, err := wallet.NewNanoPay(address, "0", 4320)
```

Increment channel balance by 100 NKN:
Expand All @@ -295,51 +316,31 @@ Then you can pass the transaction to receiver, who can send transaction to
on-chain later:

```go
txnHash, err := w.SendRawTransaction(txn)
txnHash, err := wallet.SendRawTransaction(txn)
```

Register name for this wallet:

```go
txnHash, err = w.RegisterName("somename")
txnHash, err = wallet.RegisterName("somename")
```

Delete name for this wallet:

```go
txnHash, err = w.DeleteName("somename")
txnHash, err = wallet.DeleteName("somename")
```

Subscribe to specified topic for this wallet for next 100 blocks:

```go
txnHash, err = w.Subscribe("identifier", "topic", 100, "meta", "0")
txnHash, err = wallet.Subscribe("identifier", "topic", 100, "meta", "0")
```

Unsubscribe from specified topic:

```go
txnHash, err = w.Unsubscribe("identifier", "topic", "0")
```

Get subscription:

```go
subscription, err := w.GetSubscription("topic", "identifier.publickey")
fmt.Printf("%+v\n", subscription) // &{Meta:meta ExpiresAt:100000}
```

Get 100 subscribers of specified topic starting from 0 offset, including those in tx pool (fetch meta):

```go
subscribers, err := w.GetSubscribers("topic", 0, 100, true, true)
fmt.Println(subscribers.Subscribers, subscribers.SubscribersInTxPool)
```

Get subscribers count for specified topic:

```go
count, err := w.GetSubscribersCount("topic")
txnHash, err = wallet.Unsubscribe("identifier", "topic", "0")
```

## iOS/Android
Expand Down
40 changes: 33 additions & 7 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,7 @@ func (c *Client) connect(maxRetries int) error {
}
}

var node *Node
_, err := call(c.config.GetRandomSeedRPCServerAddr(), "getwsaddr", map[string]interface{}{"address": c.Address()}, &node)
node, err := GetWsAddr(c.Address(), c.config)
if err != nil {
log.Println(err)
continue
Expand Down Expand Up @@ -747,8 +746,7 @@ func (c *Client) processDest(dest string) (string, error) {
}
addr := strings.Split(dest, ".")
if len(addr[len(addr)-1]) < 2*ed25519.PublicKeySize {
var reg *registrantInfo
_, err := call(c.config.GetRandomSeedRPCServerAddr(), "getregistrant", map[string]interface{}{"name": addr[len(addr)-1]}, &reg)
reg, err := GetRegistrant(addr[len(addr)-1], c.config)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -998,23 +996,26 @@ func publish(c clientInterface, topic string, data interface{}, config *MessageC

offset := int(config.Offset)
limit := int(config.Limit)
subscribers, subscribersInTxPool, err := getSubscribers(c.getConfig().GetRandomSeedRPCServerAddr(), topic, offset, limit, false, config.TxPool)
res, err := GetSubscribers(topic, offset, limit, false, config.TxPool, c.getConfig())
if err != nil {
return err
}

subscribers := res.Subscribers.Map
subscribersInTxPool := res.SubscribersInTxPool.Map

dests := make([]string, 0, len(subscribers)+len(subscribersInTxPool))
for subscriber := range subscribers {
dests = append(dests, subscriber)
}

for len(subscribers) >= limit {
offset += limit
subscribers, _, err = getSubscribers(c.getConfig().GetRandomSeedRPCServerAddr(), topic, offset, limit, false, false)
res, err = GetSubscribers(topic, offset, limit, false, false, c.getConfig())
if err != nil {
return err
}
for subscriber := range subscribers {
for subscriber := range res.Subscribers.Map {
dests = append(dests, subscriber)
}
}
Expand Down Expand Up @@ -1059,3 +1060,28 @@ func (c *Client) SetWriteDeadline(deadline time.Time) error {
func (c *Client) getConfig() *ClientConfig {
return c.config
}

// GetSubscribers gets the subscribers of a topic with a offset and max number
// of results (limit). If meta is true, results contain each subscriber's
// metadata. If txPool is true, results contain subscribers in txPool. Enabling
// this will get subscribers sooner after they send subscribe transactions, but
// might affect the correctness of subscribers because transactions in txpool is
// not guaranteed to be packed into a block.
//
// Offset and limit are changed to signed int for gomobile compatibility
func (c *Client) GetSubscribers(topic string, offset, limit int, meta, txPool bool) (*Subscribers, error) {
return GetSubscribers(topic, offset, limit, meta, txPool, c.config)
}

// GetSubscription gets the subscription details of a subscriber in a topic.
func (c *Client) GetSubscription(topic string, subscriber string) (*Subscription, error) {
return GetSubscription(topic, subscriber, c.config)
}

// GetSubscribersCount returns the number of subscribers of a topic (not
// including txPool).
//
// Count is changed to signed int for gomobile compatibility
func (c *Client) GetSubscribersCount(topic string) (int, error) {
return GetSubscribersCount(topic, c.config)
}
27 changes: 27 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ func GetDefaultWalletConfig() *WalletConfig {
return &walletConf
}

// RPCConfig is the rpc call configuration.
type RPCConfig struct {
SeedRPCServerAddr *StringArray
}

// DefaultRPCConfig is the default rpc configuration.
var DefaultRPCConfig = RPCConfig{
SeedRPCServerAddr: nil,
}

// GetDefaultRPCConfig returns the default rpc config with nil pointer fields
// set to default.
func GetDefaultRPCConfig() *RPCConfig {
rpcConf := DefaultRPCConfig
rpcConf.SeedRPCServerAddr = NewStringArray(DefaultSeedRPCServerAddr...)
return &rpcConf
}

// GetRandomSeedRPCServerAddr returns a random seed rpc server address from the
// client config.
func (config *ClientConfig) GetRandomSeedRPCServerAddr() string {
Expand All @@ -198,6 +216,15 @@ func (config *WalletConfig) GetRandomSeedRPCServerAddr() string {
return config.SeedRPCServerAddr.Elems[rand.Intn(len(config.SeedRPCServerAddr.Elems))]
}

// GetRandomSeedRPCServerAddr returns a random seed rpc server address from the
// rpc config.
func (config *RPCConfig) GetRandomSeedRPCServerAddr() string {
if len(config.SeedRPCServerAddr.Elems) == 0 {
return ""
}
return config.SeedRPCServerAddr.Elems[rand.Intn(len(config.SeedRPCServerAddr.Elems))]
}

// MergeClientConfig merges a given client config with the default client config
// recursively. Any non zero value fields will override the default config.
func MergeClientConfig(conf *ClientConfig) (*ClientConfig, error) {
Expand Down
19 changes: 19 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@ import (
ncp "github.com/nknorg/ncp-go"
)

// ErrorWithCode is an error interface that implements error and Code()
type ErrorWithCode interface {
error
Code() int32
}

type errorWithCode struct {
err error
code int32
}

func (e errorWithCode) Error() string {
return e.err.Error()
}

func (e errorWithCode) Code() int32 {
return e.code
}

var (
ErrClosed = ncp.NewGenericError("use of closed network connection", true, true) // The error message is meant to be identical to error returned by net package.
ErrKeyNotInMap = ncp.NewGenericError("key not in map", false, false) // for gomobile
Expand Down
Loading

0 comments on commit a095f4a

Please sign in to comment.