Super broken but what are you gonna do

main
Keegan 2 years ago
parent b1520db055
commit 0ccac301f1

@ -1,13 +1,12 @@
package main package main
import ( import (
"fmt" "FRMS/internal/pkg/config"
"os"
"flag"
"log"
"strconv"
"FRMS/internal/pkg/reactor"
"FRMS/internal/pkg/logging" "FRMS/internal/pkg/logging"
"FRMS/internal/pkg/reactor"
flag "github.com/spf13/pflag"
"github.com/spf13/viper"
) )
type coordinator interface { type coordinator interface {
@ -19,41 +18,51 @@ func NewCoordinator(ip string,port int,ch chan error) coordinator {
return reactor.NewCoordinator(ip, port, ch) return reactor.NewCoordinator(ip, port, ch)
} }
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() { func main() {
// load any stored settings
conf := NewConfig("reactor") // loads .yaml and flags
conf.Load() // load exisiting settings
// get overrides
var ip string var ip string
var port int var port int
/*
flag.Usage = func() { flag.Usage = func() {
w := flag.CommandLine.Output() w := flag.CommandLine.Output()
fmt.Fprintf(w, "Usage: %s port \n",os.Args[0]) 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("ip", "192.168.100.2", "server ip")
//iptr := flag.String("i","192.1.168.136","ip address of laptop") portptr := flag.String("port", 2022, "server port")
nameptr := flag.String("name", "", "human readable name")
flag.Parse() 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 { // lets us retrieve them from viper later
flag.Usage()
log.Fatal("Port must be between [1023,65535]") if err := viper.BindPFlags(flag.CommandLine); err != nil {
} else if err != nil { panic(err)
log.Fatal(err)
}
ip = *iptr
port, err := strconv.Atoi(args[0])
if err != nil {
log.Fatal(err)
} }
ch := make(chan error) ch := make(chan error)
rlc := NewCoordinator(ip,port,ch) // host port rlc := NewCoordinator(ch) // passing only err chan
go rlc.Start() go rlc.Start()
logging.Debug(logging.DStart, "Reactor Started") logging.Debug(logging.DStart, "Reactor Started")
err = <-ch for err = range ch {
if err != nil { if err != nil {
log.Fatal(err) panic(err)
}
} }
} }

@ -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"`
}

@ -0,0 +1,5 @@
package config
/*
Package provides a way to update current config based on values passed in flags
*/

@ -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())
}

@ -1,26 +1,3 @@
package config package config
// pacakge serves to store/load config files for reactor // pacakge serves to provide reactor config implementation
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
}

@ -1,6 +1,6 @@
package config package config
// package serves to store/load config files for server // package serves to implement config interface for server
import ( import (
"FRMS/internal/pkg/logging" "FRMS/internal/pkg/logging"
@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"sync"
"github.com/spf13/viper" "github.com/spf13/viper"
//"os" //"os"
@ -17,28 +16,6 @@ import (
//"bytes" //"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 { type Config interface {
Store() error Store() error
} }
@ -84,6 +61,8 @@ func LoadConfig() Config {
return C return C
} }
func (c *ServerConf) Load()
func (c *ServerConf) GetURL() (string, error) { func (c *ServerConf) GetURL() (string, error) {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()

@ -3,21 +3,22 @@ package reactor
// file describes reactor level coordinator and associated implementation // file describes reactor level coordinator and associated implementation
import ( import (
"fmt"
"sync"
"time"
"math"
"FRMS/internal/pkg/system"
"FRMS/internal/pkg/I2C" "FRMS/internal/pkg/I2C"
"FRMS/internal/pkg/sensor" pb "FRMS/internal/pkg/grpc"
"FRMS/internal/pkg/logging" "FRMS/internal/pkg/logging"
"errors" "FRMS/internal/pkg/sensor"
"FRMS/internal/pkg/system"
"context" "context"
"errors"
"fmt"
"math"
"sync"
"time"
influxdb2 "github.com/influxdata/influxdb-client-go/v2"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/status"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"github.com/influxdata/influxdb-client-go/v2" "google.golang.org/grpc/status"
pb "FRMS/internal/pkg/grpc"
) )
// Coordinator == Reactor Level Coordinator // Coordinator == Reactor Level Coordinator
@ -61,6 +62,7 @@ type DeviceManagers struct {
Managers map[int]DeviceManager Managers map[int]DeviceManager
sync.Mutex sync.Mutex
} }
// basic devicemanager struct manipulations // basic devicemanager struct manipulations
type DeviceManager interface { type DeviceManager interface {
@ -83,7 +85,12 @@ func NewDeviceManager(i2c I2CDev) DeviceManager {
type I2CMonitor interface { type I2CMonitor interface {
Monitor() Monitor()
GetDevice(int) interface{ GetAddr() int; GetStatus() string; GetData() string; GetType() string} GetDevice(int) interface {
GetAddr() int
GetStatus() string
GetData() string
GetType() string
}
} }
func NewI2CMonitor(b int, ch chan int) I2CMonitor { func NewI2CMonitor(b int, ch chan int) I2CMonitor {
@ -94,15 +101,18 @@ func NewCoordinator(ip string,port int,ch chan error) *Coordinator {
sen := new(DeviceManagers) sen := new(DeviceManagers)
sen.Managers = make(map[int]DeviceManager) sen.Managers = make(map[int]DeviceManager)
c := &Coordinator{Err: ch, Devices: sen} c := &Coordinator{Err: ch, Devices: sen}
// all this stuff can come from config
c.Ip = ip c.Ip = ip
c.Port = port c.Port = port
c.hw = &hw{} c.hw = &hw{}
c.HB = time.Duration(5 * time.Second) c.HB = time.Duration(5 * time.Second)
c.PingTimer = make(chan struct{})
// this is going to be scuffed // this is going to be scuffed
url := fmt.Sprintf("http://%s:8086", ip) url := fmt.Sprintf("http://%s:8086", ip)
fmt.Println(url) fmt.Println(url)
c.DB = &DB{Bucket: "bb", Org: "ForeLight", URL: url, Token: "S1UZssBu6KPfHaQCt34pZFpyc5lzbH9XanYJWCkOI5FqLY7gq205C6FTH-CmugiPH6o2WoKlTkEuPgIfaJjAhw=="} c.DB = &DB{Bucket: "bb", Org: "ForeLight", URL: url, Token: "S1UZssBu6KPfHaQCt34pZFpyc5lzbH9XanYJWCkOI5FqLY7gq205C6FTH-CmugiPH6o2WoKlTkEuPgIfaJjAhw=="}
c.PingTimer = make(chan struct{})
return c return c
} }
@ -209,7 +219,7 @@ func (c *Coordinator) Connect(ip string, port int) (*grpc.ClientConn, error) {
return &grpc.ClientConn{}, err return &grpc.ClientConn{}, err
} }
} }
break; break
} }
return conn, nil return conn, nil
} }

65
notes

@ -937,15 +937,62 @@ Basic reactor workflow overview
2) For every device shown as active, spawn a sensor manager from the assocaited config 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 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

Loading…
Cancel
Save