/server/cmd/offen/app.go

https://github.com/offen/offen · Go · 97 lines · 84 code · 11 blank · 2 comment · 19 complexity · f03ab2c097a269889a114bace0979c91 MD5 · raw file

  1. // Copyright 2020 - Offen Authors <hioffen@posteo.de>
  2. // SPDX-License-Identifier: Apache-2.0
  3. package main
  4. import (
  5. "errors"
  6. "fmt"
  7. "time"
  8. "github.com/cenkalti/backoff/v4"
  9. "github.com/offen/offen/server/config"
  10. "github.com/sirupsen/logrus"
  11. "gorm.io/driver/mysql"
  12. "gorm.io/driver/postgres"
  13. "gorm.io/driver/sqlite"
  14. "gorm.io/gorm"
  15. "gorm.io/gorm/logger"
  16. )
  17. type app struct {
  18. logger *logrus.Logger
  19. config *config.Config
  20. }
  21. func newApp(populateMissing, quiet bool, envFileOverride string) *app {
  22. logger := logrus.New()
  23. cfg, cfgErr := config.New(populateMissing, envFileOverride)
  24. if cfgErr != nil {
  25. if errors.Is(cfgErr, config.ErrPopulatedMissing) {
  26. logger.Infof("Some configuration values were missing: %v", cfgErr.Error())
  27. } else {
  28. logger.WithError(cfgErr).Fatal("Error sourcing runtime configuration")
  29. }
  30. }
  31. logger.SetLevel(cfg.App.LogLevel.LogLevel())
  32. if !quiet && !cfg.SMTPConfigured() {
  33. logger.Warn("SMTP for transactional email is not configured right now, mail delivery will be unreliable")
  34. logger.Warn("Refer to the documentation to find out how to configure SMTP")
  35. }
  36. return &app{
  37. logger: logger,
  38. config: cfg,
  39. }
  40. }
  41. func newLogger() *logrus.Logger {
  42. return logrus.New()
  43. }
  44. func newDB(c *config.Config, l *logrus.Logger) (*gorm.DB, error) {
  45. var d gorm.Dialector
  46. switch c.Database.Dialect.String() {
  47. case "sqlite3":
  48. d = sqlite.Open(c.Database.ConnectionString.String())
  49. case "mysql":
  50. d = mysql.Open(c.Database.ConnectionString.String())
  51. case "postgres":
  52. d = postgres.Open(c.Database.ConnectionString.String())
  53. }
  54. logLevel := logger.Silent
  55. if c.App.Development {
  56. logLevel = logger.Info
  57. }
  58. var gormDB *gorm.DB
  59. if err := backoff.RetryNotify(
  60. func() error {
  61. var err error
  62. gormDB, err = gorm.Open(d, &gorm.Config{
  63. Logger: logger.Default.LogMode(logLevel),
  64. DisableForeignKeyConstraintWhenMigrating: c.Database.Dialect.String() == "sqlite3",
  65. })
  66. return err
  67. },
  68. backoff.WithMaxRetries(backoff.NewExponentialBackOff(), uint64(c.Database.ConnectionRetries)),
  69. func(err error, duration time.Duration) {
  70. if l != nil && c.Database.ConnectionRetries != 0 {
  71. l.WithError(err).Warn("Connecting to database failed")
  72. l.WithField("duration", duration).Info("Scheduling sleep before retrying")
  73. }
  74. },
  75. ); err != nil {
  76. return nil, fmt.Errorf("error opening database: %w", err)
  77. }
  78. if c.Database.Dialect == "sqlite3" {
  79. db, err := gormDB.DB()
  80. if err != nil {
  81. return nil, fmt.Errorf("error accessing underlying database: %w", err)
  82. }
  83. db.SetMaxOpenConns(1)
  84. }
  85. return gormDB, nil
  86. }