diff --git a/internal/pkg/server/system.go b/internal/pkg/server/system.go index 57ae6e6..ffd80d7 100644 --- a/internal/pkg/server/system.go +++ b/internal/pkg/server/system.go @@ -124,12 +124,22 @@ func (l *listener) RemoveListener(id uint32) error { if lis, ok := l.Listeners[id]; !ok { return errors.New("Listener doesn't exists!") } else { - lis.Wait() - lis.StatusChan.Close() + go lis.Exit() delete(l.Listeners,id) } return nil } + +func (l *lischan) Exit() { + for { + select { + case ls.Wait(): + l.StatusChan.Close() + break; + case <-l.StatusChan: + // dump buffer + } +} //func (s *InfoStream) GetLayout() map[uint32]*DeviceInfo { //s.Layout.RLock() //defer s.Layout.RUnlock() @@ -141,11 +151,6 @@ type StatusMonitor struct { // serve as base to embed in managers to send/receive device info TransactionId chan uint32 // monotonically increases to track outdated reqs StatusChan chan *DeviceInfo // sending reactor info in same fmt - Buffer *buf -} - -type buf struct { - Buffer map[uint32]*DeviceInfo //directory of changes since last req sync.Mutex } @@ -212,19 +217,21 @@ func (s *SystemViewer) AddDeviceSender(reactorId uint32) *StatusMonitor { return ds.AddSender() } -func (s *SystemViewer) AddReactorListener(tid uint32) (map[uint32]*DeviceInfo, *StatusMonitor) { - // adds status monitor as a listener and returns any reactors loaded before our channel is active - // id serves as client id and limits them to one of each - rstatus, ch := s.ReactorStream.AddListener(id) - if sm - -func (s *SystemViewer) AddDeviceListener(rid, tid uint32) (map[uint32]*DeviceInfo, *StatusMonitor) { - // adds status monitor as a listener and returns any reactors loaded before our channel is active +func (s *SystemViewer) AddListener(tid uint32, rid ...uint32) (map[uint32]*DeviceInfo, *StatusMonitor) { + // adds status monitor as a listener and returns any already stored dev // id serves as client id and limits them to one of each + var rid uint32 + if len(ids) == 1 { + rid = uint32(ids[0]) + } else if len(ids) != 0{ + logging.Debug(logging.DError, "Too many arguements given to Add Listener") + os.Exit(1) + } + // id is either 0 or reactor we are interested in rstatus, sm := s.ReactorStream.AddListener(id) if sm - +func (s *SystemViewer) GetBuffer( /* func (s *SystemViewer) GetReactorStatus() map[uint32]DeviceInfo { devs := s.ReactorStream.GetLayout() diff --git a/internal/pkg/server/tuimanager.go b/internal/pkg/server/tuimanager.go index fe730ed..093ce61 100644 --- a/internal/pkg/server/tuimanager.go +++ b/internal/pkg/server/tuimanager.go @@ -17,13 +17,20 @@ import ( type TUIManager struct { *Manager // embedded manager for access to methods and client Ip string - *SystemViewer Port *port + DevsMon *StatusMonitor // use it for all devs coming in + *SystemViewer Err chan error + *DevBuffer *Timeout *pb.UnimplementedManagementServer } +type DevBuffer struct { + Devs []map[uint32]*DeviceInfo + sync.Mutex +} + type Timeout struct { Alert chan bool LastSeen time.Time @@ -43,8 +50,14 @@ func NewTUIManager(ip string, c *Client, sys *SystemViewer, err chan error) Gene alert := make(chan bool) t.Timeout = &Timeout{Alert:alert,TO:time.Duration(2500*time.Millisecond)} // short time outs are fine because we will just rejoin t.Manager = m - t.SystemViewer = sys t.Ip = ip + mon, buf := sys.AddListener() + t.DevsMon = mon + t.SystemViewer = sys + t.DevBuffer = &DevBuffer{Devs:[2]map[uint32]*DeviceInfo{})} + t.DevBuffer[0] = make(map[uint32]*DeviceInfo) + t.DevBuffer[1] = make(map[uint32]*DeviceInfo) // maps for reactors and devs + go t.UpdateBuffer(buf) return t } @@ -53,6 +66,7 @@ func (t *TUIManager) Start(cl *Client) { t.PingReset() t.Manager.Start(cl) logging.Debug(logging.DStart,"TMA %v starting", t.Id) + go t.DeviceListener() go t.Timeoutd() go t.Register() // begin tui server to respond to tui client reqs //go t.Monitor(conn) @@ -62,6 +76,7 @@ func (t *TUIManager) Exit() { t.Manager.Exit() logging.Debug(logging.DExit,"TMA %v exiting",t.Id) } + func (t *Timeout) PingReset() { t.Lock() defer t.Unlock() @@ -106,7 +121,7 @@ func (t *TUIManager) Register() { go func(ch chan int,p int) { ch <-p }(t.Port.Chan, t.Port.int) - logging.Debug(logging.DClient, "TMA %v reayd for client conn", t.Id) + logging.Debug(logging.DClient, "TMA %v ready for client conn", t.Id) // up and running } @@ -116,39 +131,65 @@ func (t *TUIManager) GetPort() int { } // tui client requests and logic will be down here - -func (t *TUIManager) ReactorListener() { +func (t *TUIManager) DeviceListener() { // called on start requests reactor info and buffers updates - buffer, devchan := t.SystemViewer.AddReactorListener(t.Id) - for dev := range devchan { - go t.UpdateReactor(dev) + for dev := range t.DevsMon.StatusChan { + go t.UpdateBuffer(dev) } } -func (t *TUIManager) DeviceListener(id uint32) { - buffer, devchan := t.SystemViewer.AddDeviceListener(t.Id,id) - for _, dev - for dev := range devchan { - go t.UpdateDevices(dev) +func (d *DevBuffer) UpdateBuffer(dv *DeviceInfo) { + // TODO + // need a way to take incoming devices and only store most recent entry in the buffer + d.Lock() + defer d.Unlock() + if dv.Type == "Reactor" { + d.Devs[0][dv.Id] = dv + } else { + d.Devs[1][dv.Id] = dv } } +func (d *DevBuffer) EmptyBuffer() []*DeviceInfo { + // TODO + // need to grab the current buffer contents and empty them into the device reply + d.Lock() + defer d.Unlock() + ret := []*DeviceInfo{} + for _, mp := range d.Devs { + for _, dev := range mp { + ret = append(ret,dev) + } + } + d.Devs = []map[uint32]*DeviceInfo{} + return ret +} + +func (t *TUIManager) AttachListener(id uint32) []*DeviceInfo { + // if a reactor is selected we need to + // empty the buffer + // get the dev info for the reactor + // add our devmon to the chan + + func (t *TUIManager) GetDevices(ctx context.Context, req *pb.GetDevicesRequest) (*pb.GetDevicesResponse, error) { go t.PingReset() + // doing 2 things, clearing reactor buffer and either + // a) clearing dev buffer + // b) killing old dev listener and getting new buffer rid := req.GetReactorId() devices := []*pb.Dev{} resp := &pb.GetDevicesResponse{ClientId:t.Id,ReactorId:rid,Devices:devices} - reactors := t.SystemViewer.GetReactorStatus() - for _, v := range reactors { - resp.Devices = append(resp.Devices, &pb.Dev{Id:v.Id,Type:v.Type,Status:v.Status,Data:v.Data,Index:v.Index}) + var devs []*DeviceInfo + if rid != 0 { + // reactor requested + devs = t.AttachListener(rid) + } else { + devs = t.EmptyBuffer() } - if rid != 0 { - // need reactor devices - devs := t.SystemViewer.GetDeviceStatus(rid) - for _, v := range devs { - resp.Devices = append(resp.Devices, &pb.Dev{Id:v.Id,Type:v.Type,Status:v.Status,Data:v.Data,Index:v.Index}) - } + for _, v := range devs { + resp.Devices = append(resp.Devices, &pb.Dev{Id:v.Id,Type:v.Type,Status:v.Status,Data:v.Data,Index:v.Index}) } logging.Debug(logging.DClient,"TMA %v sending devices to client" ,t.Id) return resp, nil diff --git a/internal/pkg/tui/client.go b/internal/pkg/tui/client.go index 5c325f4..b401091 100644 --- a/internal/pkg/tui/client.go +++ b/internal/pkg/tui/client.go @@ -128,7 +128,7 @@ func (t *TUIClient) GetDevices(id ...uint32) (map[uint32]*Device, error) { client := pb.NewManagementClient(t.ClientConn) resp, err := client.GetDevices(context.Background(), req) if err != nil { - return r, nil + return r, err } for _, v := range resp.GetDevices() { r[v.GetId()] = &Device{Type:v.GetType(),Status:v.GetStatus(),Id:v.GetId(),Data:v.GetData(),Index:v.GetIndex()} diff --git a/internal/pkg/tui/tui.go b/internal/pkg/tui/tui.go index 0ce7e34..87c4ddc 100644 --- a/internal/pkg/tui/tui.go +++ b/internal/pkg/tui/tui.go @@ -61,7 +61,7 @@ func (t *TUI) CreateDisplay() { t.SelectedReactor = rc t.SelectedDevice = dc t.Flex.AddItem(t.ReactorList,0,1,true). - AddItem(t.DevicePages,0,2,false) + AddItem(t.DeviceList,0,2,false) } func (t *TUI) Monitor() { @@ -79,14 +79,16 @@ func (t *TUI) Monitor() { case reactor := <-t.SelectedReactor: // reactor has been selected in tui, grabbing devs t.App.QueueUpdateDraw(func() { + t.Display.DeviceList.Clear() t.UpdateDevices(reactor) }) logging.Debug(logging.DClient, "%v getting reactor devices", t.Id) - case <-t.SelectedDevice: + case dev := <-t.SelectedDevice: + logging.Debug(logging.DClient, "%v editing device %v", t.Id, dev) // TODO case <-timer: // time to ping for status - logging.Debug(logging.DClient, "%v getting reactor status", t.Id) + logging.Debug(logging.DClient, "%v pinging for updates", t.Id) t.App.QueueUpdateDraw(func() { t.UpdateDevices() }) @@ -98,13 +100,14 @@ func (t *TUI) UpdateDevices(r ...uint32) { // get devices for the reactor and update the tui var id uint32 // see if there is a page being displayed + /* if name, _ := t.Display.DevicePages.GetFrontPage(); name != "" { if tmp, err := strconv.ParseUint(name, 10, 32); err != nil { log.Fatal(err) } else { id = uint32(tmp) } - } + }*/ // overwrite if called as a func if len(r) > 0 { id = r[0] @@ -113,22 +116,22 @@ func (t *TUI) UpdateDevices(r ...uint32) { if err != nil { log.Fatal(err) } - if id != 0 { - // reactor specificed split devs - reactors := make(map[uint32]*Device) - devices := make(map[uint32]*Device) - for id, dev := range devs { - if dev.Type == "Reactor" { - reactors[id] = dev - } else { - devices[id] = dev - } + //if id != 0 { + // split based on type to simplify update + reactors := make(map[uint32]*Device) + devices := make(map[uint32]*Device) + for id, dev := range devs { + if dev.Type == "Reactor" { + reactors[id] = dev + } else { + devices[id] = dev } - t.DisplayDevices(devices, id) - t.DisplayReactors(reactors) - } else { - t.DisplayReactors(devs) } + t.DisplayDevices(devices) + t.DisplayReactors(reactors) + // } else { + // t.DisplayReactors(devs) + //} } // display struct and logic @@ -136,8 +139,7 @@ type Display struct { App *tview.Application Flex *tview.Flex ReactorList *tview.List - DevicePages *tview.Pages - DeviceList map[string]*tview.List + DeviceList *tview.List SelectedReactor chan<- uint32 SelectedDevice chan<- uint32 sync.Mutex @@ -147,17 +149,16 @@ func NewDisplay(rc,dc chan uint32) *Display { d := &Display{} d.App = tview.NewApplication() d.Flex = tview.NewFlex() - lists := make(map[string]*tview.List) - d.DeviceList = lists - d.ReactorList = tview.NewList()//.ShowSecondaryText(false) + d.DeviceList = tview.NewList() + d.ReactorList = tview.NewList() d.ReactorList.AddItem("Quit","Press (q) to quit",113,func() { d.App.Stop() os.Exit(0) }) - d.DevicePages = tview.NewPages() d.ReactorList.SetTitle("Reactors").SetBorder(true) d.ReactorList.SetSelectedFunc(d.SelectReactor) - d.DevicePages.SetTitle("Devices").SetBorder(true) + d.DeviceList.SetTitle("Devices").SetBorder(true) + d.DeviceList.SetSelectedFunc(d.SelectDevice) d.SelectedReactor = rc d.SelectedDevice = dc return d @@ -171,21 +172,36 @@ func (d *Display) Start() { } func (d *Display) DisplayReactors(r map[uint32]*Device) { - // function to display reactor list to table - //d.Lock() - //defer d.Unlock() - // locking may break the hell out of this gonna trust tview + // this func takes in a list of devices to update and loops over them + // works by padding list for entries not seen yet for _, reactor := range r { txt := fmt.Sprintf("%v %v", reactor.Id, reactor.Status) - if d.ReactorList.GetItemCount() > int(reactor.Index) + 1 { - d.ReactorList.RemoveItem(int(reactor.Index)) + indx := int(reactor.Index) + for indx + 1 >= d.ReactorList.GetItemCount() { + // this prevent overwriting quit entry + d.ReactorList.InsertItem(-2,txt,reactor.Data,rune(48+d.ReactorList.GetItemCount()),nil) + } + if indx + 1 < d.ReactorList.GetItemCount() { + d.ReactorList.SetItemText(indx,txt,reactor.Data) } - d.ReactorList.InsertItem(int(reactor.Index),txt,reactor.Data,rune(49+reactor.Index),nil) } } -func (d *Display) DisplayDevices(devs map[uint32]*Device, rid uint32) { - //d.Lock() +func (d *Display) DisplayDevices(devs map[uint32]*Device) { + // going to just clear every time as we reload new dev lists anyway + // going to clear on every reactor selection to simplify + // can probably just load from SM to save system resources on spam reloading + for _, dev := range devs { + txt := fmt.Sprintf("0x%x %v %v",dev.Id,dev.Status,dev.Type) + indx := int(dev.Index) + for indx >= d.DeviceList.GetItemCount() { + d.DeviceList.AddItem(txt,dev.Data,rune(49+d.DeviceList.GetItemCount()), nil) + } + if indx < d.DeviceList.GetItemCount() { + d.DeviceList.SetItemText(indx,txt,dev.Data) + } + } + /* reactorPage := strconv.FormatUint(uint64(rid), 10) var reactorList *tview.List var ok bool @@ -203,6 +219,7 @@ func (d *Display) DisplayDevices(devs map[uint32]*Device, rid uint32) { reactorList.InsertItem(int(dev.Index),txt,dev.Data,0,nil) } d.DevicePages.SwitchToPage(reactorPage) + */ } @@ -219,10 +236,15 @@ func (d *Display) SelectReactor(index int, main, data string, r rune) { } } -func (d *Display) SelectDevice(index int, main, id string, r rune) { +func (d *Display) SelectDevice(index int, main, data string, r rune) { // called when device is selected in sub menu - if id, err := strconv.ParseUint(id, 10, 32); err != nil { - log.Fatal(err) + maintxt := strings.Split(main," ") + id := maintxt[0] + id = strings.Trim(id,"0x \n") + logging.Debug(logging.DClient,"Selected dev %v", id) + if id, err := strconv.ParseUint(id, 16, 32); err != nil { + logging.Debug(logging.DError, "Error parsing: %v", err) + os.Exit(1) } else { d.SelectedDevice <-uint32(id) }