Files
go-omni/examples/userService/internal/settings/config.go

113 lines
3.9 KiB
Go

// Package settings owns this project's configuration; it adds no business identity model.
package settings
import (
"errors"
"git.yuntuo.hk/k2safe/go-omni/config"
"git.yuntuo.hk/k2safe/go-omni/database"
"git.yuntuo.hk/k2safe/go-omni/logx"
"git.yuntuo.hk/k2safe/go-omni/storage"
"net/url"
"strings"
"time"
)
type Config struct {
Server config.Config `json:"server"`
Database database.Config `json:"database"`
Storage StorageConfig `json:"storage"`
}
func Default() Config {
server := config.Default()
server.Address = "127.0.0.1:8080"
server.EnableLogger = true
server.SlowRequestThreshold = 500 * time.Millisecond
server.Log.Service = "example.com/userService"
server.Log.Format = "json"
server.Log.File = "./var/log/server.log"
server.Log.Rotation = logx.RotationConfig{Enabled: true, MaxSizeMB: 100, MaxBackups: 10, MaxAgeDays: 7, Compress: true}
return Config{Server: server, Database: database.DefaultConfig(), Storage: StorageConfig{
Provider: "local", Root: "./var/files", PublicURL: "http://127.0.0.1:8080/storage/object",
Secure: true, MaxBytes: 32 << 20, ContentTypes: []string{"text/plain", "image/png", "image/jpeg", "application/pdf"},
LinkTTL: 5 * time.Minute, RequestTimeout: 30 * time.Second,
}}
}
func Load(path string) (Config, error) { return config.LoadProject(path, Default()) }
func (c Config) Validate() error {
if err := c.Database.Validate(); err != nil {
return err
}
if c.Database.Driver != "mysql" || c.Database.MaxOpenConns < 1 {
return errors.New("database requires driver mysql and a positive maxOpenConns")
}
if err := c.Server.Validate(); err != nil {
return err
}
if c.Server.Log.Format != "json" && c.Server.Log.Format != "text" {
return errors.New("log.format must be json or text")
}
switch strings.ToLower(c.Server.Log.Level) {
case "debug", "info", "warn", "warning", "error":
default:
return errors.New("invalid log.level")
}
return c.Storage.Validate()
}
type StorageConfig struct {
Provider string `json:"provider"`
Root string `json:"root"`
PublicURL string `json:"publicUrl"`
Endpoint string `json:"endpoint"`
Region string `json:"region"`
Bucket string `json:"bucket"`
AccountID string `json:"accountId"`
Secure bool `json:"secure"`
MaxBytes int64 `json:"maxBytes"`
ContentTypes []string `json:"contentTypes"`
LinkTTL time.Duration `json:"linkTtl"`
RequestTimeout time.Duration `json:"requestTimeout"`
// The file explicitly selects secret environment references.
FilesToken string `json:"filesToken"`
SigningKey string `json:"signingKey"`
AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"`
SessionToken string `json:"sessionToken"`
}
func (s StorageConfig) Policy() storage.UploadPolicy {
return storage.UploadPolicy{MaxBytes: s.MaxBytes, ContentTypes: s.ContentTypes}
}
func (s StorageConfig) Validate() error {
if s.Provider != "local" {
return errors.New("storage.provider must match the adapter selected at generation")
}
if err := s.Policy().Validate(); err != nil {
return err
}
if s.LinkTTL < time.Second || s.LinkTTL > time.Hour {
return errors.New("storage.linkTtl must be 1s..1h")
}
if s.RequestTimeout <= 0 || s.RequestTimeout > 5*time.Minute {
return errors.New("storage.requestTimeout must be >0 and <=5m")
}
if s.Root == "" {
return errors.New("storage.root is required")
}
u, err := url.Parse(s.PublicURL)
if err != nil || u.Host == "" || u.Hostname() == "" || (u.Scheme != "http" && u.Scheme != "https") || u.User != nil || u.RawQuery != "" || u.Fragment != "" || u.Path != "/storage/object" {
return errors.New("storage.publicUrl must be an absolute HTTP(S) URL ending in /storage/object")
}
if len(s.SigningKey) < 32 {
return errors.New("storage.signingKey requires a stable secret of at least 32 bytes")
}
return nil
}