phase3: HTTP server with converter, one-shot preview store, and middleware
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAddr = ":8080"
|
||||
defaultMaxMarkdownBytes = int64(1_048_576)
|
||||
defaultMaxRequestBytes = int64(1_200_000)
|
||||
defaultPreviewTTL = time.Hour
|
||||
defaultShutdownTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Addr string
|
||||
MaxMarkdownBytes int64
|
||||
MaxRequestBytes int64
|
||||
PreviewTTL time.Duration
|
||||
ShutdownTimeout time.Duration
|
||||
}
|
||||
|
||||
func LoadConfig() (Config, error) {
|
||||
maxMarkdownBytes, err := loadPositiveInt64("MAX_MARKDOWN_BYTES", defaultMaxMarkdownBytes)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
maxRequestBytes, err := loadPositiveInt64("MAX_REQUEST_BYTES", defaultMaxRequestBytes)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
previewTTL, err := loadDuration("PREVIEW_TTL", defaultPreviewTTL)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
shutdownTimeout, err := loadDuration("SHUTDOWN_TIMEOUT", defaultShutdownTimeout)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
addr := strings.TrimSpace(os.Getenv("ADDR"))
|
||||
if addr == "" {
|
||||
addr = defaultAddr
|
||||
}
|
||||
|
||||
return Config{
|
||||
Addr: addr,
|
||||
MaxMarkdownBytes: maxMarkdownBytes,
|
||||
MaxRequestBytes: maxRequestBytes,
|
||||
PreviewTTL: previewTTL,
|
||||
ShutdownTimeout: shutdownTimeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadPositiveInt64(name string, fallback int64) (int64, error) {
|
||||
raw := strings.TrimSpace(os.Getenv(name))
|
||||
if raw == "" {
|
||||
return fallback, nil
|
||||
}
|
||||
|
||||
value, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s must be an integer: %w", name, err)
|
||||
}
|
||||
if value <= 0 {
|
||||
return 0, fmt.Errorf("%s must be positive", name)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func loadDuration(name string, fallback time.Duration) (time.Duration, error) {
|
||||
raw := strings.TrimSpace(os.Getenv(name))
|
||||
if raw == "" {
|
||||
return fallback, nil
|
||||
}
|
||||
|
||||
value, err := time.ParseDuration(raw)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("%s must be a valid duration: %w", name, err)
|
||||
}
|
||||
if value <= 0 {
|
||||
return 0, fmt.Errorf("%s must be positive", name)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
Reference in New Issue
Block a user