diff --git a/control.go b/control.go new file mode 100644 index 0000000..8158291 --- /dev/null +++ b/control.go @@ -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 +} diff --git a/loop.go b/loop.go index 6154f1e..fed0bda 100644 --- a/loop.go +++ b/loop.go @@ -4,16 +4,16 @@ import ( "time" ) -func FetchLoop(state *AppState, interval int) { +func FetchLoop(s *StateController, interval int) { // Get the first peers fetch going sooner - state.Fetch() + s.Fetch() // Then fetch every `interval` seconds for { select { case <-threadDone: return case <-time.After(time.Duration(interval) * time.Second): - state.Fetch() + s.Fetch() } } } diff --git a/main.go b/main.go index e27161c..36ab0db 100644 --- a/main.go +++ b/main.go @@ -39,19 +39,17 @@ func main() { 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. - state := NewState(client) + state := NewState() + + // Create a state controller + stateCtrl := &StateController{ + State: state, + Client: client, + } // Subscribe rendering method to state changes. - state.Store.Subscribe(GenRenderFunc(g, state)) + state.Store.Subscribe(GenRenderFunc(g, stateCtrl)) mainView := &ViewController{ Name: "main", @@ -63,7 +61,7 @@ func main() { Current: true, SelFgColor: gocui.ColorBlack, SelBgColor: gocui.ColorGreen, - State: state, + StateCtrl: stateCtrl, // corner positions TopLeft: func(mx, my int) (int, int) { return 0, 0 }, BotRight: func(mx, my int) (int, int) { return mx - 1, my / 2 }, @@ -84,7 +82,7 @@ func main() { Placeholder: "Loading details...", Enabled: true, Wrap: true, - State: state, + StateCtrl: stateCtrl, // corner positions TopLeft: func(mx, my int) (int, int) { return 0, (my / 2) + 1 }, BotRight: func(mx, my int) (int, int) { return mx - 1, my - 1 }, @@ -98,7 +96,7 @@ func main() { g.SetManagerFunc(vm.Layout) // 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 { log.Panicln(err) diff --git a/render.go b/render.go index f519782..1901c0c 100644 --- a/render.go +++ b/render.go @@ -8,11 +8,11 @@ import ( "github.com/jroimartin/gocui" ) -func GenRenderFunc(g *gocui.Gui, state *AppState) func() { +func GenRenderFunc(g *gocui.Gui, sc *StateController) func() { return func() { - ps := state.GetState() + ps := sc.State.GetData() renderPeerList(g, ps.Peers) - renderPeerInfo(g, state.GetCurrent()) + renderPeerInfo(g, sc.State.GetCurrent()) updatePeerCursor(g, ps.Current) } } diff --git a/state.go b/state.go index 362a989..9842fb2 100644 --- a/state.go +++ b/state.go @@ -1,8 +1,6 @@ package main import ( - "log" - "github.com/dannypsnl/redux/v2/rematch" "github.com/dannypsnl/redux/v2/store" ) @@ -10,14 +8,14 @@ import ( // This might need renaming, since it also contains the Client. // I need the client to make the RPC calls. type AppState struct { - Reducer *AppModel - Store *store.Store - Client *StatusGoClient - updatePeers *rematch.Action - setCurrent *rematch.Action + Reducer *AppModel + Store *store.Store + setNodeInfo *rematch.Action + updatePeers *rematch.Action + setCurrentPeer *rematch.Action } -func NewState(client *StatusGoClient) *AppState { +func NewState() *AppState { // Generate the reducer from our model. Reducer := &AppModel{ State: AppData{ @@ -30,51 +28,34 @@ func NewState(client *StatusGoClient) *AppState { Reducer: Reducer, // Define the store. Store: store.New(Reducer), - // Client for RPC calls. - Client: client, // Define available reducers for the store. - updatePeers: Reducer.Action(Reducer.Update), - setCurrent: Reducer.Action(Reducer.Current), + setNodeInfo: Reducer.Action(Reducer.SetInfo), + updatePeers: Reducer.Action(Reducer.Update), + setCurrentPeer: Reducer.Action(Reducer.Current), } } // 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)) } + func (s *AppState) GetCurrent() *Peer { - state := s.GetState() + state := s.GetData() if state.Current == -1 { return nil } 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) } - -// 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 -} diff --git a/view.go b/view.go index 5a53027..7859f5f 100644 --- a/view.go +++ b/view.go @@ -32,7 +32,7 @@ type ViewController struct { SelFgColor gocui.Attribute Keybindings []Binding // Extra field for view state. Might need different name. - State *AppState + StateCtrl *StateController } // 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 { 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 { 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 { // 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 } func (vc *ViewController) CursorDown(g *gocui.Gui, v *gocui.View) error { // 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 } func (vc *ViewController) HandleDelete(g *gocui.Gui, v *gocui.View) error { - currentPeer := vc.State.GetCurrent() - err := vc.State.Remove(currentPeer) + currentPeer := vc.StateCtrl.State.GetCurrent() + err := vc.StateCtrl.RemovePeer(currentPeer) if err != nil { return err }