apps/blobs/cmd_server.go 2.7 K raw
1
package main
2
3
import (
4
	"fmt"
5
	"log"
6
	"log/slog"
7
	"net/http"
8
	"os"
9
	"strconv"
10
	"time"
11
12
	"github.com/stevedylandev/andromeda/pkg/auth"
13
	"github.com/stevedylandev/andromeda/pkg/config"
14
)
15
16
func runServer(args []string) {
17
	config.LoadDotEnv(".env")
18
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
19
20
	host := config.Getenv("HOST", "127.0.0.1")
21
	port := config.GetenvInt("PORT", 3000)
22
	for i := 0; i < len(args); i++ {
23
		switch args[i] {
24
		case "--host":
25
			if i+1 < len(args) {
26
				host = args[i+1]
27
				i++
28
			}
29
		case "--port", "-p":
30
			if i+1 < len(args) {
31
				if n, err := strconv.Atoi(args[i+1]); err == nil {
32
					port = n
33
				}
34
				i++
35
			}
36
		}
37
	}
38
39
	dbPath := config.Getenv("BLOBS_DB_PATH", "blobs.sqlite")
40
	db, err := openDB(dbPath)
41
	if err != nil {
42
		log.Fatal(err)
43
	}
44
	defer db.Close()
45
46
	sessions := &auth.Store{
47
		DB:           db,
48
		CookieName:   "blobs_session",
49
		CookieSecure: config.GetenvBool("BLOBS_COOKIE_SECURE", false),
50
	}
51
	if err := sessions.EnsureSchema(); err != nil {
52
		log.Fatal(err)
53
	}
54
	sessions.PruneExpired()
55
	go func() {
56
		ticker := time.NewTicker(time.Hour)
57
		defer ticker.Stop()
58
		for range ticker.C {
59
			sessions.PruneExpired()
60
		}
61
	}()
62
63
	password := os.Getenv("BLOBS_PASSWORD")
64
	if password == "" {
65
		logger.Warn("BLOBS_PASSWORD not set, using default 'changeme'")
66
		password = "changeme"
67
	}
68
69
	endpoint := config.Getenv("S3_ENDPOINT", "")
70
	if endpoint == "" {
71
		if accountID := config.Getenv("R2_ACCOUNT_ID", ""); accountID != "" {
72
			endpoint = "https://" + accountID + ".r2.cloudflarestorage.com"
73
		}
74
	}
75
	accessKey := config.Getenv("S3_ACCESS_KEY_ID", config.Getenv("R2_ACCESS_KEY_ID", ""))
76
	secretKey := config.Getenv("S3_SECRET_ACCESS_KEY", config.Getenv("R2_SECRET_ACCESS_KEY", ""))
77
	region := config.Getenv("S3_REGION", "auto")
78
	publicURLs := parsePublicURLs(os.Getenv("BLOBS_PUBLIC_URLS"))
79
	presignTTL := time.Duration(config.GetenvInt("BLOBS_PRESIGN_TTL_SECONDS", 3600)) * time.Second
80
81
	client, err := NewS3Client(endpoint, region, accessKey, secretKey, publicURLs, presignTTL)
82
	if err != nil {
83
		log.Fatalf("configure S3: %v", err)
84
	}
85
	logger.Info("S3 client ready", "endpoint", endpoint, "region", region, "public_buckets", len(publicURLs))
86
87
	tmpl, err := buildTemplates()
88
	if err != nil {
89
		log.Fatal(err)
90
	}
91
92
	maxUploadMB := int64(config.GetenvInt("BLOBS_MAX_UPLOAD_MB", 100))
93
	app := &App{
94
		DB:             db,
95
		Log:            logger,
96
		Templates:      tmpl,
97
		Sessions:       sessions,
98
		S3:             client,
99
		Password:       password,
100
		CookieSecure:   sessions.CookieSecure,
101
		MaxUploadBytes: maxUploadMB << 20,
102
	}
103
104
	addr := fmt.Sprintf("%s:%d", host, port)
105
	logger.Info("blobs server running", "addr", addr)
106
	if err := http.ListenAndServe(addr, app.routes()); err != nil {
107
		log.Fatal(err)
108
	}
109
}