add StateController to take Client out of AppState
Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
parent
ecf69febbc
commit
b620ad6ea6
|
@ -0,0 +1,42 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StateController struct {
|
||||||
|
State *AppState
|
||||||
|
Client *StatusGoClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// For fetching current state of peers from status-go
|
||||||
|
func (s *StateController) Fetch() {
|
||||||
|
peers, err := s.Client.getPeers()
|
||||||
|
if err != nil {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
ps := s.State.GetData()
|
||||||
|
s.State.UpdatePeers(peers)
|
||||||
|
if ps.Current == -1 {
|
||||||
|
s.State.SetCurrentPeer(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For removing a selected peer from connected to status-go
|
||||||
|
func (s *StateController) RemovePeer(peer *Peer) error {
|
||||||
|
success, err := s.Client.removePeer(peer.Enode)
|
||||||
|
if err != nil || success != true {
|
||||||
|
log.Panicln(err)
|
||||||
|
}
|
||||||
|
s.Fetch()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateController) GetInfo() error {
|
||||||
|
info, err := s.Client.nodeInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.State.UpdateInfo(*info)
|
||||||
|
return nil
|
||||||
|
}
|
6
loop.go
6
loop.go
|
@ -4,16 +4,16 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FetchLoop(state *AppState, interval int) {
|
func FetchLoop(s *StateController, interval int) {
|
||||||
// Get the first peers fetch going sooner
|
// Get the first peers fetch going sooner
|
||||||
state.Fetch()
|
s.Fetch()
|
||||||
// Then fetch every `interval` seconds
|
// Then fetch every `interval` seconds
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-threadDone:
|
case <-threadDone:
|
||||||
return
|
return
|
||||||
case <-time.After(time.Duration(interval) * time.Second):
|
case <-time.After(time.Duration(interval) * time.Second):
|
||||||
state.Fetch()
|
s.Fetch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
24
main.go
24
main.go
|
@ -39,19 +39,17 @@ func main() {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the RPC endpoint is available first
|
|
||||||
node, err := client.nodeInfo()
|
|
||||||
if err != nil {
|
|
||||||
log.Panicln(err)
|
|
||||||
}
|
|
||||||
log.Println("Successful connection to:", url)
|
|
||||||
log.Println("Enode:", node.Enode)
|
|
||||||
|
|
||||||
// Create a state wrapper.
|
// Create a state wrapper.
|
||||||
state := NewState(client)
|
state := NewState()
|
||||||
|
|
||||||
|
// Create a state controller
|
||||||
|
stateCtrl := &StateController{
|
||||||
|
State: state,
|
||||||
|
Client: client,
|
||||||
|
}
|
||||||
|
|
||||||
// Subscribe rendering method to state changes.
|
// Subscribe rendering method to state changes.
|
||||||
state.Store.Subscribe(GenRenderFunc(g, state))
|
state.Store.Subscribe(GenRenderFunc(g, stateCtrl))
|
||||||
|
|
||||||
mainView := &ViewController{
|
mainView := &ViewController{
|
||||||
Name: "main",
|
Name: "main",
|
||||||
|
@ -63,7 +61,7 @@ func main() {
|
||||||
Current: true,
|
Current: true,
|
||||||
SelFgColor: gocui.ColorBlack,
|
SelFgColor: gocui.ColorBlack,
|
||||||
SelBgColor: gocui.ColorGreen,
|
SelBgColor: gocui.ColorGreen,
|
||||||
State: state,
|
StateCtrl: stateCtrl,
|
||||||
// corner positions
|
// corner positions
|
||||||
TopLeft: func(mx, my int) (int, int) { return 0, 0 },
|
TopLeft: func(mx, my int) (int, int) { return 0, 0 },
|
||||||
BotRight: func(mx, my int) (int, int) { return mx - 1, my / 2 },
|
BotRight: func(mx, my int) (int, int) { return mx - 1, my / 2 },
|
||||||
|
@ -84,7 +82,7 @@ func main() {
|
||||||
Placeholder: "Loading details...",
|
Placeholder: "Loading details...",
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Wrap: true,
|
Wrap: true,
|
||||||
State: state,
|
StateCtrl: stateCtrl,
|
||||||
// corner positions
|
// corner positions
|
||||||
TopLeft: func(mx, my int) (int, int) { return 0, (my / 2) + 1 },
|
TopLeft: func(mx, my int) (int, int) { return 0, (my / 2) + 1 },
|
||||||
BotRight: func(mx, my int) (int, int) { return mx - 1, my - 1 },
|
BotRight: func(mx, my int) (int, int) { return mx - 1, my - 1 },
|
||||||
|
@ -98,7 +96,7 @@ func main() {
|
||||||
g.SetManagerFunc(vm.Layout)
|
g.SetManagerFunc(vm.Layout)
|
||||||
|
|
||||||
// Start RPC calling routine for fetching peers periodically.
|
// Start RPC calling routine for fetching peers periodically.
|
||||||
go FetchLoop(state, interval)
|
go FetchLoop(stateCtrl, interval)
|
||||||
|
|
||||||
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
|
||||||
log.Panicln(err)
|
log.Panicln(err)
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"github.com/jroimartin/gocui"
|
"github.com/jroimartin/gocui"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenRenderFunc(g *gocui.Gui, state *AppState) func() {
|
func GenRenderFunc(g *gocui.Gui, sc *StateController) func() {
|
||||||
return func() {
|
return func() {
|
||||||
ps := state.GetState()
|
ps := sc.State.GetData()
|
||||||
renderPeerList(g, ps.Peers)
|
renderPeerList(g, ps.Peers)
|
||||||
renderPeerInfo(g, state.GetCurrent())
|
renderPeerInfo(g, sc.State.GetCurrent())
|
||||||
updatePeerCursor(g, ps.Current)
|
updatePeerCursor(g, ps.Current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
61
state.go
61
state.go
|
@ -1,8 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/dannypsnl/redux/v2/rematch"
|
"github.com/dannypsnl/redux/v2/rematch"
|
||||||
"github.com/dannypsnl/redux/v2/store"
|
"github.com/dannypsnl/redux/v2/store"
|
||||||
)
|
)
|
||||||
|
@ -10,14 +8,14 @@ import (
|
||||||
// This might need renaming, since it also contains the Client.
|
// This might need renaming, since it also contains the Client.
|
||||||
// I need the client to make the RPC calls.
|
// I need the client to make the RPC calls.
|
||||||
type AppState struct {
|
type AppState struct {
|
||||||
Reducer *AppModel
|
Reducer *AppModel
|
||||||
Store *store.Store
|
Store *store.Store
|
||||||
Client *StatusGoClient
|
setNodeInfo *rematch.Action
|
||||||
updatePeers *rematch.Action
|
updatePeers *rematch.Action
|
||||||
setCurrent *rematch.Action
|
setCurrentPeer *rematch.Action
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(client *StatusGoClient) *AppState {
|
func NewState() *AppState {
|
||||||
// Generate the reducer from our model.
|
// Generate the reducer from our model.
|
||||||
Reducer := &AppModel{
|
Reducer := &AppModel{
|
||||||
State: AppData{
|
State: AppData{
|
||||||
|
@ -30,51 +28,34 @@ func NewState(client *StatusGoClient) *AppState {
|
||||||
Reducer: Reducer,
|
Reducer: Reducer,
|
||||||
// Define the store.
|
// Define the store.
|
||||||
Store: store.New(Reducer),
|
Store: store.New(Reducer),
|
||||||
// Client for RPC calls.
|
|
||||||
Client: client,
|
|
||||||
// Define available reducers for the store.
|
// Define available reducers for the store.
|
||||||
updatePeers: Reducer.Action(Reducer.Update),
|
setNodeInfo: Reducer.Action(Reducer.SetInfo),
|
||||||
setCurrent: Reducer.Action(Reducer.Current),
|
updatePeers: Reducer.Action(Reducer.Update),
|
||||||
|
setCurrentPeer: Reducer.Action(Reducer.Current),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers for shorter calls.
|
// Helpers for shorter calls.
|
||||||
func (s *AppState) Update(peers []Peer) {
|
func (s *AppState) UpdateInfo(info NodeInfo) {
|
||||||
|
s.Store.Dispatch(s.setNodeInfo.With(info))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *AppState) UpdatePeers(peers []Peer) {
|
||||||
s.Store.Dispatch(s.updatePeers.With(peers))
|
s.Store.Dispatch(s.updatePeers.With(peers))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AppState) GetCurrent() *Peer {
|
func (s *AppState) GetCurrent() *Peer {
|
||||||
state := s.GetState()
|
state := s.GetData()
|
||||||
if state.Current == -1 {
|
if state.Current == -1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &state.Peers[state.Current]
|
return &state.Peers[state.Current]
|
||||||
}
|
}
|
||||||
func (s *AppState) SetCurrent(index int) {
|
|
||||||
s.Store.Dispatch(s.setCurrent.With(index))
|
func (s *AppState) SetCurrentPeer(index int) {
|
||||||
|
s.Store.Dispatch(s.setCurrentPeer.With(index))
|
||||||
}
|
}
|
||||||
func (s *AppState) GetState() AppData {
|
|
||||||
|
func (s *AppState) GetData() AppData {
|
||||||
return s.Store.StateOf(s.Reducer).(AppData)
|
return s.Store.StateOf(s.Reducer).(AppData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For fetching current state of peers from status-go
|
|
||||||
func (s *AppState) Fetch() {
|
|
||||||
peers, err := s.Client.getPeers()
|
|
||||||
if err != nil {
|
|
||||||
log.Panicln(err)
|
|
||||||
}
|
|
||||||
ps := s.GetState()
|
|
||||||
s.Update(peers)
|
|
||||||
if ps.Current == -1 {
|
|
||||||
s.SetCurrent(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For removing a selected peer from connected to status-go
|
|
||||||
func (s *AppState) Remove(peer *Peer) error {
|
|
||||||
success, err := s.Client.removePeer(peer.Enode)
|
|
||||||
if err != nil || success != true {
|
|
||||||
log.Panicln(err)
|
|
||||||
}
|
|
||||||
s.Fetch()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
13
view.go
13
view.go
|
@ -32,7 +32,7 @@ type ViewController struct {
|
||||||
SelFgColor gocui.Attribute
|
SelFgColor gocui.Attribute
|
||||||
Keybindings []Binding
|
Keybindings []Binding
|
||||||
// Extra field for view state. Might need different name.
|
// Extra field for view state. Might need different name.
|
||||||
State *AppState
|
StateCtrl *StateController
|
||||||
}
|
}
|
||||||
|
|
||||||
// To combine all existing views into one
|
// To combine all existing views into one
|
||||||
|
@ -84,7 +84,6 @@ func (m *ViewManager) Layout(g *gocui.Gui) error {
|
||||||
|
|
||||||
func (v *ViewController) SetKeybindings(g *gocui.Gui) error {
|
func (v *ViewController) SetKeybindings(g *gocui.Gui) error {
|
||||||
for _, b := range v.Keybindings {
|
for _, b := range v.Keybindings {
|
||||||
// IDEA: I can pass a method instead of a function here
|
|
||||||
if err := g.SetKeybinding("", b.Key, b.Mod, b.Handler); err != nil {
|
if err := g.SetKeybinding("", b.Key, b.Mod, b.Handler); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -94,19 +93,21 @@ func (v *ViewController) SetKeybindings(g *gocui.Gui) error {
|
||||||
|
|
||||||
func (vc *ViewController) CursorUp(g *gocui.Gui, v *gocui.View) error {
|
func (vc *ViewController) CursorUp(g *gocui.Gui, v *gocui.View) error {
|
||||||
// TODO propper error handling?
|
// TODO propper error handling?
|
||||||
vc.State.SetCurrent(vc.State.GetState().Current - 1)
|
current := vc.StateCtrl.State.GetData().Current
|
||||||
|
vc.StateCtrl.State.SetCurrentPeer(current - 1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vc *ViewController) CursorDown(g *gocui.Gui, v *gocui.View) error {
|
func (vc *ViewController) CursorDown(g *gocui.Gui, v *gocui.View) error {
|
||||||
// TODO propper error handling?
|
// TODO propper error handling?
|
||||||
vc.State.SetCurrent(vc.State.GetState().Current + 1)
|
current := vc.StateCtrl.State.GetData().Current
|
||||||
|
vc.StateCtrl.State.SetCurrentPeer(current + 1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vc *ViewController) HandleDelete(g *gocui.Gui, v *gocui.View) error {
|
func (vc *ViewController) HandleDelete(g *gocui.Gui, v *gocui.View) error {
|
||||||
currentPeer := vc.State.GetCurrent()
|
currentPeer := vc.StateCtrl.State.GetCurrent()
|
||||||
err := vc.State.Remove(currentPeer)
|
err := vc.StateCtrl.RemovePeer(currentPeer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue