You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.5 KiB
Go
146 lines
3.5 KiB
Go
3 years ago
|
package tui
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"fmt"
|
||
|
"time"
|
||
|
"github.com/rivo/tview"
|
||
|
tcell "github.com/gdamore/tcell/v2"
|
||
|
)
|
||
|
|
||
|
type System struct {
|
||
|
// struct to hold actual system state
|
||
|
Display
|
||
|
Connected map[uint32]*Reactor
|
||
|
err chan error
|
||
|
|
||
|
|
||
|
type Display struct {
|
||
|
app *tview.Application
|
||
|
flex *tview.Flex
|
||
|
reactorlist *tview.List
|
||
|
sensortable *tview.Table
|
||
|
mu sync.Mutex
|
||
|
}
|
||
|
|
||
|
type Reactor struct {
|
||
|
Index int // index into list
|
||
|
Id uint32
|
||
|
Ip string
|
||
|
Port int
|
||
|
Model string
|
||
|
Status bool
|
||
|
Sensors map[int]*Sensor
|
||
|
}
|
||
|
|
||
|
func (r Reactor) String() string {
|
||
|
s := ""
|
||
|
if r.Status {
|
||
|
s = "[green]ONLINE"
|
||
|
} else {
|
||
|
s = "[red]OFFLINE"
|
||
|
}
|
||
|
return fmt.Sprintf("Reactor %v (%v) is %v on %v:%v",r.Id,r.Model,s,r.Ip,r.Port)
|
||
|
}
|
||
|
|
||
|
type Sensor struct {
|
||
|
Id uint32
|
||
|
Addr int
|
||
|
Type string
|
||
|
Status string
|
||
|
}
|
||
|
|
||
|
func NewDisplay(ch chan error) *Display {
|
||
|
m := make(map[uint32]*Reactor)
|
||
|
a := tview.NewApplication()
|
||
|
f := tview.NewFlex()
|
||
|
f.AddItem(tview.NewBox().SetTitle("Connected Reactors").SetBorder(true),0,1, true)
|
||
|
f.AddItem(tview.NewBox().SetTitle("Sensor Info").SetBorder(true),0,2, false)
|
||
|
if err := a.SetRoot(f,true).SetFocus(f).Run(); err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
a.Stop()
|
||
|
return &Display{app:a,Connected:m,err:ch}
|
||
|
}
|
||
|
|
||
|
func NewReactor(ip,model string, status bool, id uint32, port int) *Reactor {
|
||
|
s := map[int]*Sensor{}
|
||
|
return &Reactor{Ip:ip,Model:model,Status:status,Id:id,Port:port,Sensors:s}
|
||
|
}
|
||
|
|
||
|
func NewSensor(addr int, t, status string) *Sensor {
|
||
|
return &Sensor{Addr:addr,Type:t,Status:status}
|
||
|
}
|
||
|
|
||
|
func (d *Display) Start () {
|
||
|
go d.Refresh()
|
||
|
}
|
||
|
|
||
|
func (d *Display) UpdateReactor(r *Reactor) {
|
||
|
d.mu.Lock()
|
||
|
defer d.mu.Unlock()
|
||
|
if _, ok := d.Connected[r.Id]; ok {
|
||
|
// reactor exists in memory
|
||
|
d.Connected[r.Id] = r
|
||
|
d.reactorlist.SetItemText(r.Index,fmt.Sprint(r),"")
|
||
|
} else {
|
||
|
r.Index = d.reactorlist.GetItemCount() // get before adding
|
||
|
d.reactorlist.AddItem(fmt.Sprint(r),"",rune(r.Index), func () {d.SelectSensor(r.Id)})
|
||
|
}
|
||
|
d.app.Run()
|
||
|
d.app.Stop()
|
||
|
}
|
||
|
|
||
|
func (d *Display) UpdateSensor(s *Sensor) {
|
||
|
d.mu.Lock()
|
||
|
defer d.mu.Unlock()
|
||
|
if r,ok := d.Connected[s.Id]; ok {
|
||
|
r.Sensors[s.Addr] = s
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *Display) SelectSensor(id uint32) {
|
||
|
d.mu.Lock()
|
||
|
defer d.mu.Unlock()
|
||
|
if reactor, ok := d.Connected[id]; ok {
|
||
|
d.sensortable.Clear()
|
||
|
row := 0
|
||
|
ch := []string{"Type","Addr","Status"}
|
||
|
for i,v := range ch {
|
||
|
// create column headings
|
||
|
c := tview.NewTableCell(v).SetTextColor(tcell.ColorGray)
|
||
|
d.sensortable.SetCell(row,i,c)
|
||
|
}
|
||
|
row += 1
|
||
|
for a,s := range reactor.Sensors {
|
||
|
addr := tview.NewTableCell(string(a))
|
||
|
typ := tview.NewTableCell(s.Type)
|
||
|
st := ""
|
||
|
col := tcell.ColorWhite
|
||
|
if s.Status == "ACTIVE" {
|
||
|
col = tcell.ColorGreen
|
||
|
} else if s.Status == "KILLED" {
|
||
|
col = tcell.ColorRed
|
||
|
} else {
|
||
|
st = "UNKNOWN"
|
||
|
col = tcell.ColorYellow
|
||
|
}
|
||
|
status := tview.NewTableCell(st).SetTextColor(col)
|
||
|
d.sensortable.SetCell(row,0,typ)
|
||
|
d.sensortable.SetCell(row,1,addr)
|
||
|
d.sensortable.SetCell(row,2,status)
|
||
|
row += 1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (d *Display) Refresh() {
|
||
|
tick := time.NewTicker(500 * time.Millisecond)
|
||
|
for {
|
||
|
select {
|
||
|
case <-tick.C:
|
||
|
d.app.Draw()
|
||
|
}
|
||
|
}
|
||
|
}
|