fix: new implementation
changes: - Remove cli Some cli commands are not complete tested and are deprecated. - Daemon - Old version has a very bad implementation of how to verify, if the device or the sensors are in the database insert. The current implementation can be improved but this one is betten then the old one. - Remove complete the cache store implementation. Use a normal array and query the length and capacity to determine how the array cache must be cleaned. - Type Remove unused types and functions
This commit is contained in:
@ -1,98 +0,0 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
"github.com/volker-raschek/flucky/pkg/storage"
|
||||
"github.com/volker-raschek/flucky/pkg/storage/logfile"
|
||||
"github.com/volker-raschek/flucky/pkg/types"
|
||||
)
|
||||
|
||||
type cacheStore struct {
|
||||
compression bool
|
||||
cache []*types.MeasuredValue
|
||||
mux *sync.Mutex
|
||||
round float64
|
||||
URL *url.URL
|
||||
}
|
||||
|
||||
func (cs *cacheStore) Add(measuredValue *types.MeasuredValue) {
|
||||
cs.mux.Lock()
|
||||
defer cs.mux.Unlock()
|
||||
cs.cache = append(cs.cache, measuredValue)
|
||||
}
|
||||
|
||||
func (cs *cacheStore) Flush(measuredValue *types.MeasuredValue) *cacheStore {
|
||||
cs.mux.Lock()
|
||||
defer cs.mux.Unlock()
|
||||
cs.cache = make([]*types.MeasuredValue, 0)
|
||||
return cs
|
||||
}
|
||||
|
||||
func (cs *cacheStore) Get(id string) *types.MeasuredValue {
|
||||
cs.mux.Lock()
|
||||
defer cs.mux.Unlock()
|
||||
for _, measuredValue := range cs.cache {
|
||||
if measuredValue.ID == id {
|
||||
return measuredValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *cacheStore) Size() int {
|
||||
cs.mux.Lock()
|
||||
defer cs.mux.Unlock()
|
||||
return len(cs.cache)
|
||||
}
|
||||
|
||||
func (cs *cacheStore) WriteToEndpoint() error {
|
||||
cs.mux.Lock()
|
||||
defer cs.mux.Unlock()
|
||||
defer func() { cs.cache = make([]*types.MeasuredValue, 0) }()
|
||||
switch cs.URL.Scheme {
|
||||
case "file":
|
||||
return cs.logfile()
|
||||
case "postgres":
|
||||
return cs.postgres()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *cacheStore) logfile() error {
|
||||
|
||||
newMeasuredValues := make([]*types.MeasuredValue, 0)
|
||||
for _, measuredValue := range cs.cache {
|
||||
newMeasuredValues = append(newMeasuredValues, measuredValue)
|
||||
}
|
||||
|
||||
if cs.round != 0 {
|
||||
storage.Round(newMeasuredValues, cs.round)
|
||||
}
|
||||
|
||||
measuredLogfile := logfile.New(cs.URL.Path)
|
||||
|
||||
measuredValues, err := measuredLogfile.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
measuredValues = append(measuredValues, newMeasuredValues...)
|
||||
|
||||
if cs.compression {
|
||||
measuredValues = storage.Compression(measuredValues)
|
||||
}
|
||||
|
||||
err = measuredLogfile.Write(measuredValues)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *cacheStore) postgres() error {
|
||||
ctx := context.Background()
|
||||
return storage.Write(ctx, cs.cache, cs.URL)
|
||||
}
|
@ -2,81 +2,77 @@ package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/volker-raschek/flucky/pkg/config"
|
||||
"github.com/volker-raschek/flucky/pkg/sensor"
|
||||
"github.com/volker-raschek/flucky/pkg/storage"
|
||||
"github.com/volker-raschek/flucky/pkg/types"
|
||||
"github.com/volker-raschek/go-logger/pkg/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
flogger = logger.NewSilentLogger()
|
||||
)
|
||||
func Start(cnf *config.Config, flogger logger.Logger) error {
|
||||
|
||||
func SetLogger(logger logger.Logger) {
|
||||
flogger = logger
|
||||
}
|
||||
sensors := make([]sensor.Sensor, 0)
|
||||
for _, cnfSensor := range cnf.Sensors {
|
||||
if !cnfSensor.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
// Start the daemon
|
||||
func Start(cnf *config.Configuration, cacheSize uint, compression bool, round float64) error {
|
||||
sensor, err := sensor.New(cnfSensor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sensors = append(sensors, sensor)
|
||||
}
|
||||
|
||||
storageEndpointURL, err := cnf.GetStorageEndpointURL()
|
||||
measuredValueChannel := make(chan *types.MeasuredValue, 0)
|
||||
|
||||
// load storage endpoint
|
||||
storageEndpoint, err := storage.New(cnf.StorageEndpoint, flogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cache := &cacheStore{
|
||||
compression: compression,
|
||||
cache: make([]*types.MeasuredValue, 0),
|
||||
mux: new(sync.Mutex),
|
||||
round: round,
|
||||
URL: storageEndpointURL,
|
||||
interruptChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(interruptChannel, os.Kill, syscall.SIGTERM)
|
||||
|
||||
// Collection
|
||||
parentCtx := context.Background()
|
||||
|
||||
// Insert device if not exist
|
||||
device, _ := storageEndpoint.SelectDevice(parentCtx, cnf.Device.ID)
|
||||
if device == nil {
|
||||
if err := storageEndpoint.InsertDevice(parentCtx, cnf.Device); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Insert sensors if not exist
|
||||
for _, cnfSensor := range cnf.Sensors {
|
||||
sensor, _ := storageEndpoint.SelectSensor(parentCtx, cnfSensor.ID)
|
||||
if sensor == nil {
|
||||
if err := storageEndpoint.InsertSensor(parentCtx, cnfSensor); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Context
|
||||
parentCtx := context.Background()
|
||||
ctx, cancel := context.WithCancel(parentCtx)
|
||||
|
||||
// channels
|
||||
debugChannel := make(chan string, 0)
|
||||
infoChannel := make(chan string, 0)
|
||||
warnChannel := make(chan string, 0)
|
||||
errorChannel := make(chan error, 0)
|
||||
fatalChannel := make(chan error, 1)
|
||||
interruptChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(interruptChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
measuredValueChannel := make(chan *types.MeasuredValue, 0)
|
||||
|
||||
// Info
|
||||
flogger.Debug("Use compression: %v", compression)
|
||||
flogger.Debug("Round values to: %v", round)
|
||||
|
||||
// Init semaphoreChannel
|
||||
semaphoreChannels := make(map[string]chan struct{})
|
||||
for _, sensor := range cnf.GetSensors(config.ENABLED) {
|
||||
semaphoreChannels[sensor.GetID()] = make(chan struct{}, 1)
|
||||
}
|
||||
|
||||
// Start producers
|
||||
for _, s := range cnf.GetSensors(config.ENABLED) {
|
||||
|
||||
// start go routine for each sensor
|
||||
for _, s := range sensors {
|
||||
go func(sensor sensor.Sensor) {
|
||||
// run forever
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-semaphoreChannels[sensor.GetID()]:
|
||||
case <-sensor.GetTicker().C:
|
||||
measuredValues, err := sensor.Read()
|
||||
if err != nil {
|
||||
errorChannel <- err
|
||||
return
|
||||
flogger.Error("%v", err)
|
||||
continue
|
||||
}
|
||||
for _, measuredValue := range measuredValues {
|
||||
measuredValueChannel <- measuredValue
|
||||
@ -84,98 +80,36 @@ func Start(cnf *config.Configuration, cacheSize uint, compression bool, round fl
|
||||
}
|
||||
}
|
||||
}(s)
|
||||
|
||||
// start ticker for each sensor
|
||||
go func(sensor sensor.Sensor) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-sensor.GetTicker().C:
|
||||
semaphoreChannels[sensor.GetID()] <- struct{}{}
|
||||
}
|
||||
}
|
||||
}(s)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
debugChannel <- fmt.Sprintf("Stop consumer of measured values: Closed context: %v", ctx.Err().Error())
|
||||
return
|
||||
case measuredValue := <-measuredValueChannel:
|
||||
cache.Add(measuredValue)
|
||||
debugChannel <- fmt.Sprintf("CacheStore ID: %v, Sensor ID: %v, Type: %v, Value: %v", cache.Size(), measuredValue.SensorID, measuredValue.ValueType, measuredValue.Value)
|
||||
if cache.Size() >= int(cacheSize) {
|
||||
debugChannel <- fmt.Sprint("Write cache into storage endpoint")
|
||||
err := cache.WriteToEndpoint()
|
||||
if err != nil {
|
||||
errorChannel <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
measuredValues := make([]*types.MeasuredValue, 0, 10)
|
||||
for {
|
||||
select {
|
||||
case debug, _ := <-debugChannel:
|
||||
flogger.Debug("%v", debug)
|
||||
case info, _ := <-infoChannel:
|
||||
flogger.Info("%v", info)
|
||||
case warn, _ := <-warnChannel:
|
||||
flogger.Warn("%v", warn)
|
||||
case err, _ := <-errorChannel:
|
||||
flogger.Error("%v", err)
|
||||
case fatal, _ := <-fatalChannel:
|
||||
flogger.Fatal("Received a fatal error: %v", fatal)
|
||||
case measuredValue := <-measuredValueChannel:
|
||||
flogger.Debug("%v\t%v\t%v", measuredValue.ID, measuredValue.ValueType, measuredValue.Value)
|
||||
measuredValues = append(measuredValues, measuredValue)
|
||||
|
||||
if cap(measuredValues) == len(measuredValues) {
|
||||
flogger.Debug("Flush cache")
|
||||
err := storageEndpoint.InsertMeasuredValues(ctx, measuredValues)
|
||||
if err != nil {
|
||||
flogger.Error("%v", err)
|
||||
}
|
||||
measuredValues = make([]*types.MeasuredValue, 0, 10)
|
||||
}
|
||||
|
||||
case <-interruptChannel:
|
||||
flogger.Debug("Write %v cached values into storage endpoint", cache.Size())
|
||||
err := cache.WriteToEndpoint()
|
||||
cancel()
|
||||
close(measuredValueChannel)
|
||||
|
||||
err := storageEndpoint.InsertMeasuredValues(ctx, measuredValues)
|
||||
if err != nil {
|
||||
flogger.Error("%v", err)
|
||||
}
|
||||
flogger.Debug("Close context")
|
||||
cancel()
|
||||
flogger.Debug("Close channels")
|
||||
close(debugChannel)
|
||||
close(infoChannel)
|
||||
close(warnChannel)
|
||||
close(errorChannel)
|
||||
close(interruptChannel)
|
||||
return nil
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func checkDeviceInDatabase(ctx context.Context, device *types.Device, database db.Database) {
|
||||
// _, err := database.SelectDeviceByID(ctx, device.ID)
|
||||
// if err != nil {
|
||||
// flogger.Debug("It's seems the current device is not registered in the database. Register the device now")
|
||||
// err2 := database.InsertDevices(ctx, []*types.Device{device})
|
||||
// if err2 != nil {
|
||||
// flogger.Fatal("Can not register device into database: %v", err2)
|
||||
// }
|
||||
// flogger.Debug("Device successfully registered into the database")
|
||||
// return
|
||||
// }
|
||||
// flogger.Debug("Device already registered into the database")
|
||||
// }
|
||||
|
||||
// func checkSensorsInDatabase(ctx context.Context, sensors []*types.Sensor, database db.Database) {
|
||||
// for _, sensor := range sensors {
|
||||
// _, err := database.SelectSensorByID(ctx, sensor.ID)
|
||||
// if err != nil {
|
||||
// flogger.Debug("It's seems the sensor %v is not registered in the database. Register the sensor now", sensor.Name)
|
||||
// err2 := database.InsertSensors(ctx, []*types.Sensor{sensor})
|
||||
// if err2 != nil {
|
||||
// flogger.Fatal("Can not register sensor %v into database: %v", sensor.Name, err2)
|
||||
// }
|
||||
// flogger.Debug("Sensor %v successfully registered into the database", sensor.Name)
|
||||
// continue
|
||||
// }
|
||||
// flogger.Debug("Sensor %v is already registered into the database", sensor.Name)
|
||||
// }
|
||||
// }
|
||||
|
Reference in New Issue
Block a user