main.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. package main
  2. import (
  3. "flag"
  4. "path/filepath"
  5. "strings"
  6. log "github.com/sirupsen/logrus"
  7. "github.com/OliveTin/OliveTin/internal/auth"
  8. "github.com/OliveTin/OliveTin/internal/entities"
  9. "github.com/OliveTin/OliveTin/internal/executor"
  10. "github.com/OliveTin/OliveTin/internal/httpservers"
  11. "github.com/OliveTin/OliveTin/internal/installationinfo"
  12. "github.com/OliveTin/OliveTin/internal/oncalendarfile"
  13. "github.com/OliveTin/OliveTin/internal/oncron"
  14. "github.com/OliveTin/OliveTin/internal/onfileindir"
  15. "github.com/OliveTin/OliveTin/internal/onstartup"
  16. "github.com/OliveTin/OliveTin/internal/servicehost"
  17. updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck"
  18. "os"
  19. "strconv"
  20. config "github.com/OliveTin/OliveTin/internal/config"
  21. "github.com/knadh/koanf/parsers/yaml"
  22. "github.com/knadh/koanf/providers/env"
  23. "github.com/knadh/koanf/providers/file"
  24. "github.com/knadh/koanf/v2"
  25. )
  26. var (
  27. cfg *config.Config
  28. version = "dev"
  29. commit = "nocommit"
  30. date = "nodate"
  31. )
  32. func init() {
  33. initLog()
  34. initConfig(initCliFlags())
  35. initCheckEnvironment()
  36. initInstallationInfo()
  37. log.Info("OliveTin initialization complete")
  38. }
  39. func initLog() {
  40. logFormat := os.Getenv("OLIVETIN_LOG_FORMAT")
  41. if logFormat == "json" {
  42. log.SetFormatter(&log.JSONFormatter{})
  43. } else {
  44. log.SetFormatter(&log.TextFormatter{
  45. ForceQuote: true,
  46. DisableTimestamp: true,
  47. })
  48. }
  49. // Use debug this early on to catch details about startup errors. The
  50. // default config will raise the log level later, if not set.
  51. log.SetLevel(log.DebugLevel) // Default to debug, to catch cfg issue
  52. }
  53. func initCliFlags() string {
  54. var configDir string
  55. flag.StringVar(&configDir, "configdir", ".", "Config directory path")
  56. var printVersion bool
  57. flag.BoolVar(&printVersion, "version", false, "Prints the version number and exits")
  58. flag.Parse()
  59. // This log message should be the first log message OliveTin prints.
  60. if printVersion {
  61. logStartupMessage("OliveTin is just printing the startup message")
  62. os.Exit(1)
  63. } else {
  64. logStartupMessage("OliveTin initializing")
  65. }
  66. log.WithFields(log.Fields{
  67. "value": configDir,
  68. }).Debugf("Value of -configdir flag")
  69. return configDir
  70. }
  71. func getBasePort() int {
  72. var err error
  73. defaultPort := 1337
  74. basePort := defaultPort
  75. envPort := os.Getenv("PORT")
  76. if envPort != "" {
  77. basePort, err = strconv.Atoi(os.Getenv("PORT"))
  78. if err != nil {
  79. log.Errorf("Error converting port to int. %s", err)
  80. os.Exit(1)
  81. }
  82. }
  83. if defaultPort != basePort {
  84. log.WithFields(log.Fields{
  85. "basePort": basePort,
  86. }).Debug("Base port")
  87. }
  88. return basePort
  89. }
  90. func getConfigPath(directory string) string {
  91. joinedPath := filepath.Join(directory, "config.yaml")
  92. configPath, err := filepath.Abs(joinedPath)
  93. if err != nil {
  94. log.WithError(err).Warnf("Error getting absolute path for %s", joinedPath)
  95. return joinedPath
  96. }
  97. return configPath
  98. }
  99. func initConfig(configDir string) {
  100. k := koanf.New(".")
  101. k.Load(env.Provider(".", ".", nil), nil)
  102. directories := []string{
  103. configDir,
  104. }
  105. // Only load additional configs if not in integration test mode
  106. absConfigDir, _ := filepath.Abs(configDir)
  107. if !strings.Contains(absConfigDir, "integration-tests") {
  108. directories = append(directories,
  109. servicehost.GetConfigFilePath(),
  110. "/config", // For containers.
  111. "/etc/OliveTin/",
  112. )
  113. }
  114. var firstConfigPath string
  115. for _, directory := range directories {
  116. configPath := getConfigPath(directory)
  117. log.Debugf("Checking config path: %s", configPath)
  118. if _, err := os.Stat(configPath); err != nil {
  119. log.Debugf("Config file not found at %s: %v", configPath, err)
  120. continue
  121. }
  122. if firstConfigPath == "" {
  123. firstConfigPath = configPath
  124. }
  125. log.Infof("Loading config from %s", configPath)
  126. f := file.Provider(configPath)
  127. if err := k.Load(f, yaml.Parser()); err != nil {
  128. log.Fatalf("error loading config from %s: %v", configPath, err)
  129. os.Exit(1)
  130. }
  131. f.Watch(func(evt interface{}, err error) {
  132. log.Infof("config file changed: %v", evt)
  133. k.Load(f, yaml.Parser())
  134. config.AppendSource(cfg, k, configPath)
  135. })
  136. }
  137. cfg = config.DefaultConfigWithBasePort(getBasePort())
  138. if firstConfigPath != "" {
  139. config.AppendSourceWithIncludes(cfg, k, firstConfigPath)
  140. } else {
  141. config.AppendSource(cfg, k, "base")
  142. }
  143. }
  144. func initInstallationInfo() {
  145. installationinfo.Config = cfg
  146. installationinfo.Build.Version = version
  147. installationinfo.Build.Commit = commit
  148. installationinfo.Build.Date = date
  149. }
  150. func logStartupMessage(message string) {
  151. log.WithFields(log.Fields{
  152. "version": version,
  153. "commit": commit,
  154. "date": date,
  155. }).Info(message)
  156. }
  157. func initCheckEnvironment() {
  158. warnIfPuidGuid()
  159. }
  160. func warnIfPuidGuid() {
  161. if os.Getenv("PUID") != "" || os.Getenv("PGID") != "" {
  162. log.Warnf("PUID or PGID seem to be set to something, but they are ignored by OliveTin. Please check https://docs.olivetin.app/no-puid-pgid.html")
  163. }
  164. }
  165. func main() {
  166. servicehost.Start(cfg.ServiceHostMode)
  167. log.WithFields(log.Fields{
  168. "configDir": cfg.GetDir(),
  169. }).Infof("OliveTin started")
  170. log.Debugf("Config: %+v", cfg)
  171. executor := executor.DefaultExecutor(cfg)
  172. executor.RebuildActionMap()
  173. config.AddListener(executor.RebuildActionMap)
  174. go onstartup.Execute(cfg, executor)
  175. go oncron.Schedule(cfg, executor)
  176. go onfileindir.WatchFilesInDirectory(cfg, executor)
  177. go oncalendarfile.Schedule(cfg, executor)
  178. entities.AddListener(executor.RebuildActionMap)
  179. go entities.SetupEntityFileWatchers(cfg)
  180. go updatecheck.StartUpdateChecker(cfg)
  181. // Load persistent sessions from disk
  182. auth.LoadUserSessions(cfg)
  183. httpservers.StartServers(cfg, executor)
  184. }