From 0ccac301f1c1946f90553c097d596c12c923f7f8 Mon Sep 17 00:00:00 2001 From: Keegan Date: Sun, 4 Sep 2022 16:10:01 -0400 Subject: [PATCH] Super broken but what are you gonna do --- cmd/reactor/main.go | 103 +++---- internal/pkg/config/def.go | 52 ++++ internal/pkg/config/flags.go | 5 + internal/pkg/config/load.go | 172 ++++++++++++ internal/pkg/config/reactor.go | 25 +- internal/pkg/config/server.go | 27 +- internal/pkg/reactor/rlcoordinator.go | 388 +++++++++++++------------- notes | 65 ++++- 8 files changed, 544 insertions(+), 293 deletions(-) create mode 100644 internal/pkg/config/def.go create mode 100644 internal/pkg/config/flags.go create mode 100644 internal/pkg/config/load.go diff --git a/cmd/reactor/main.go b/cmd/reactor/main.go index bbd3b10..f3445bc 100644 --- a/cmd/reactor/main.go +++ b/cmd/reactor/main.go @@ -1,59 +1,68 @@ package main import ( - "fmt" - "os" - "flag" - "log" - "strconv" - "FRMS/internal/pkg/reactor" - "FRMS/internal/pkg/logging" + "FRMS/internal/pkg/config" + "FRMS/internal/pkg/logging" + "FRMS/internal/pkg/reactor" + + flag "github.com/spf13/pflag" + "github.com/spf13/viper" ) type coordinator interface { - Start() + Start() } -func NewCoordinator(ip string,port int,ch chan error) coordinator { - // allows interface checking as opposed to calling directly - return reactor.NewCoordinator(ip,port,ch) +func NewCoordinator(ip string, port int, ch chan error) coordinator { + // allows interface checking as opposed to calling directly + return reactor.NewCoordinator(ip, port, ch) } -func main() { - var ip string - var port int - - flag.Usage = func() { - w := flag.CommandLine.Output() - fmt.Fprintf(w, "Usage: %s port \n",os.Args[0]) - } - iptr := flag.String("i","192.168.100.2","ip address of server") - //iptr := flag.String("i","192.1.168.136","ip address of laptop") - flag.Parse() - if flag.NArg() != 1 { - flag.Usage() - os.Exit(1) - } - args := flag.Args() - - if p, err := strconv.Atoi(args[0]);p < 1024 || p > 65535 { - flag.Usage() - log.Fatal("Port must be between [1023,65535]") - } else if err != nil { - log.Fatal(err) - } - ip = *iptr - port, err := strconv.Atoi(args[0]) - if err != nil { - log.Fatal(err) - } - ch := make(chan error) - rlc := NewCoordinator(ip,port,ch) // host port - go rlc.Start() - logging.Debug(logging.DStart, "Reactor Started") - err = <-ch - if err != nil { - log.Fatal(err) - } +type Config interface { + Load() error // load config, keys and env for a string + Store() error // write any pending changes +} + +func NewConfig(fname string) Config { + if conf, err := config.NewConfig(fname); err != nil { + panic(err) + } + return conf } +func main() { + + // load any stored settings + conf := NewConfig("reactor") // loads .yaml and flags + conf.Load() // load exisiting settings + + // get overrides + var ip string + var port int + /* + flag.Usage = func() { + w := flag.CommandLine.Output() + fmt.Fprintf(w, "Usage: %s port \n",os.Args[0]) + }*/ + iptr := flag.String("ip", "192.168.100.2", "server ip") + portptr := flag.String("port", 2022, "server port") + nameptr := flag.String("name", "", "human readable name") + + flag.Parse() + + // lets us retrieve them from viper later + + if err := viper.BindPFlags(flag.CommandLine); err != nil { + panic(err) + } + + ch := make(chan error) + rlc := NewCoordinator(ch) // passing only err chan + go rlc.Start() + logging.Debug(logging.DStart, "Reactor Started") + for err = range ch { + if err != nil { + panic(err) + } + } +} diff --git a/internal/pkg/config/def.go b/internal/pkg/config/def.go new file mode 100644 index 0000000..5fc48ce --- /dev/null +++ b/internal/pkg/config/def.go @@ -0,0 +1,52 @@ +package config + +// def.go serves as a central place to view/edit config structs and device manager map + +import ( + "sync" +) + +// Server Config + +type ServerConf struct { + // Structure to demarshall into + Server ServerConfig `mapstructure:"server"` + Reactors map[string]ReactorConfig `mapstructure:"reactors"` + sync.RWMutex +} + +type ServerConfig struct { + // Server config settings + URL string `mapstructure:"db-url"` + Token string `mapstructure:"db-token"` + Orginization string `mapstructure:"db-org"` + Ports map[string]int `mapstructure:"ports"` // changed from map[string]string to map[string]int + Name string `mapstructure:"name"` +} + +// Reactor Config + +type ReactorConf struct { + // Structure to demarshall to + Reactor ReactorConfig `mapstructure:"reactor"` + Devices map[int]DeviceConfig `mapstructure:"devices"` + sync.RWMutex +} + +type ReactorConfig struct { + // Reactor config settings + Token string `mapstructure:"db-token"` + Bucket string `mapstructure:"db-bucket"` + URL string `mapstructure:"db-url",omitempty` // only needed by reactor + Name string `mapstructure:"name",omitempty` // not always set + Id uint32 `mapstructure:"id"` +} + +// Device Config + +type DeviceConfig struct { + // Device config settings + Address uint32 `mapstructure:"address"` + Interval uint32 `mapstructure:"interval"` + Name string `mapstructure:"name"` +} diff --git a/internal/pkg/config/flags.go b/internal/pkg/config/flags.go new file mode 100644 index 0000000..7490a17 --- /dev/null +++ b/internal/pkg/config/flags.go @@ -0,0 +1,5 @@ +package config + +/* +Package provides a way to update current config based on values passed in flags +*/ diff --git a/internal/pkg/config/load.go b/internal/pkg/config/load.go new file mode 100644 index 0000000..54ea492 --- /dev/null +++ b/internal/pkg/config/load.go @@ -0,0 +1,172 @@ +package config + +/* +Load.go contains methods to load values from config, flags and env. +*/ + +import ( + "FRMS/internal/pkg/logging" + "errors" + "fmt" + "strconv" + "strings" + + "github.com/spf13/viper" + //"os" + //"log" + //"os/exec" + //"bytes" +) + +func NewConfig(name string) (Config, error) { + // returns a Config Structure of assocaited name + return + +type ConfigStruct interface { + // structure to do demarshall config into + LoadFile(string) error +} + +func LoadConfigFile(fname string, strct ConfigStruct) error { + // Demarshalls a given filename into the struct + // returns nil if successful + logging.Debug(logging.DStart, "Loading config for %s", fname) + viper.SetConfigName(fname) + viper.SetConfigType("yaml") + viper.AddConfigPath("/etc/frms/config") + + // unmarshalling + if err := viper.ReadInConfig(); err != nil { + return err + } + + logging.Debug(logging.DStart, "CON Loaded configs from %v", viper.ConfigFileUsed()) + if err = viper.Unmarshal(strct); err != nil { + logging.Debug(logging.DError, "Cannot unmarshall %v", err) + return err + } + fmt.Printf("Outcome: %#v\n \n", C) + // unmarshalled at this point +} + +//// + +func LoadConfig() Config { + return C +} + +func (c *ServerConf) GetURL() (string, error) { + c.RLock() + defer c.RUnlock() + return C.Server.URL, nil +} + +func (c *ServerConf) GetOrg() (string, error) { + c.RLock() + defer c.RUnlock() + return c.Server.Orginization, nil +} + +func (c *ServerConf) GetPort(port string) (int, error) { + c.RLock() + defer c.RUnlock() + portString, ok := c.Server.Ports[port] + if !ok { + portEnv := strings.ToUpper(port) + "_PORT" + return 0, fmt.Errorf("%s port doesnt exist! Please set using env %s=####", port, portEnv) + } + // returns int, err + //return strconv.Atoi(portString) + return portString, nil +} + +func (c *ServerConf) GetServerToken() (string, error) { + c.RLock() + defer c.RUnlock() + return c.Server.Token, nil +} + +func (c *ServerConf) GetReactorClient(id uint32) (string, string, error) { + c.RLock() + defer c.RUnlock() + idString := strconv.FormatUint(uint64(id), 10) + if r, ok := c.Reactors[idString]; ok { + return r.Bucket, r.Token, nil + } + return "", "", fmt.Errorf("reactor %v config doesnt exist", id) +} + +// setters +func (c *ServerConf) UpdateURL(url string) error { + c.Lock() + defer c.Unlock() + if url == "" { + return errors.New("string cannot be empty") + } + c.Server.URL = url + viper.Set("server.db-url", url) + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} + +func (c *ServerConf) UpdateOrg(org string) error { + c.Lock() + defer c.Unlock() + if org == "" { + return errors.New("string cannot be empty") + } + c.Server.Orginization = org + viper.Set("server.db-org", org) + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} + +func (c *ServerConf) UpdatePort(pName string, port int) error { + c.Lock() + defer c.Unlock() + if port < 1024 || port > 65535 { + // OOB + return fmt.Errorf("Port %d out of bounds! [1024,65535]", port) + } + if c.Server.Ports == nil { + c.Server.Ports = make(map[string]int) + } + c.Server.Ports[pName] = port + pname := fmt.Sprintf("server.ports.%s", pName) + viper.Set(pname, port) + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} + +func (c *ServerConf) UpdateServerToken(token string) error { + c.Lock() + defer c.Unlock() + if token == "" { + return errors.New("String cannot be empty!") + } + c.Server.Token = token + viper.Set("server.token", token) + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} + +func (c *ServerConf) UpdateReactorClient(id uint32, bucket, token string) error { + c.Lock() + c.Unlock() + sid := strconv.FormatUint(uint64(id), 10) + if token == "" || bucket == "" { + return errors.New("String cannot be empty!") + } + if reactor, ok := c.Reactors[sid]; !ok { + c.Reactors[sid] = ReactorConfig{Token: token, Bucket: bucket, Id: id} + } else { + reactor.Bucket = bucket + reactor.Token = token + c.Reactors[sid] = reactor + } + reactorbucket := fmt.Sprintf("%s.db-bucket", id) + reactortoken := fmt.Sprintf("%s.db-token", id) + viper.Set(reactorbucket, bucket) + viper.Set(reactortoken, token) + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} + +func (c *ServerConf) Store() error { + return viper.WriteConfigAs(viper.ConfigFileUsed()) +} diff --git a/internal/pkg/config/reactor.go b/internal/pkg/config/reactor.go index f227709..8ca77be 100644 --- a/internal/pkg/config/reactor.go +++ b/internal/pkg/config/reactor.go @@ -1,26 +1,3 @@ package config -// pacakge serves to store/load config files for reactor - -import ( - "sync" -) - -type ReactorConf struct { - Reactor ReactorConfig `mapstructure:"reactor"` - Devices map[int]DeviceConfig `mapstructure:"devices"` - sync.RWMutex -} - -type DeviceConfig struct { - Address uint32 `mapstructure:"address"` - Interval uint32 `mapstructure:"interval"` - Name string `mapstructure:"name"` -} - -// loaded in other file -func (c *ReactorConf) GetURL() (string, error) { - c.RLock() - defer c.RUnlock() - return c.Reactor.URL, nil -} +// pacakge serves to provide reactor config implementation diff --git a/internal/pkg/config/server.go b/internal/pkg/config/server.go index a1b5001..9d600b1 100644 --- a/internal/pkg/config/server.go +++ b/internal/pkg/config/server.go @@ -1,6 +1,6 @@ package config -// package serves to store/load config files for server +// package serves to implement config interface for server import ( "FRMS/internal/pkg/logging" @@ -8,7 +8,6 @@ import ( "fmt" "strconv" "strings" - "sync" "github.com/spf13/viper" //"os" @@ -17,28 +16,6 @@ import ( //"bytes" ) -type ServerConf struct { - Server ServerConfig `mapstructure:"server"` - Reactors map[string]ReactorConfig `mapstructure:"reactors"` - sync.RWMutex -} - -type ServerConfig struct { - URL string `mapstructure:"db-url"` - Token string `mapstructure:"db-token"` - Orginization string `mapstructure:"db-org"` - Ports map[string]int `mapstructure:"ports"` // changed from map[string]string to map[string]int - Name string `mapstructure:"name"` -} - -type ReactorConfig struct { - Token string `mapstructure:"db-token"` - Bucket string `mapstructure:"db-bucket"` - URL string `mapstructure:"db-url",omitempty` // only needed by reactor - Name string `mapstructure:"name",omitempty` // not always set - Id uint32 `mapstructure:"id"` -} - type Config interface { Store() error } @@ -84,6 +61,8 @@ func LoadConfig() Config { return C } +func (c *ServerConf) Load() + func (c *ServerConf) GetURL() (string, error) { c.RLock() defer c.RUnlock() diff --git a/internal/pkg/reactor/rlcoordinator.go b/internal/pkg/reactor/rlcoordinator.go index a5ab7ad..32cbce4 100644 --- a/internal/pkg/reactor/rlcoordinator.go +++ b/internal/pkg/reactor/rlcoordinator.go @@ -3,258 +3,268 @@ package reactor // file describes reactor level coordinator and associated implementation import ( - "fmt" - "sync" - "time" - "math" - "FRMS/internal/pkg/system" - "FRMS/internal/pkg/I2C" - "FRMS/internal/pkg/sensor" - "FRMS/internal/pkg/logging" - "errors" - "context" - "google.golang.org/grpc" - "google.golang.org/grpc/status" - "google.golang.org/grpc/credentials/insecure" - "github.com/influxdata/influxdb-client-go/v2" - pb "FRMS/internal/pkg/grpc" + "FRMS/internal/pkg/I2C" + pb "FRMS/internal/pkg/grpc" + "FRMS/internal/pkg/logging" + "FRMS/internal/pkg/sensor" + "FRMS/internal/pkg/system" + "context" + "errors" + "fmt" + "math" + "sync" + "time" + + influxdb2 "github.com/influxdata/influxdb-client-go/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" ) // Coordinator == Reactor Level Coordinator type Coordinator struct { - Ip string - Port int // listener port - MonitoringClient pb.MonitoringClient - *hw - Devices *DeviceManagers // struct for fine grain locking - Err chan error - mu sync.Mutex - HB time.Duration - PingTimer chan struct{} - *DB - Active active + Ip string + Port int // listener port + MonitoringClient pb.MonitoringClient + *hw + Devices *DeviceManagers // struct for fine grain locking + Err chan error + mu sync.Mutex + HB time.Duration + PingTimer chan struct{} + *DB + Active active } type DB struct { - // struct to hold db connection info - Org string - Bucket string - Token string - URL string + // struct to hold db connection info + Org string + Bucket string + Token string + URL string } type active struct { - bool - int - sync.Mutex + bool + int + sync.Mutex } type hw struct { - // store reactor info - Model string - Bus int - Id uint32 + // store reactor info + Model string + Bus int + Id uint32 } type DeviceManagers struct { - Managers map[int]DeviceManager - sync.Mutex + Managers map[int]DeviceManager + sync.Mutex } + // basic devicemanager struct manipulations type DeviceManager interface { - Start() - GetType() string - GetStatus() string - GetData() string + Start() + GetType() string + GetStatus() string + GetData() string } type I2CDev interface { - GetAddr() int - GetData() string - GetStatus() string - GetType() string + GetAddr() int + GetData() string + GetStatus() string + GetType() string } func NewDeviceManager(i2c I2CDev) DeviceManager { - return sensor.NewDeviceManager(i2c) + return sensor.NewDeviceManager(i2c) } type I2CMonitor interface { - Monitor() - GetDevice(int) interface{ GetAddr() int; GetStatus() string; GetData() string; GetType() string} + Monitor() + GetDevice(int) interface { + GetAddr() int + GetStatus() string + GetData() string + GetType() string + } } -func NewI2CMonitor(b int,ch chan int) I2CMonitor { - return I2C.NewMonitor(b, ch) +func NewI2CMonitor(b int, ch chan int) I2CMonitor { + return I2C.NewMonitor(b, ch) } -func NewCoordinator(ip string,port int,ch chan error) *Coordinator { - sen := new(DeviceManagers) - sen.Managers = make(map[int]DeviceManager) - c := &Coordinator{Err:ch,Devices:sen} - c.Ip = ip - c.Port = port - c.hw = &hw{} - c.HB = time.Duration(5 * time.Second) - c.PingTimer = make(chan struct{}) - // this is going to be scuffed - url := fmt.Sprintf("http://%s:8086",ip) - fmt.Println(url) - c.DB = &DB{Bucket:"bb",Org:"ForeLight",URL:url,Token:"S1UZssBu6KPfHaQCt34pZFpyc5lzbH9XanYJWCkOI5FqLY7gq205C6FTH-CmugiPH6o2WoKlTkEuPgIfaJjAhw=="} - return c +func NewCoordinator(ip string, port int, ch chan error) *Coordinator { + sen := new(DeviceManagers) + sen.Managers = make(map[int]DeviceManager) + c := &Coordinator{Err: ch, Devices: sen} + // all this stuff can come from config + c.Ip = ip + c.Port = port + c.hw = &hw{} + c.HB = time.Duration(5 * time.Second) + + // this is going to be scuffed + url := fmt.Sprintf("http://%s:8086", ip) + fmt.Println(url) + c.DB = &DB{Bucket: "bb", Org: "ForeLight", URL: url, Token: "S1UZssBu6KPfHaQCt34pZFpyc5lzbH9XanYJWCkOI5FqLY7gq205C6FTH-CmugiPH6o2WoKlTkEuPgIfaJjAhw=="} + + c.PingTimer = make(chan struct{}) + return c } func (c *Coordinator) Start() { - // should discover hwinfo and sensors on its own - // now setting up sensor managers - // setting up hw stuff - c.Activate() - var err error - c.Id, err = system.GetId("eth0") - c.Model, err = system.GetModel() - c.Bus, err = system.GetBus() - if err != nil { - c.Err <-err - } - go c.Monitor() - go c.Discover() + // should discover hwinfo and sensors on its own + // now setting up sensor managers + // setting up hw stuff + c.Activate() + var err error + c.Id, err = system.GetId("eth0") + c.Model, err = system.GetModel() + c.Bus, err = system.GetBus() + if err != nil { + c.Err <- err + } + go c.Monitor() + go c.Discover() } func (c *Coordinator) Monitor() { - // function to automatically create and destroy sm - // scuffedaf - client := influxdb2.NewClient(c.URL,c.Token) - defer client.Close() - dch := make(chan int) - im := NewI2CMonitor(c.Bus,dch) - go im.Monitor() - for c.IsActive() { - select { - case d := <-dch: - i := im.GetDevice(d) - go c.DeviceConnect(i) - case <-c.PingTimer: - go c.Ping(client) - } - } + // function to automatically create and destroy sm + // scuffedaf + client := influxdb2.NewClient(c.URL, c.Token) + defer client.Close() + dch := make(chan int) + im := NewI2CMonitor(c.Bus, dch) + go im.Monitor() + for c.IsActive() { + select { + case d := <-dch: + i := im.GetDevice(d) + go c.DeviceConnect(i) + case <-c.PingTimer: + go c.Ping(client) + } + } } func (c *Coordinator) HeartBeat() { - for c.IsActive() { - c.PingTimer <-struct{}{} - logging.Debug(logging.DClient,"RLC Pinging server") - time.Sleep(c.HB) - } + for c.IsActive() { + c.PingTimer <- struct{}{} + logging.Debug(logging.DClient, "RLC Pinging server") + time.Sleep(c.HB) + } } func (c *Coordinator) DeviceConnect(i2c I2CDev) { - c.Devices.Lock() - defer c.Devices.Unlock() - addr := i2c.GetAddr() - if dm, exists := c.Devices.Managers[addr]; !exists{ - dm := NewDeviceManager(i2c) - c.Devices.Managers[addr] = dm - go dm.Start() - } else { - go dm.Start() - } + c.Devices.Lock() + defer c.Devices.Unlock() + addr := i2c.GetAddr() + if dm, exists := c.Devices.Managers[addr]; !exists { + dm := NewDeviceManager(i2c) + c.Devices.Managers[addr] = dm + go dm.Start() + } else { + go dm.Start() + } } func (c *Coordinator) Discover() { - // sets up connection to central coordiantor - conn, err := c.Connect(c.Ip, c.Port) - if err != nil { - c.Err <-err - } - defer conn.Close() - client := pb.NewHandshakeClient(conn) - req := &pb.ClientRequest{ClientId:c.Id,ClientType:"reactor"} - resp, err := client.ClientDiscoveryHandler(context.Background(), req) - if err != nil { - c.Err <-err - } - c.Port = int(resp.GetServerPort()) // updating server port - logging.Debug(logging.DClient,"RLC Central server reached, supplied port %v",c.Port) - // connecting to manager now - clientConn, err := c.Connect(c.Ip, c.Port) - if err != nil { - c.Err <-err - } - c.MonitoringClient = pb.NewMonitoringClient(clientConn) - go c.HeartBeat() + // sets up connection to central coordiantor + conn, err := c.Connect(c.Ip, c.Port) + if err != nil { + c.Err <- err + } + defer conn.Close() + client := pb.NewHandshakeClient(conn) + req := &pb.ClientRequest{ClientId: c.Id, ClientType: "reactor"} + resp, err := client.ClientDiscoveryHandler(context.Background(), req) + if err != nil { + c.Err <- err + } + c.Port = int(resp.GetServerPort()) // updating server port + logging.Debug(logging.DClient, "RLC Central server reached, supplied port %v", c.Port) + // connecting to manager now + clientConn, err := c.Connect(c.Ip, c.Port) + if err != nil { + c.Err <- err + } + c.MonitoringClient = pb.NewMonitoringClient(clientConn) + go c.HeartBeat() } func (c *Coordinator) Connect(ip string, port int) (*grpc.ClientConn, error) { - // function connects to central server and passes hwinfo - var opts []grpc.DialOption - opts = append(opts,grpc.WithTransportCredentials(insecure.NewCredentials())) - var conn *grpc.ClientConn - var err error - for { - conn, err = grpc.Dial(fmt.Sprintf("%v:%v",ip,port),opts...) - code := status.Code(err) - if code != 0 { // != OK - if code == (5 | 14) { // service temp down - to := c.Timeout() - if to == 0 { - err = errors.New("Failed to connect to central server") - return &grpc.ClientConn{}, err - } - logging.Debug(logging.DClient,"Server currently unavailable, retrying in %v ms", to) - time.Sleep(time.Duration(to) * time.Millisecond) - } else { - return &grpc.ClientConn{}, err - } - } - break; - } - return conn, nil + // function connects to central server and passes hwinfo + var opts []grpc.DialOption + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + var conn *grpc.ClientConn + var err error + for { + conn, err = grpc.Dial(fmt.Sprintf("%v:%v", ip, port), opts...) + code := status.Code(err) + if code != 0 { // != OK + if code == (5 | 14) { // service temp down + to := c.Timeout() + if to == 0 { + err = errors.New("Failed to connect to central server") + return &grpc.ClientConn{}, err + } + logging.Debug(logging.DClient, "Server currently unavailable, retrying in %v ms", to) + time.Sleep(time.Duration(to) * time.Millisecond) + } else { + return &grpc.ClientConn{}, err + } + } + break + } + return conn, nil } func (c *Coordinator) Timeout() int { - c.Active.Lock() - defer c.Active.Unlock() - if c.Active.int < 9 { - v := int(5 * math.Pow(float64(2), float64(c.Active.int))) - c.Active.int +=1 - return v - } else { - //excedded retries - return 0 - } + c.Active.Lock() + defer c.Active.Unlock() + if c.Active.int < 9 { + v := int(5 * math.Pow(float64(2), float64(c.Active.int))) + c.Active.int += 1 + return v + } else { + //excedded retries + return 0 + } } func (c *Coordinator) IsActive() bool { - c.Active.Lock() - defer c.Active.Unlock() - return c.Active.bool + c.Active.Lock() + defer c.Active.Unlock() + return c.Active.bool } func (c *Coordinator) Exit() bool { - c.Active.Lock() - defer c.Active.Unlock() - if c.Active.bool { - c.Active.bool = false - logging.Debug(logging.DClient,"RLC Exiting...") - return true - } else { - logging.Debug(logging.DError, "RLC Already Dead!") - return false - } + c.Active.Lock() + defer c.Active.Unlock() + if c.Active.bool { + c.Active.bool = false + logging.Debug(logging.DClient, "RLC Exiting...") + return true + } else { + logging.Debug(logging.DError, "RLC Already Dead!") + return false + } } func (c *Coordinator) Activate() bool { - c.Active.Lock() - defer c.Active.Unlock() - if c.Active.bool { - logging.Debug(logging.DError,"RLC Already Started!") - return false - } else { - logging.Debug(logging.DClient, "RLC Starting") - c.Active.bool = true - return c.Active.bool - } + c.Active.Lock() + defer c.Active.Unlock() + if c.Active.bool { + logging.Debug(logging.DError, "RLC Already Started!") + return false + } else { + logging.Debug(logging.DClient, "RLC Starting") + c.Active.bool = true + return c.Active.bool + } } diff --git a/notes b/notes index bf54896..99d46ce 100644 --- a/notes +++ b/notes @@ -937,15 +937,62 @@ Basic reactor workflow overview 2) For every device shown as active, spawn a sensor manager from the assocaited config 3) on disconnect, shut the dm down and save current settings to config - - - - - - - - - +implementation time +#TODO 9/4 +Might be dying nbd + - i think its just freshman flu but could be clot who knows + +on to code +Need to have a functional BETA by 9/15 at the latest + pref 9/8 with a week to test + +What do we NEED out of FRMS v0.1.0 (pre-alpha + as an aside v1.#.#-apha then v.1.#.#-beta for versions) + +Needs: + - Connect and disconnect at will + - set sample and log rate + - set name + - live view data + - export expiriement data to CSV + +Notes: + - all sensors will be atlas + - can leverage for a unified library + - can use grafana for the UI + - can bash script to eport data for a given time range into resspective sheet aka sheet of DO measurements etc. + - can setuo the format pretty easily and probably just print F the query worst case I mean its 3 data points at probabnly 1 sample per minute at worst + +Architecture planning phase + +What would each need require software wise + +Need: Connect and disconnect at will + - directory of which device manager to load + - a way to store and load settings + - a way to monitor the i2c lines for new devices + + +Config interface + At a core +Load() + - load keys, config and env + - prompt for any updates + - store said updates + - store any future requests + +functions both server and reactor will use: +- load config +- load keys + - dif keys +- load env + - dif env + +order of ops + load config + load keys and env to overwrite config + store updates + have config with methods to get/set values