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.
319 lines
7.9 KiB
Go
319 lines
7.9 KiB
Go
package server
|
|
|
|
import (
|
|
_ "fmt"
|
|
)
|
|
|
|
// allows for multiple readers/writers
|
|
type DeviceInfo struct {
|
|
Id int
|
|
Type string
|
|
Status string
|
|
Data string
|
|
Index int
|
|
TransactionId uint32
|
|
}
|
|
|
|
/*
|
|
|
|
type StatusMonitor struct {
|
|
// allows for embedding into managers
|
|
TransactionId chan uint32 // monotonically increases to track outdated reqs
|
|
DevChan chan *DeviceInfo // channel for device status
|
|
ReactorChan chan *DeviceInfo // channel for reactor status
|
|
*SystemViewer
|
|
DevBuf *devbuf
|
|
sync.Mutex
|
|
}
|
|
|
|
type devbuf struct {
|
|
ReactorId int // reactor we are looking at, if any
|
|
Buf map[string]map[int]*DeviceInfo // convienent way to store/seperate device data
|
|
sync.Mutex
|
|
}
|
|
|
|
func NewBuffer() map[string]map[int]*DeviceInfo {
|
|
rbuf := make(map[int]*DeviceInfo)
|
|
dbuf := make(map[int]*DeviceInfo)
|
|
sbuf := make(map[string]map[int]*DeviceInfo)
|
|
sbuf["Reactor"] = rbuf
|
|
sbuf["Device"] = dbuf
|
|
return sbuf
|
|
}
|
|
|
|
func NewStatusMonitor(t string, id int, sys *SystemViewer) *StatusMonitor {
|
|
tid := make(chan uint32)
|
|
sm := &StatusMonitor{TransactionId: tid}
|
|
sm.SystemViewer = sys
|
|
logging.Debug(logging.DClient, "SYS Creating new status monitor")
|
|
if t == "Reactor" {
|
|
// reactor status monitor
|
|
sm.ReactorChan = sys.AddReactorSender()
|
|
sm.DevChan = sys.AddDeviceSender(id)
|
|
go sm.GenerateIds()
|
|
} else {
|
|
// tui status monitor
|
|
sbuf := NewBuffer()
|
|
//sm.ReactorChan, sbuf["Reactor"] = sys.AddListener(id,0)
|
|
sm.DevBuf = &devbuf{Buf: sbuf} // makes it easier to work with
|
|
go sm.UpdateListener(id, 0)
|
|
}
|
|
return sm
|
|
}
|
|
|
|
func (s *StatusMonitor) GenerateIds() {
|
|
var id uint32
|
|
id = 0
|
|
for {
|
|
s.TransactionId <- id
|
|
id += 1
|
|
}
|
|
}
|
|
|
|
func (s *StatusMonitor) Send(d *DeviceInfo, dtype string) {
|
|
d.TransactionId = <-s.TransactionId
|
|
logging.Debug(logging.DClient, "SYS 01 Sending update for: %s (%s)", d.Type, d.Status)
|
|
if dtype == "Reactor" {
|
|
s.ReactorChan <- d
|
|
} else {
|
|
s.DevChan <- d
|
|
}
|
|
}
|
|
|
|
func (s *StatusMonitor) GetBuffer() []*DeviceInfo {
|
|
// also clears buffer
|
|
s.DevBuf.Lock()
|
|
defer s.DevBuf.Unlock()
|
|
res := []*DeviceInfo{}
|
|
if len(s.DevBuf.Buf["Reactor"]) != 0 || len(s.DevBuf.Buf["Device"]) != 0 {
|
|
logging.Debug(logging.DClient, "Clearing buff %v", s.DevBuf.Buf)
|
|
}
|
|
for _, devs := range s.DevBuf.Buf {
|
|
for _, dev := range devs {
|
|
// loops over reactors then devices
|
|
res = append(res, dev)
|
|
}
|
|
}
|
|
s.DevBuf.Buf = NewBuffer() // clearing old buffer
|
|
return res
|
|
}
|
|
|
|
func (s *StatusMonitor) UpdateListener(tid, reactorId uint32) {
|
|
s.DevBuf.Lock()
|
|
defer s.DevBuf.Unlock()
|
|
// clearing proper buffer
|
|
if reactorId == 0 {
|
|
logging.Debug(logging.DClient, "SYS 01 Adding %v as reactor listener", tid)
|
|
s.DevBuf.Buf["Reactor"] = make(map[uint32]*DeviceInfo)
|
|
s.ReactorChan, s.DevBuf.Buf["Reactor"] = s.SystemViewer.AddListener(tid, reactorId)
|
|
go s.Listen(s.ReactorChan)
|
|
} else {
|
|
logging.Debug(logging.DClient, "SYS 01 Adding %v as reactor %v listener", tid, reactorId)
|
|
s.DevBuf.Buf["Device"] = make(map[uint32]*DeviceInfo) // clearing old devices
|
|
if s.DevBuf.ReactorId != reactorId && s.DevBuf.ReactorId != 0 {
|
|
go s.SystemViewer.RemoveListener(s.DevBuf.ReactorId, tid)
|
|
}
|
|
s.DevBuf.ReactorId = reactorId
|
|
s.DevChan, s.DevBuf.Buf["Device"] = s.SystemViewer.AddListener(tid, reactorId)
|
|
go s.Listen(s.DevChan)
|
|
}
|
|
}
|
|
|
|
func (s *StatusMonitor) UpdateBuffer(d *DeviceInfo, dtype string, ch chan *DeviceInfo) {
|
|
s.DevBuf.Lock()
|
|
defer s.DevBuf.Unlock()
|
|
logging.Debug(logging.DClient, "SYS 01 Dev %v update requested", d)
|
|
if dev, exists := s.DevBuf.Buf[dtype][d.Id]; exists {
|
|
// already a device in the buffer
|
|
if dev.TransactionId > d.TransactionId {
|
|
logging.Debug(logging.DClient, "SYS 01 Update Processed. Old: %v, New: %v \n", dev, d)
|
|
d = dev // not sure if i can do this lol
|
|
}
|
|
}
|
|
if ch == s.ReactorChan || ch == s.DevChan {
|
|
// hacky way to check if the device came from a listener of a current channel
|
|
s.DevBuf.Buf[dtype][d.Id] = d
|
|
} else {
|
|
logging.Debug(logging.DClient, "Dev out of date!")
|
|
}
|
|
}
|
|
|
|
func (s *StatusMonitor) Listen(ch chan *DeviceInfo) {
|
|
for dev := range ch {
|
|
if dev.Type == "Reactor" {
|
|
go s.UpdateBuffer(dev, "Reactor", ch)
|
|
} else {
|
|
go s.UpdateBuffer(dev, "Device", ch)
|
|
}
|
|
}
|
|
}
|
|
|
|
type InfoStream struct {
|
|
// base stream for any reactor/device
|
|
// NewSender embedds the channel to send updates on
|
|
// NewListener will add the statusmon to the list of devs to echo to
|
|
Stream chan *DeviceInfo
|
|
Layout *syslayout
|
|
*listeners
|
|
}
|
|
|
|
type listeners struct {
|
|
sync.RWMutex
|
|
Listeners map[uint32]*lischan
|
|
}
|
|
|
|
type lischan struct {
|
|
sync.WaitGroup
|
|
StatusChan chan *DeviceInfo
|
|
}
|
|
|
|
type syslayout struct {
|
|
Devs map[uint32]*DeviceInfo
|
|
uint32 //index
|
|
sync.RWMutex
|
|
}
|
|
|
|
func NewLisChan(ch chan *DeviceInfo) *lischan {
|
|
l := &lischan{StatusChan: ch}
|
|
return l
|
|
}
|
|
|
|
func NewInfoStream() *InfoStream {
|
|
dch := make(chan *DeviceInfo)
|
|
s := &InfoStream{Stream: dch}
|
|
m := make(map[uint32]*DeviceInfo)
|
|
s.Layout = &syslayout{Devs: m}
|
|
s.listeners = &listeners{Listeners: make(map[uint32]*lischan)}
|
|
return s
|
|
}
|
|
|
|
func (s *InfoStream) Start() {
|
|
// consistency
|
|
go s.Listen()
|
|
}
|
|
|
|
// goal is to hook every new manager into the reactor status chan
|
|
func (s *InfoStream) AddSender() chan *DeviceInfo {
|
|
return s.Stream
|
|
}
|
|
|
|
func (s *InfoStream) Listen() {
|
|
for deviceInfo := range s.Stream {
|
|
go s.Update(deviceInfo)
|
|
}
|
|
}
|
|
|
|
func (s *InfoStream) Update(d *DeviceInfo) {
|
|
s.Layout.Lock()
|
|
defer s.Layout.Unlock()
|
|
if dev, ok := s.Layout.Devs[d.Id]; !ok {
|
|
d.Index = s.Layout.uint32
|
|
s.Layout.uint32 += 1
|
|
} else {
|
|
d.Index = dev.Index
|
|
}
|
|
s.Layout.Devs[d.Id] = d
|
|
go s.Echo(d)
|
|
}
|
|
|
|
func (l *listeners) Echo(d *DeviceInfo) {
|
|
l.RLock()
|
|
defer l.RUnlock()
|
|
// read only lock
|
|
for _, lis := range l.Listeners {
|
|
lis.Add(1)
|
|
go func(listener *lischan, dev *DeviceInfo) {
|
|
defer listener.Done()
|
|
listener.StatusChan <- dev
|
|
}(lis, d)
|
|
}
|
|
}
|
|
|
|
func (s *InfoStream) AddListener(id int, ch chan *DeviceInfo) map[uint32]*DeviceInfo {
|
|
// if i get a memory leak ill eat my shoe
|
|
s.listeners.Lock()
|
|
defer s.listeners.Unlock()
|
|
if _, ok := s.listeners.Listeners[id]; ok {
|
|
// exists
|
|
go s.RemoveListener(id)
|
|
}
|
|
s.listeners.Listeners[id] = NewLisChan(ch)
|
|
logging.Debug(logging.DClient, "SYS 01 Getting Devices")
|
|
//s.Layout.RLock()
|
|
//defer s.Layout.RUnlock()
|
|
logging.Debug(logging.DClient, "SYS 01 Returning Devices %v", s.Layout.Devs)
|
|
return s.Layout.Devs
|
|
}
|
|
|
|
func (l *listeners) RemoveListener(id int) {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
if lis, ok := l.Listeners[id]; ok {
|
|
delete(l.Listeners, id)
|
|
go func(ls *lischan) {
|
|
ls.Wait()
|
|
close(ls.StatusChan)
|
|
}(lis)
|
|
}
|
|
}
|
|
|
|
// status buffer maintaince
|
|
|
|
type SystemViewer struct {
|
|
// stores system directory and provide methods to be embedded in managers
|
|
ReactorStream *InfoStream // can add itself as a listener to provide methods
|
|
DeviceStream *ds
|
|
}
|
|
|
|
type ds struct {
|
|
Reactors map[uint32]*InfoStream //map from reactor id to its device info stream
|
|
sync.Mutex
|
|
}
|
|
|
|
func NewSystemViewer() *SystemViewer {
|
|
rs := NewInfoStream()
|
|
s := &SystemViewer{ReactorStream: rs}
|
|
m := make(map[uint32]*InfoStream)
|
|
s.DeviceStream = &ds{Reactors: m}
|
|
return s
|
|
}
|
|
|
|
func (s *SystemViewer) Start() {
|
|
go s.ReactorStream.Start()
|
|
}
|
|
|
|
func (s *SystemViewer) AddReactorSender() chan *DeviceInfo {
|
|
return s.ReactorStream.AddSender()
|
|
}
|
|
|
|
func (s *SystemViewer) AddDeviceSender(reactorId uint32) chan *DeviceInfo {
|
|
s.DeviceStream.Lock()
|
|
defer s.DeviceStream.Unlock()
|
|
var ds *InfoStream
|
|
var ok bool
|
|
if ds, ok = s.DeviceStream.Reactors[reactorId]; !ok {
|
|
ds = NewInfoStream()
|
|
s.DeviceStream.Reactors[reactorId] = ds
|
|
go ds.Start()
|
|
}
|
|
return ds.AddSender()
|
|
}
|
|
|
|
func (s *SystemViewer) AddListener(id, rid int) (chan *DeviceInfo, map[uint32]*DeviceInfo) {
|
|
// returns a listener for that chan
|
|
ch := make(chan *DeviceInfo)
|
|
if rid != 0 {
|
|
return ch, s.DeviceStream.Reactors[rid].AddListener(id, ch)
|
|
} else {
|
|
return ch, s.ReactorStream.AddListener(id, ch)
|
|
}
|
|
}
|
|
|
|
func (s *SystemViewer) RemoveListener(rid, tid int) {
|
|
// removes chan for specific tid and rid
|
|
s.DeviceStream.Lock()
|
|
defer s.DeviceStream.Unlock()
|
|
go s.DeviceStream.Reactors[rid].RemoveListener(tid)
|
|
}
|
|
*/
|