diff --git a/tm-monitor/monitor/monitor.go b/tm-monitor/monitor/monitor.go index e70c001fa..1e5c56e98 100644 --- a/tm-monitor/monitor/monitor.go +++ b/tm-monitor/monitor/monitor.go @@ -18,7 +18,7 @@ const nodeLivenessTimeout = 5 * time.Second // // Common statistics is stored in Network struct. type Monitor struct { - Nodes map[string]*Node + Nodes []*Node Network *Network monitorQuit chan struct{} // monitor exitting @@ -37,7 +37,7 @@ type Monitor struct { // NewMonitor(monitor.SetNumValidatorsUpdateInterval(1 * time.Second)) func NewMonitor(options ...func(*Monitor)) *Monitor { m := &Monitor{ - Nodes: make(map[string]*Node), + Nodes: make([]*Node, 0), Network: NewNetwork(), monitorQuit: make(chan struct{}), nodeQuit: make(map[string]chan struct{}), @@ -75,7 +75,7 @@ func (m *Monitor) SetLogger(l log.Logger) { // Monitor begins to monitor the node `n`. The node will be started and added // to the monitor. func (m *Monitor) Monitor(n *Node) error { - m.Nodes[n.Name] = n + m.Nodes = append(m.Nodes, n) blockCh := make(chan tmtypes.Header, 10) n.SendBlocksTo(blockCh) @@ -104,7 +104,20 @@ func (m *Monitor) Unmonitor(n *Node) { n.Stop() close(m.nodeQuit[n.Name]) delete(m.nodeQuit, n.Name) - delete(m.Nodes, n.Name) + i, _ := m.NodeByName(n.Name) + m.Nodes[i] = m.Nodes[len(m.Nodes)-1] + m.Nodes = m.Nodes[:len(m.Nodes)-1] +} + +// NodeByName returns the node and its index if such node exists within the +// monitor. Otherwise, -1 and nil are returned. +func (m *Monitor) NodeByName(name string) (index int, node *Node) { + for i, n := range m.Nodes { + if name == n.Name { + return i, n + } + } + return -1, nil } // Start starts the monitor's routines: recalculating network uptime and diff --git a/tm-monitor/rpc.go b/tm-monitor/rpc.go index 127179e20..5162ecb45 100644 --- a/tm-monitor/rpc.go +++ b/tm-monitor/rpc.go @@ -38,14 +38,7 @@ func routes(m *monitor.Monitor) map[string]*rpc.RPCFunc { // RPCStatus returns common statistics for the network and statistics per node. func RPCStatus(m *monitor.Monitor) interface{} { return func() (networkAndNodes, error) { - values := make([]*monitor.Node, len(m.Nodes)) - i := 0 - for _, v := range m.Nodes { - values[i] = v - i++ - } - - return networkAndNodes{m.Network, values}, nil + return networkAndNodes{m.Network, m.Nodes}, nil } } @@ -59,19 +52,23 @@ func RPCNetworkStatus(m *monitor.Monitor) interface{} { // RPCNodeStatus returns statistics for the given node. func RPCNodeStatus(m *monitor.Monitor) interface{} { return func(name string) (*monitor.Node, error) { - if n, ok := m.Nodes[name]; ok { + if i, n := m.NodeByName(name); i != -1 { return n, nil } return nil, errors.New("Cannot find node with that name") } } -// RPCMonitor allows to dynamically add a endpoint to under the monitor. +// RPCMonitor allows to dynamically add a endpoint to under the monitor. Safe +// to call multiple times. func RPCMonitor(m *monitor.Monitor) interface{} { return func(endpoint string) (*monitor.Node, error) { - n := monitor.NewNode(endpoint) - if err := m.Monitor(n); err != nil { - return nil, err + i, n := m.NodeByName(endpoint) + if i == -1 { + n = monitor.NewNode(endpoint) + if err := m.Monitor(n); err != nil { + return nil, err + } } return n, nil } @@ -80,7 +77,7 @@ func RPCMonitor(m *monitor.Monitor) interface{} { // RPCUnmonitor removes the given endpoint from under the monitor. func RPCUnmonitor(m *monitor.Monitor) interface{} { return func(endpoint string) (bool, error) { - if n, ok := m.Nodes[endpoint]; ok { + if i, n := m.NodeByName(endpoint); i != -1 { m.Unmonitor(n) return true, nil }