Clean api package (#1055)
This commit is contained in:
parent
3ca120c2aa
commit
afb3ce159e
|
@ -5,30 +5,30 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppState represents if the app is in foreground, background or some other state
|
// appState represents if the app is in foreground, background or some other state
|
||||||
type AppState string
|
type appState string
|
||||||
|
|
||||||
func (a AppState) String() string {
|
func (a appState) String() string {
|
||||||
return string(a)
|
return string(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific app states
|
// Specific app states
|
||||||
// see https://facebook.github.io/react-native/docs/appstate.html
|
// see https://facebook.github.io/react-native/docs/appstate.html
|
||||||
const (
|
const (
|
||||||
AppStateForeground = AppState("active") // these constant values are kept in sync with React Native
|
appStateForeground = appState("active") // these constant values are kept in sync with React Native
|
||||||
AppStateBackground = AppState("background")
|
appStateBackground = appState("background")
|
||||||
AppStateInactive = AppState("inactive")
|
appStateInactive = appState("inactive")
|
||||||
|
|
||||||
AppStateInvalid = AppState("")
|
appStateInvalid = appState("")
|
||||||
)
|
)
|
||||||
|
|
||||||
// validAppStates returns an immutable set of valid states.
|
// validAppStates returns an immutable set of valid states.
|
||||||
func validAppStates() []AppState {
|
func validAppStates() []appState {
|
||||||
return []AppState{AppStateInactive, AppStateBackground, AppStateForeground}
|
return []appState{appStateInactive, appStateBackground, appStateForeground}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAppState creates AppState from a string
|
// parseAppState creates AppState from a string
|
||||||
func ParseAppState(stateString string) (AppState, error) {
|
func parseAppState(stateString string) (appState, error) {
|
||||||
// a bit of cleaning up
|
// a bit of cleaning up
|
||||||
stateString = strings.ToLower(strings.TrimSpace(stateString))
|
stateString = strings.ToLower(strings.TrimSpace(stateString))
|
||||||
|
|
||||||
|
@ -38,5 +38,5 @@ func ParseAppState(stateString string) (AppState, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AppStateInvalid, fmt.Errorf("could not parse app state: %s", stateString)
|
return appStateInvalid, fmt.Errorf("could not parse app state: %s", stateString)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,22 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseAppType(t *testing.T) {
|
func TestParseAppType(t *testing.T) {
|
||||||
check := func(input string, expectedState AppState, expectError bool) {
|
check := func(input string, expectedState appState, expectError bool) {
|
||||||
actualState, err := ParseAppState(input)
|
actualState, err := parseAppState(input)
|
||||||
assert.Equalf(t, expectedState, actualState, "unexpected result from ParseAppState")
|
assert.Equalf(t, expectedState, actualState, "unexpected result from parseAppState")
|
||||||
if expectError {
|
if expectError {
|
||||||
assert.NotNil(t, err, "error should not be nil")
|
assert.NotNil(t, err, "error should not be nil")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check("active", AppStateForeground, false)
|
check("active", appStateForeground, false)
|
||||||
check("background", AppStateBackground, false)
|
check("background", appStateBackground, false)
|
||||||
check("inactive", AppStateInactive, false)
|
check("inactive", appStateInactive, false)
|
||||||
check(" acTIVE ", AppStateForeground, false)
|
check(" acTIVE ", appStateForeground, false)
|
||||||
check(" backGROUND ", AppStateBackground, false)
|
check(" backGROUND ", appStateBackground, false)
|
||||||
check(" INACTIVE ", AppStateInactive, false)
|
check(" INACTIVE ", appStateInactive, false)
|
||||||
check("", AppStateInvalid, true)
|
check("", appStateInvalid, true)
|
||||||
check("back ground", AppStateInvalid, true)
|
check("back ground", appStateInvalid, true)
|
||||||
check(" back ground ", AppStateInvalid, true)
|
check(" back ground ", appStateInvalid, true)
|
||||||
check(" ", AppStateInvalid, true)
|
check(" ", appStateInvalid, true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ type StatusBackend struct {
|
||||||
transactor *transactions.Transactor
|
transactor *transactions.Transactor
|
||||||
jailManager jail.Manager
|
jailManager jail.Manager
|
||||||
newNotification fcm.NotificationConstructor
|
newNotification fcm.NotificationConstructor
|
||||||
connectionState ConnectionState
|
connectionState connectionState
|
||||||
|
appState appState
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +91,6 @@ func (b *StatusBackend) JailManager() jail.Manager {
|
||||||
return b.jailManager
|
return b.jailManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersonalAPI returns reference to personal APIs
|
|
||||||
func (b *StatusBackend) PersonalAPI() *personal.PublicAPI {
|
|
||||||
return b.personalAPI
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transactor returns reference to a status transactor
|
// Transactor returns reference to a status transactor
|
||||||
func (b *StatusBackend) Transactor() *transactions.Transactor {
|
func (b *StatusBackend) Transactor() *transactions.Transactor {
|
||||||
return b.transactor
|
return b.transactor
|
||||||
|
@ -155,7 +151,7 @@ func (b *StatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
}
|
}
|
||||||
b.log.Info("Handlers registered")
|
b.log.Info("Handlers registered")
|
||||||
|
|
||||||
if err = b.ReSelectAccount(); err != nil {
|
if err = b.reSelectAccount(); err != nil {
|
||||||
b.log.Error("Reselect account failed", "err", err)
|
b.log.Error("Reselect account failed", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -316,24 +312,22 @@ func (b *StatusBackend) registerHandlers() error {
|
||||||
return hash.Hex(), err
|
return hash.Hex(), err
|
||||||
})
|
})
|
||||||
|
|
||||||
rpcClient.RegisterHandler(params.PersonalSignMethodName, b.PersonalAPI().Sign)
|
rpcClient.RegisterHandler(params.PersonalSignMethodName, b.personalAPI.Sign)
|
||||||
rpcClient.RegisterHandler(params.PersonalRecoverMethodName, b.PersonalAPI().Recover)
|
rpcClient.RegisterHandler(params.PersonalRecoverMethodName, b.personalAPI.Recover)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// ConnectionChange handles network state changes logic.
|
// ConnectionChange handles network state changes logic.
|
||||||
func (b *StatusBackend) ConnectionChange(typ string, expensive bool) {
|
func (b *StatusBackend) ConnectionChange(typ string, expensive bool) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
state := ConnectionState{
|
state := connectionState{
|
||||||
Type: NewConnectionType(typ),
|
Type: newConnectionType(typ),
|
||||||
Expensive: expensive,
|
Expensive: expensive,
|
||||||
}
|
}
|
||||||
if typ == "none" {
|
if typ == none {
|
||||||
state.Offline = true
|
state.Offline = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,13 +342,14 @@ func (b *StatusBackend) ConnectionChange(typ string, expensive bool) {
|
||||||
// AppStateChange handles app state changes (background/foreground).
|
// AppStateChange handles app state changes (background/foreground).
|
||||||
// state values: see https://facebook.github.io/react-native/docs/appstate.html
|
// state values: see https://facebook.github.io/react-native/docs/appstate.html
|
||||||
func (b *StatusBackend) AppStateChange(state string) {
|
func (b *StatusBackend) AppStateChange(state string) {
|
||||||
appState, err := ParseAppState(state)
|
s, err := parseAppState(state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("AppStateChange failed, ignoring", "error", err)
|
log.Error("AppStateChange failed, ignoring", "error", err)
|
||||||
return // and do nothing
|
return // and do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
b.log.Info("App State changed", "new-state", appState)
|
b.log.Info("App State changed", "new-state", s)
|
||||||
|
b.appState = s
|
||||||
|
|
||||||
// TODO: put node in low-power mode if the app is in background (or inactive)
|
// TODO: put node in low-power mode if the app is in background (or inactive)
|
||||||
// and normal mode if the app is in foreground.
|
// and normal mode if the app is in foreground.
|
||||||
|
@ -385,8 +380,8 @@ func (b *StatusBackend) Logout() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSelectAccount selects previously selected account, often, after node restart.
|
// reSelectAccount selects previously selected account, often, after node restart.
|
||||||
func (b *StatusBackend) ReSelectAccount() error {
|
func (b *StatusBackend) reSelectAccount() error {
|
||||||
selectedAccount, err := b.AccountManager().SelectedAccount()
|
selectedAccount, err := b.AccountManager().SelectedAccount()
|
||||||
if selectedAccount == nil || err == account.ErrNoAccountSelected {
|
if selectedAccount == nil || err == account.ErrNoAccountSelected {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -103,7 +103,7 @@ func TestBackendGettersConcurrently(t *testing.T) {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
assert.NotNil(t, backend.PersonalAPI())
|
assert.NotNil(t, backend.personalAPI)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ func TestBackendAccountsConcurrently(t *testing.T) {
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
assert.NoError(t, backend.ReSelectAccount())
|
assert.NoError(t, backend.reSelectAccount())
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ func TestBackendAccountsConcurrently(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackendConnectionChangesConcurrently(t *testing.T) {
|
func TestBackendConnectionChangesConcurrently(t *testing.T) {
|
||||||
connections := [...]string{"wifi", "cellular"}
|
connections := [...]string{wifi, cellular, unknown}
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
count := 3
|
count := 3
|
||||||
|
|
||||||
|
@ -207,6 +207,18 @@ func TestBackendConnectionChangesConcurrently(t *testing.T) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBackendConnectionChangesToOffline(t *testing.T) {
|
||||||
|
b := NewStatusBackend()
|
||||||
|
b.ConnectionChange(none, false)
|
||||||
|
assert.True(t, b.connectionState.Offline)
|
||||||
|
|
||||||
|
b.ConnectionChange(wifi, false)
|
||||||
|
assert.False(t, b.connectionState.Offline)
|
||||||
|
|
||||||
|
b.ConnectionChange("unknown-state", false)
|
||||||
|
assert.False(t, b.connectionState.Offline)
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackendCallRPCConcurrently(t *testing.T) {
|
func TestBackendCallRPCConcurrently(t *testing.T) {
|
||||||
backend := NewStatusBackend()
|
backend := NewStatusBackend()
|
||||||
config := params.NodeConfig{}
|
config := params.NodeConfig{}
|
||||||
|
@ -245,6 +257,38 @@ func TestBackendCallRPCConcurrently(t *testing.T) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAppStateChange(t *testing.T) {
|
||||||
|
backend := NewStatusBackend()
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
name string
|
||||||
|
fromState appState
|
||||||
|
toState appState
|
||||||
|
expectedState appState
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
fromState: appStateInactive,
|
||||||
|
toState: appStateBackground,
|
||||||
|
expectedState: appStateBackground,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid state",
|
||||||
|
fromState: appStateInactive,
|
||||||
|
toState: "unexisting",
|
||||||
|
expectedState: appStateInactive,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
backend.appState = tc.fromState
|
||||||
|
backend.AppStateChange(tc.toState.String())
|
||||||
|
assert.Equal(t, tc.expectedState.String(), backend.appState.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrepareTxArgs(t *testing.T) {
|
func TestPrepareTxArgs(t *testing.T) {
|
||||||
var flagtests = []struct {
|
var flagtests = []struct {
|
||||||
description string
|
description string
|
||||||
|
|
|
@ -4,60 +4,61 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectionState represents device connection state and type,
|
// connectionState represents device connection state and type,
|
||||||
// as reported by mobile framework.
|
// as reported by mobile framework.
|
||||||
//
|
//
|
||||||
// Zero value represents default assumption about network (online and unknown type).
|
// Zero value represents default assumption about network (online and unknown type).
|
||||||
type ConnectionState struct {
|
type connectionState struct {
|
||||||
Offline bool `json:"offline"`
|
Offline bool `json:"offline"`
|
||||||
Type ConnectionType `json:"type"`
|
Type connectionType `json:"type"`
|
||||||
Expensive bool `json:"expensive"`
|
Expensive bool `json:"expensive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionType represents description of available
|
// connectionType represents description of available
|
||||||
// connection types as reported by React Native (see
|
// connection types as reported by React Native (see
|
||||||
// https://facebook.github.io/react-native/docs/netinfo.html)
|
// https://facebook.github.io/react-native/docs/netinfo.html)
|
||||||
// We're interested mainly in 'wifi' and 'cellular', but
|
// We're interested mainly in 'wifi' and 'cellular', but
|
||||||
// other types are also may be used.
|
// other types are also may be used.
|
||||||
type ConnectionType byte
|
type connectionType byte
|
||||||
|
|
||||||
const (
|
const (
|
||||||
offline = "offline"
|
offline = "offline"
|
||||||
wifi = "wifi"
|
wifi = "wifi"
|
||||||
cellular = "cellular"
|
cellular = "cellular"
|
||||||
unknown = "unknown"
|
unknown = "unknown"
|
||||||
|
none = "none"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewConnectionType creates new ConnectionType from string.
|
// newConnectionType creates new connectionType from string.
|
||||||
func NewConnectionType(s string) ConnectionType {
|
func newConnectionType(s string) connectionType {
|
||||||
switch s {
|
switch s {
|
||||||
case cellular:
|
case cellular:
|
||||||
return ConnectionCellular
|
return connectionCellular
|
||||||
case wifi:
|
case wifi:
|
||||||
return ConnectionWifi
|
return connectionWifi
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConnectionUnknown
|
return connectionUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionType constants
|
// ConnectionType constants
|
||||||
const (
|
const (
|
||||||
ConnectionUnknown ConnectionType = iota
|
connectionUnknown connectionType = iota
|
||||||
ConnectionCellular // cellular, LTE, 4G, 3G, EDGE, etc.
|
connectionCellular // cellular, LTE, 4G, 3G, EDGE, etc.
|
||||||
ConnectionWifi // WIFI or iOS simulator
|
connectionWifi // WIFI or iOS simulator
|
||||||
)
|
)
|
||||||
|
|
||||||
// String formats ConnectionState for logs. Implements Stringer.
|
// string formats ConnectionState for logs. Implements Stringer.
|
||||||
func (c ConnectionState) String() string {
|
func (c connectionState) String() string {
|
||||||
if c.Offline {
|
if c.Offline {
|
||||||
return offline
|
return offline
|
||||||
}
|
}
|
||||||
|
|
||||||
var typ string
|
var typ string
|
||||||
switch c.Type {
|
switch c.Type {
|
||||||
case ConnectionWifi:
|
case connectionWifi:
|
||||||
typ = wifi
|
typ = wifi
|
||||||
case ConnectionCellular:
|
case connectionCellular:
|
||||||
typ = cellular
|
typ = cellular
|
||||||
default:
|
default:
|
||||||
typ = unknown
|
typ = unknown
|
||||||
|
|
|
@ -3,16 +3,16 @@ package api
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestConnectionType(t *testing.T) {
|
func TestConnectionType(t *testing.T) {
|
||||||
c := NewConnectionType("wifi")
|
c := newConnectionType("wifi")
|
||||||
if c != ConnectionWifi {
|
if c != connectionWifi {
|
||||||
t.Fatalf("Wrong connection type: %v", c)
|
t.Fatalf("Wrong connection type: %v", c)
|
||||||
}
|
}
|
||||||
c = NewConnectionType("cellular")
|
c = newConnectionType("cellular")
|
||||||
if c != ConnectionCellular {
|
if c != connectionCellular {
|
||||||
t.Fatalf("Wrong connection type: %v", c)
|
t.Fatalf("Wrong connection type: %v", c)
|
||||||
}
|
}
|
||||||
c = NewConnectionType("bluetooth")
|
c = newConnectionType("bluetooth")
|
||||||
if c != ConnectionUnknown {
|
if c != connectionUnknown {
|
||||||
t.Fatalf("Wrong connection type: %v", c)
|
t.Fatalf("Wrong connection type: %v", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,34 +20,39 @@ func TestConnectionType(t *testing.T) {
|
||||||
func TestConnectionState(t *testing.T) {
|
func TestConnectionState(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
state ConnectionState
|
state connectionState
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"zero value",
|
"zero value",
|
||||||
ConnectionState{},
|
connectionState{},
|
||||||
"unknown",
|
"unknown",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offline",
|
"offline",
|
||||||
ConnectionState{Offline: true},
|
connectionState{Offline: true},
|
||||||
"offline",
|
"offline",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"wifi",
|
"wifi",
|
||||||
ConnectionState{Type: ConnectionWifi},
|
connectionState{Type: connectionWifi},
|
||||||
"wifi",
|
"wifi",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"wifi tethered",
|
"wifi tethered",
|
||||||
ConnectionState{Type: ConnectionWifi, Expensive: true},
|
connectionState{Type: connectionWifi, Expensive: true},
|
||||||
"wifi (expensive)",
|
"wifi (expensive)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unknown",
|
"unknown",
|
||||||
ConnectionState{Type: ConnectionUnknown},
|
connectionState{Type: connectionUnknown},
|
||||||
"unknown",
|
"unknown",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cellular",
|
||||||
|
connectionState{Type: connectionCellular},
|
||||||
|
"cellular",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
|
// RunAsync runs the specified function asynchronously.
|
||||||
func RunAsync(f func() error) <-chan error {
|
func RunAsync(f func() error) <-chan error {
|
||||||
resp := make(chan error, 1)
|
resp := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
Loading…
Reference in New Issue