package app
import (
"flag"
"fmt"
"html/template"
"io/fs"
"log/slog"
"os"
"strconv"
"time"
"go.etcd.io/bbolt"
)
const (
DefaultHost = "0.0.0.0"
DefaultPort = 8080
DefaultStorage = "./storage"
DefaultMaxMB = 512
ServerTimeout = 10 * time.Minute
ShutdownTimeout = 10 * time.Second
UploadChunkSize = 8 << 20
MaxRequestOverhead = 10 << 20
PermUserRWX = 0o700
MegaByte = 1 << 20
ChunkSafetyMargin = 2
SlugLength = 22
KeyLength = 16
CleanupInterval = 1 * time.Hour
TempExpiry = 4 * time.Hour
MinRetention = 24 * time.Hour
MaxRetention = 365 * 24 * time.Hour
DBFileName = "safebin.db"
DBBucketName = "files"
DBBucketIndexName = "expiry_index"
TempDirName = "tmp"
)
type Config struct {
Addr string
StorageDir string
MaxMB int64
}
type App struct {
Conf Config
Tmpl *template.Template
Logger *slog.Logger
DB *bbolt.DB
Assets fs.FS
}
func LoadConfig() Config {
hostEnv := getEnv("SAFEBIN_HOST", DefaultHost)
portEnv := getEnvInt("SAFEBIN_PORT", DefaultPort)
storageEnv := getEnv("SAFEBIN_STORAGE", DefaultStorage)
maxMBEnv := int64(getEnvInt("SAFEBIN_MAX_MB", DefaultMaxMB))
var host string
var port int
var storage string
var maxMB int64
flag.StringVar(&host, "h", hostEnv, "Bind address")
flag.IntVar(&port, "p", portEnv, "Port")
flag.StringVar(&storage, "s", storageEnv, "Storage directory")
flag.Int64Var(&maxMB, "m", maxMBEnv, "Max file size in MB")
flag.Parse()
return Config{
Addr: fmt.Sprintf("%s:%d", host, port),
StorageDir: storage,
MaxMB: maxMB,
}
}
func getEnv(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return fallback
}
func getEnvInt(key string, fallback int) int {
if value, ok := os.LookupEnv(key); ok {
i, err := strconv.Atoi(value)
if err == nil {
return i
}
}
return fallback
}
func ParseTemplates(fsys fs.FS) *template.Template {
return template.Must(template.ParseFS(fsys, "*.html"))
}