All checks were successful
Build and Package OPKG / Build for aarch64-3.10 (push) Successful in 2m5s
Build and Package OPKG / Build for armv5-3.2 (push) Successful in 53s
Build and Package OPKG / Build for armv7-2.6 (push) Successful in 55s
Build and Package OPKG / Build for armv7-3.2 (push) Successful in 53s
Build and Package OPKG / Build for mips-3.4 (push) Successful in 55s
Build and Package OPKG / Build for mipsel-3.4 (push) Successful in 55s
164 lines
3.5 KiB
Go
164 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"magitrickle"
|
|
"magitrickle/constant"
|
|
"magitrickle/models"
|
|
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
const cfgFolderLocation = "/opt/var/lib/magitrickle"
|
|
const cfgFileLocation = cfgFolderLocation + "/config.yaml"
|
|
const pidFileLocation = "/opt/var/run/magitrickle.pid"
|
|
|
|
func checkPIDFile() error {
|
|
data, err := os.ReadFile(pidFileLocation)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
pid, err := strconv.Atoi(string(data))
|
|
if err != nil {
|
|
return errors.New("invalid PID file content")
|
|
}
|
|
|
|
if err := syscall.Kill(pid, 0); err == nil {
|
|
return fmt.Errorf("process %d is already running", pid)
|
|
}
|
|
|
|
_ = os.Remove(pidFileLocation)
|
|
return nil
|
|
}
|
|
|
|
func createPIDFile() error {
|
|
pid := os.Getpid()
|
|
return os.WriteFile(pidFileLocation, []byte(strconv.Itoa(pid)), 0644)
|
|
}
|
|
|
|
func removePIDFile() {
|
|
_ = os.Remove(pidFileLocation)
|
|
}
|
|
|
|
func main() {
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
|
log.Info().
|
|
Str("version", constant.Version).
|
|
Str("commit", constant.Commit).
|
|
Msg("starting MagiTrickle daemon")
|
|
|
|
if err := checkPIDFile(); err != nil {
|
|
log.Fatal().Err(err).Msg("failed to start MagiTrickle daemon")
|
|
}
|
|
|
|
if err := createPIDFile(); err != nil {
|
|
log.Fatal().Err(err).Msg("failed to create PID file")
|
|
}
|
|
defer removePIDFile()
|
|
|
|
cfg := models.Config{}
|
|
cfgFile, err := os.ReadFile(cfgFileLocation)
|
|
if err != nil {
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
log.Fatal().Err(err).Msg("failed to read config.yaml")
|
|
}
|
|
cfg = models.Config{
|
|
ConfigVersion: "0.1.0",
|
|
App: magitrickle.DefaultAppConfig,
|
|
}
|
|
out, err := yaml.Marshal(cfg)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("failed to serialize config.yaml")
|
|
}
|
|
err = os.MkdirAll(cfgFolderLocation, os.ModePerm)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("failed to create config directory")
|
|
}
|
|
err = os.WriteFile(cfgFileLocation, out, 0600)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("failed to save config.yaml")
|
|
}
|
|
} else {
|
|
err = yaml.Unmarshal(cfgFile, &cfg)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("failed to parse config.yaml")
|
|
}
|
|
}
|
|
|
|
switch cfg.App.LogLevel {
|
|
case "trace":
|
|
zerolog.SetGlobalLevel(zerolog.TraceLevel)
|
|
case "debug":
|
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
case "info":
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
case "warn":
|
|
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
|
case "error":
|
|
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
|
case "fatal":
|
|
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
|
case "panic":
|
|
zerolog.SetGlobalLevel(zerolog.PanicLevel)
|
|
case "nolevel":
|
|
zerolog.SetGlobalLevel(zerolog.NoLevel)
|
|
case "disabled":
|
|
zerolog.SetGlobalLevel(zerolog.Disabled)
|
|
default:
|
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
}
|
|
|
|
app := magitrickle.New()
|
|
err = app.ImportConfig(cfg)
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("failed to import config")
|
|
}
|
|
|
|
log.Info().Msg("starting service")
|
|
|
|
/*
|
|
Starting app with graceful shutdown
|
|
*/
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
appResult := make(chan error)
|
|
go func() {
|
|
appResult <- app.Start(ctx)
|
|
}()
|
|
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
|
|
var once sync.Once
|
|
closeEvent := func() {
|
|
log.Info().Msg("shutting down service")
|
|
cancel()
|
|
}
|
|
|
|
for {
|
|
select {
|
|
case err, _ := <-appResult:
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("failed to start application")
|
|
}
|
|
log.Info().Msg("exiting application")
|
|
return
|
|
case <-c:
|
|
once.Do(closeEvent)
|
|
}
|
|
}
|
|
}
|