package daemon import ( "context" "os" "os/signal" "syscall" "time" "github.com/Masterminds/semver" "github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/sensor" "github.com/go-flucky/flucky/pkg/storage" "github.com/go-flucky/flucky/pkg/storage/db" "github.com/go-flucky/flucky/pkg/storage/logfile" "github.com/go-flucky/flucky/pkg/types" "github.com/volker-raschek/go-logger/pkg/logger" ) var ( postgresHost = "markus-pc.trier.cryptic.systems" postgresPort = "5432" postgresDatabase = "postgres" postgresUser = "postgres" postgresPassword = "postgres" flogger logger.Logger ) func init() { flogger = logger.NewSilentLogger() } func SetLogger(logger logger.Logger) { flogger = logger } // Start the daemon func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, version *semver.Version) { // Info flogger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String()) flogger.Info("Use compression: %v", compression) flogger.Info("Round: %v", round) ticker := time.Tick(cleanCacheInterval) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) errorChannel := make(chan error, 0) measuredValuesChannel := make(chan []*types.MeasuredValue, 0) ctx := context.Background() childContext, cancel := context.WithCancel(ctx) measuredValuesLogfile := logfile.New(cnf.Logfile) measuredValuesCache := make([]*types.MeasuredValue, 0) var postgres db.Database if cnf.DatabaseSettings != nil { p, err := db.New(cnf.DatabaseSettings) if err != nil { flogger.Error("%v", err) } if err := p.Schema(ctx, version); err != nil { flogger.Error("%v", err) } postgres = p checkDeviceInDatabase(ctx, cnf.Device, postgres) checkSensorsInDatabase(ctx, cnf.Sensors, postgres) defer postgres.Close() } rgbLEDs := cnf.GetRGBLEDs(config.ENABLED) go sensor.ReadContinuously(childContext, cnf.GetSensors(config.ENABLED), measuredValuesChannel, errorChannel) for { err := rgbled.Run(rgbLEDs) if err != nil { flogger.Error("Can not turn on green info light: %v", err) } select { case err, _ := <-errorChannel: flogger.Error("%v", err) err = rgbled.Error(rgbLEDs) if err != nil { flogger.Error("Can not turn on red info light: %v", err) } time.Sleep(time.Second * 2) case <-ticker: err := rgbled.Logfile(rgbLEDs) if err != nil { flogger.Error("Can not turn on blue info light: %v", err) } if round != 0 { storage.Round(measuredValuesCache, round) } if compression { measuredValuesCache = storage.Compression(measuredValuesCache) } if err := logfile.Append(measuredValuesLogfile, measuredValuesCache); err != nil { err2 := rgbled.Error(rgbLEDs) if err2 != nil { flogger.Error("Can not turn on red info light: %v", err2) } flogger.Error("Can not save caches measured values in logfile: %v", err) } if postgres != nil { if err := postgres.InsertMeasuredValues(ctx, measuredValuesCache); err != nil { err2 := rgbled.Error(rgbLEDs) if err2 != nil { flogger.Error("Can not turn on red info light: %v", err) } flogger.Error("Can not save cached measured values in database: %v", err) } } measuredValuesCache = make([]*types.MeasuredValue, 0) case measuredValues, _ := <-measuredValuesChannel: measuredValuesCache = append(measuredValuesCache, measuredValues...) case killSignal := <-interrupt: flogger.Warn("Daemon was interruped by system signal %v\n", killSignal) cancel() err := rgbled.Error(rgbLEDs) if err != nil { flogger.Error("Can not turn on red info light: %v", err) } flogger.Warn("Save remaining data from the cache") err = logfile.Append(measuredValuesLogfile, measuredValuesCache) if err != nil { flogger.Fatal("%v", err) } return } } } func checkDeviceInDatabase(ctx context.Context, device *types.Device, database db.Database) { _, err := database.SelectDeviceByID(ctx, device.DeviceID) 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.SensorID) if err != nil { flogger.Debug("It's seems the sensor %v is not registered in the database. Register the sensor now", sensor.SensorName) err2 := database.InsertSensors(ctx, []*types.Sensor{sensor}) if err2 != nil { flogger.Fatal("Can not register sensor %v into database: %v", sensor.SensorName, err2) } flogger.Debug("Sensor %v successfully registered into the database", sensor.SensorName) continue } flogger.Debug("Sensor %v is already registered into the database", sensor.SensorName) } }