1
0

config.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package server
  2. import (
  3. "errors"
  4. "fmt"
  5. "time"
  6. "github.com/imgproxy/imgproxy/v3/ensure"
  7. "github.com/imgproxy/imgproxy/v3/env"
  8. "github.com/imgproxy/imgproxy/v3/server/responsewriter"
  9. )
  10. var (
  11. IMGPROXY_PORT = env.Describe("IMGPROXY_PORT", "port")
  12. IMGPROXY_NETWORK = env.Describe("IMGPROXY_NETWORK", "tcp|tcp4|tcp6|udp|udp4|udp6|unix|unixgram|unixpacket")
  13. IMGPROXY_BIND = env.Describe("IMGPROXY_BIND", "address:port, path to unix socket, etc")
  14. IMGPROXY_PATH_PREFIX = env.Describe("IMGPROXY_PATH_PREFIX", "string")
  15. IMGPROXY_MAX_CLIENTS = env.Describe("IMGPROXY_MAX_CLIENTS", "number, 0 means unlimited")
  16. IMGPROXY_TIMEOUT = env.Describe("IMGPROXY_TIMEOUT", "seconds > 0")
  17. IMGPROXY_READ_REQUEST_TIMEOUT = env.Describe("IMGPROXY_READ_REQUEST_TIMEOUT", "seconds > 0")
  18. IMGPROXY_KEEP_ALIVE_TIMEOUT = env.Describe("IMGPROXY_KEEP_ALIVE_TIMEOUT", "seconds >= 0")
  19. IMGPROXY_GRACEFUL_STOP_TIMEOUT = env.Describe("IMGPROXY_GRACEFUL_STOP_TIMEOUT", "seconds >= 0")
  20. IMGPROXY_ALLOW_ORIGIN = env.Describe("IMGPROXY_ALLOW_ORIGIN", "string")
  21. IMGPROXY_SECRET = env.Describe("IMGPROXY_SECRET", "string")
  22. IMGPROXY_DEVELOPMENT_ERRORS_MODE = env.Describe("IMGPROXY_DEVELOPMENT_ERRORS_MODE", "boolean")
  23. IMGPROXY_SO_REUSEPORT = env.Describe("IMGPROXY_SO_REUSEPORT", "boolean")
  24. IMGPROXY_HEALTH_CHECK_PATH = env.Describe("IMGPROXY_HEALTH_CHECK_PATH", "string")
  25. IMGPROXY_FREE_MEMORY_INTERVAL = env.Describe("IMGPROXY_FREE_MEMORY_INTERVAL", "seconds >= 0")
  26. IMGPROXY_LOG_MEM_STATS = env.Describe("IMGPROXY_LOG_MEM_STATS", "boolean")
  27. )
  28. // Config represents HTTP server config
  29. type Config struct {
  30. Network string // Network type (tcp, unix)
  31. Bind string // Bind address
  32. PathPrefix string // Path prefix for the server
  33. MaxClients int // Maximum number of concurrent clients
  34. RequestTimeout time.Duration // Timeout for requests
  35. ReadRequestTimeout time.Duration // Timeout for reading requests
  36. KeepAliveTimeout time.Duration // Timeout for keep-alive connections
  37. GracefulStopTimeout time.Duration // Timeout for graceful shutdown
  38. CORSAllowOrigin string // CORS allowed origin
  39. Secret string // Secret for authorization
  40. DevelopmentErrorsMode bool // Enable development mode for detailed error messages
  41. SocketReusePort bool // Enable SO_REUSEPORT socket option
  42. HealthCheckPath string // Health check path from config
  43. ResponseWriter responsewriter.Config // Response writer config
  44. // TODO: We are not sure where to put it yet
  45. FreeMemoryInterval time.Duration // Interval for freeing memory
  46. LogMemStats bool // Log memory stats
  47. }
  48. // NewDefaultConfig returns default config values
  49. func NewDefaultConfig() Config {
  50. return Config{
  51. Network: "tcp",
  52. Bind: ":8080",
  53. PathPrefix: "",
  54. MaxClients: 2048,
  55. RequestTimeout: 10 * time.Second,
  56. ReadRequestTimeout: 10 * time.Second,
  57. KeepAliveTimeout: 10 * time.Second,
  58. GracefulStopTimeout: 20 * time.Second,
  59. CORSAllowOrigin: "",
  60. Secret: "",
  61. DevelopmentErrorsMode: false,
  62. SocketReusePort: false,
  63. HealthCheckPath: "",
  64. FreeMemoryInterval: 10 * time.Second,
  65. LogMemStats: false,
  66. ResponseWriter: responsewriter.NewDefaultConfig(),
  67. }
  68. }
  69. // LoadConfigFromEnv overrides current values with environment variables
  70. func LoadConfigFromEnv(c *Config) (*Config, error) {
  71. c = ensure.Ensure(c, NewDefaultConfig)
  72. var port string
  73. if err := env.String(&port, IMGPROXY_PORT); err != nil {
  74. return nil, err
  75. }
  76. if len(port) > 0 {
  77. c.Bind = fmt.Sprintf(":%s", port)
  78. }
  79. _, rwErr := responsewriter.LoadConfigFromEnv(&c.ResponseWriter)
  80. err := errors.Join(
  81. rwErr,
  82. env.String(&c.Network, IMGPROXY_NETWORK),
  83. env.String(&c.Bind, IMGPROXY_BIND),
  84. env.URLPath(&c.PathPrefix, IMGPROXY_PATH_PREFIX),
  85. env.Int(&c.MaxClients, IMGPROXY_MAX_CLIENTS),
  86. env.Duration(&c.RequestTimeout, IMGPROXY_TIMEOUT),
  87. env.Duration(&c.ReadRequestTimeout, IMGPROXY_READ_REQUEST_TIMEOUT),
  88. env.Duration(&c.KeepAliveTimeout, IMGPROXY_KEEP_ALIVE_TIMEOUT),
  89. env.Duration(&c.GracefulStopTimeout, IMGPROXY_GRACEFUL_STOP_TIMEOUT),
  90. env.String(&c.CORSAllowOrigin, IMGPROXY_ALLOW_ORIGIN),
  91. env.String(&c.Secret, IMGPROXY_SECRET),
  92. env.Bool(&c.DevelopmentErrorsMode, IMGPROXY_DEVELOPMENT_ERRORS_MODE),
  93. env.Bool(&c.SocketReusePort, IMGPROXY_SO_REUSEPORT),
  94. env.URLPath(&c.HealthCheckPath, IMGPROXY_HEALTH_CHECK_PATH),
  95. env.Duration(&c.FreeMemoryInterval, IMGPROXY_FREE_MEMORY_INTERVAL),
  96. env.Bool(&c.LogMemStats, IMGPROXY_LOG_MEM_STATS),
  97. )
  98. return c, err
  99. }
  100. // Validate checks that the config values are valid
  101. func (c *Config) Validate() error {
  102. if len(c.Bind) == 0 {
  103. return IMGPROXY_BIND.ErrorEmpty()
  104. }
  105. if c.MaxClients < 0 {
  106. return IMGPROXY_MAX_CLIENTS.ErrorNegative()
  107. }
  108. if c.RequestTimeout <= 0 {
  109. return IMGPROXY_TIMEOUT.ErrorZeroOrNegative()
  110. }
  111. if c.ReadRequestTimeout <= 0 {
  112. return IMGPROXY_READ_REQUEST_TIMEOUT.ErrorZeroOrNegative()
  113. }
  114. if c.KeepAliveTimeout < 0 {
  115. return IMGPROXY_KEEP_ALIVE_TIMEOUT.ErrorNegative()
  116. }
  117. if c.GracefulStopTimeout < 0 {
  118. return IMGPROXY_GRACEFUL_STOP_TIMEOUT.ErrorNegative()
  119. }
  120. if c.FreeMemoryInterval <= 0 {
  121. return IMGPROXY_FREE_MEMORY_INTERVAL.ErrorZeroOrNegative()
  122. }
  123. return nil
  124. }