2020-10-23 03:54:50 +13:00
|
|
|
package cmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
2021-03-17 03:24:58 +13:00
|
|
|
"strings"
|
2020-10-23 03:54:50 +13:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/rs/zerolog/diode"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
|
2022-07-14 10:58:22 +12:00
|
|
|
"github.com/demodesk/neko"
|
|
|
|
"github.com/demodesk/neko/internal/config"
|
2020-10-23 03:54:50 +13:00
|
|
|
)
|
|
|
|
|
|
|
|
func Execute() error {
|
2022-12-16 10:15:50 +13:00
|
|
|
// properly log unhandled panics
|
|
|
|
defer func() {
|
|
|
|
panicVal := recover()
|
|
|
|
if panicVal != nil {
|
|
|
|
log.Panic().Msgf("%v", panicVal)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-10-23 03:54:50 +13:00
|
|
|
return root.Execute()
|
|
|
|
}
|
|
|
|
|
|
|
|
var root = &cobra.Command{
|
|
|
|
Use: "neko",
|
|
|
|
Short: "neko streaming server",
|
|
|
|
Long: `neko streaming server`,
|
2022-01-17 08:35:57 +13:00
|
|
|
Version: neko.Version.String(),
|
2020-10-23 03:54:50 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2022-01-17 08:35:57 +13:00
|
|
|
rootConfig := config.Root{}
|
2022-01-14 12:22:23 +13:00
|
|
|
|
2020-10-23 03:54:50 +13:00
|
|
|
cobra.OnInitialize(func() {
|
|
|
|
//////
|
|
|
|
// configs
|
|
|
|
//////
|
2022-03-07 23:05:02 +13:00
|
|
|
|
2021-03-19 07:37:37 +13:00
|
|
|
config := viper.GetString("config") // Use config file from the flag.
|
|
|
|
if config == "" {
|
|
|
|
config = os.Getenv("NEKO_CONFIG") // Use config file from the environment variable.
|
|
|
|
}
|
|
|
|
|
2020-10-23 03:54:50 +13:00
|
|
|
if config != "" {
|
2021-03-19 07:37:37 +13:00
|
|
|
viper.SetConfigFile(config)
|
2020-10-23 03:54:50 +13:00
|
|
|
} else {
|
|
|
|
if runtime.GOOS == "linux" {
|
|
|
|
viper.AddConfigPath("/etc/neko/")
|
|
|
|
}
|
|
|
|
|
|
|
|
viper.AddConfigPath(".")
|
|
|
|
viper.SetConfigName("neko")
|
|
|
|
}
|
|
|
|
|
|
|
|
viper.SetEnvPrefix("NEKO")
|
2021-03-17 03:24:58 +13:00
|
|
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
2020-10-23 03:54:50 +13:00
|
|
|
viper.AutomaticEnv() // read in environment variables that match
|
|
|
|
|
2022-03-07 23:05:02 +13:00
|
|
|
// read config values
|
2021-09-27 08:29:56 +13:00
|
|
|
err := viper.ReadInConfig()
|
|
|
|
if err != nil && config != "" {
|
2022-03-07 23:05:02 +13:00
|
|
|
panic("unable to read config file: " + err.Error())
|
2020-10-23 03:54:50 +13:00
|
|
|
}
|
|
|
|
|
2021-09-27 08:29:56 +13:00
|
|
|
// get full config file path
|
|
|
|
config = viper.ConfigFileUsed()
|
|
|
|
|
2022-03-07 23:05:02 +13:00
|
|
|
// set root config values
|
|
|
|
rootConfig.Set()
|
|
|
|
|
2021-03-19 07:37:37 +13:00
|
|
|
//////
|
2022-03-07 23:05:02 +13:00
|
|
|
// logs
|
2021-03-19 07:37:37 +13:00
|
|
|
//////
|
2022-03-07 23:05:02 +13:00
|
|
|
var logWriter io.Writer
|
|
|
|
|
|
|
|
// log to a directory instead of stderr
|
|
|
|
if rootConfig.LogDir != "" {
|
|
|
|
if _, err := os.Stat(rootConfig.LogDir); os.IsNotExist(err) {
|
|
|
|
_ = os.Mkdir(rootConfig.LogDir, os.ModePerm)
|
|
|
|
}
|
|
|
|
|
|
|
|
latest := filepath.Join(rootConfig.LogDir, "neko-latest.log")
|
|
|
|
if _, err := os.Stat(latest); err == nil {
|
|
|
|
err = os.Rename(latest, filepath.Join(rootConfig.LogDir, "neko."+time.Now().Format("2006-01-02T15-04-05Z07-00")+".log"))
|
|
|
|
if err != nil {
|
|
|
|
panic("failed to rotate log file: " + err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logf, err := os.OpenFile(latest, os.O_RDWR|os.O_CREATE, 0666)
|
|
|
|
if err != nil {
|
|
|
|
panic("failed to open log file: " + err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
logWriter = diode.NewWriter(logf, 1000, 10*time.Millisecond, func(missed int) {
|
|
|
|
fmt.Printf("logger dropped %d messages", missed)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
logWriter = os.Stderr
|
|
|
|
}
|
|
|
|
|
|
|
|
// log console output instead of json
|
|
|
|
if !rootConfig.LogJson {
|
|
|
|
logWriter = zerolog.ConsoleWriter{
|
|
|
|
Out: logWriter,
|
|
|
|
NoColor: rootConfig.LogNocolor,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// save new logger output
|
|
|
|
log.Logger = log.Output(logWriter)
|
|
|
|
|
|
|
|
// set custom log level
|
|
|
|
if rootConfig.LogLevel != zerolog.NoLevel {
|
|
|
|
zerolog.SetGlobalLevel(rootConfig.LogLevel)
|
|
|
|
}
|
|
|
|
|
|
|
|
// set custom log tiem format
|
|
|
|
if rootConfig.LogTime != "" {
|
|
|
|
zerolog.TimeFieldFormat = rootConfig.LogTime
|
|
|
|
}
|
|
|
|
|
|
|
|
timeFormat := rootConfig.LogTime
|
|
|
|
if rootConfig.LogTime == zerolog.TimeFormatUnix {
|
|
|
|
timeFormat = "UNIX"
|
2021-01-18 07:10:59 +13:00
|
|
|
}
|
|
|
|
|
2020-10-23 03:54:50 +13:00
|
|
|
logger := log.With().
|
2021-09-27 08:29:56 +13:00
|
|
|
Str("config", config).
|
2022-03-07 23:05:02 +13:00
|
|
|
Str("log-level", zerolog.GlobalLevel().String()).
|
|
|
|
Bool("log-json", rootConfig.LogJson).
|
|
|
|
Str("log-time", timeFormat).
|
|
|
|
Str("log-dir", rootConfig.LogDir).
|
2020-10-23 03:54:50 +13:00
|
|
|
Logger()
|
|
|
|
|
2021-09-27 08:29:56 +13:00
|
|
|
if config == "" {
|
2020-10-23 03:54:50 +13:00
|
|
|
logger.Warn().Msg("preflight complete without config file")
|
|
|
|
} else {
|
2021-09-27 08:29:56 +13:00
|
|
|
if _, err := os.Stat(config); os.IsNotExist(err) {
|
2021-09-02 09:10:06 +12:00
|
|
|
logger.Err(err).Msg("preflight complete with nonexistent config file")
|
2021-03-19 07:47:28 +13:00
|
|
|
} else {
|
2021-09-27 08:29:56 +13:00
|
|
|
logger.Info().Msg("preflight complete with config file")
|
2021-03-19 07:47:28 +13:00
|
|
|
}
|
2020-10-23 03:54:50 +13:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-01-17 08:35:57 +13:00
|
|
|
if err := rootConfig.Init(root); err != nil {
|
|
|
|
log.Panic().Err(err).Msg("unable to run root command")
|
2020-10-23 03:54:50 +13:00
|
|
|
}
|
|
|
|
|
2022-01-17 08:35:57 +13:00
|
|
|
root.SetVersionTemplate(neko.Version.Details())
|
2020-10-23 03:54:50 +13:00
|
|
|
}
|