package app import ( "net/http" "sync" "bitmask.me/skeleton/assets" "bitmask.me/skeleton/internal/database" "bitmask.me/skeleton/internal/storage" "bitmask.me/skeleton/internal/templates" "github.com/caarlos0/env" "github.com/jmoiron/sqlx" ) // Config contains all neccessary configuration for the App type Config struct { DatabaseDSN string `env:"DATABASE_DSN"` S3Key string `env:"S3_KEY"` S3Secret string `env:"S3_SECRET"` S3Location string `env:"S3_LOCATION"` S3Endpoint string `env:"S3_ENDPOINT"` S3SSL bool `env:"S3_SSL"` S3Bucket string `env:"S3_BUCKET"` SMTPServer string `env:"SMTP_SERVER"` SMTPUser string `env:"SMTP_USER"` SMTPPassword string `env:"SMTP_PASS"` } // ConfigFromEnv loads the configuration from environment variables func ConfigFromEnv() *Config { config := &Config{} env.Parse(config) return config } // App contains the dependencies for this application. type App struct { config *Config Files http.FileSystem database *sqlx.DB // guard for lazy initialization of s3 client storageOnce sync.Once storage *storage.Client // guard for lazy template loading templatesOnce sync.Once templates templates.Templates } func (c *App) Templates() templates.Templates { c.templatesOnce.Do(func() { c.templates = templates.LoadTemplatesFS(c.Files, "/templates") }) return c.templates } func (c *App) Storage() *storage.Client { c.storageOnce.Do(func() { // ignore error since we will handle the nonfunctional client // later down the line. c.storage, _ = storage.New(&storage.Config{ Key: c.config.S3Key, Secret: c.config.S3Secret, Location: c.config.S3Location, Endpoint: c.config.S3Endpoint, SSL: c.config.S3SSL, Bucket: c.config.S3Bucket, }) }) return c.storage } func (c *App) Database() *sqlx.DB { return c.database } // NewContext creates a new App from a config func New(config *Config) *App { context := &App{ config: config, Files: assets.Assets, } initialize(context) return context } func initialize(app *App) { var err error app.database, err = database.New(app.config.DatabaseDSN) if err != nil { // Since we are not sending any data yet, any error occuring here // is likely result of a missing driver or wrong parameters. panic(err) } if err != nil { panic(err) } }