Antonio Mika
·
2026-10-10
1package pgs
2
3import (
4 "fmt"
5 "html/template"
6 "log/slog"
7 "path/filepath"
8 "strconv"
9 "time"
10
11 pgsdb "github.com/picosh/pico/pkg/apps/pgs/db"
12 "github.com/picosh/pico/pkg/shared"
13 "github.com/picosh/pico/pkg/shared/router"
14 "github.com/picosh/pico/pkg/storage"
15)
16
17type Config struct {
18 CacheTTL time.Duration
19 CacheMaxItems int
20 CacheMaxBodySize int64
21 Domain string
22 MaxAssetSize int64
23 MaxSize uint64
24 MaxSpecialFileSize int64
25 SshHost string
26 SshPort string
27 WebPort string
28 WebProtocol string
29 TxtPrefix string
30
31 // This channel will receive the surrogate key for a project (e.g. static site)
32 // which will inform the caching layer to clear the cache for that site.
33 CacheClearingQueue chan string
34 // Database layer; it's just an interface that could be implemented
35 // with anything.
36 DB pgsdb.PgsDB
37 Logger *slog.Logger
38 // Where we store the static assets uploaded to our service.
39 Storage storage.StorageServe
40 Pubsub PicoPubsub
41}
42
43func (c *Config) AssetURL(username, projectName, fpath string) string {
44 if username == projectName {
45 return fmt.Sprintf(
46 "%s://%s.%s/%s",
47 c.WebProtocol,
48 username,
49 c.Domain,
50 fpath,
51 )
52 }
53
54 return fmt.Sprintf(
55 "%s://%s-%s.%s/%s",
56 c.WebProtocol,
57 username,
58 projectName,
59 c.Domain,
60 fpath,
61 )
62}
63
64// staticDir holds pgs's templates and public files.
65const staticDir = "pkg/apps/pgs"
66
67func (c *Config) StaticPath(fname string) string {
68 return filepath.Join(staticDir, fname)
69}
70
71func (c *Config) Static() router.Static {
72 return router.Static{
73 Dir: staticDir,
74 Logger: c.Logger,
75 Site: shared.SitePageData{Domain: template.URL(c.Domain), HomeURL: "/"},
76 }
77}
78
79var maxSize = uint64(50 * shared.MB)
80var maxAssetSize = int64(10 * shared.MB)
81
82// Larger responses stream from storage instead of being held in the cache.
83// Zero means no limit.
84var cacheMaxBodySize = int64(0)
85
86// Needs to be small for caching files like _headers and _redirects.
87var maxSpecialFileSize = int64(5 * shared.KB)
88
89func NewConfig(logger *slog.Logger, dbpool pgsdb.PgsDB, st storage.StorageServe, pubsub PicoPubsub) *Config {
90 domain := shared.GetEnv("PGS_DOMAIN", "pgs.sh")
91 port := shared.GetEnv("PGS_WEB_PORT", "3000")
92 protocol := shared.GetEnv("PGS_PROTOCOL", "https")
93 cacheTTL, err := time.ParseDuration(shared.GetEnv("PGS_CACHE_TTL", ""))
94 if err != nil {
95 cacheTTL = 600 * time.Second
96 }
97 cacheMaxItemsStr := shared.GetEnv("PGS_CACHE_MAX_ITEMS", "")
98 cacheMaxItems := 0
99 if cacheMaxItemsStr != "" {
100 cacheMaxItems, _ = strconv.Atoi(cacheMaxItemsStr)
101 }
102 cacheMaxBody, err := strconv.ParseInt(shared.GetEnv("PGS_CACHE_MAX_BODY_SIZE", ""), 10, 64)
103 if err != nil {
104 cacheMaxBody = cacheMaxBodySize
105 }
106
107 sshHost := shared.GetEnv("PGS_SSH_HOST", "0.0.0.0")
108 sshPort := shared.GetEnv("PGS_SSH_PORT", "2222")
109
110 cfg := Config{
111 CacheTTL: cacheTTL,
112 CacheMaxItems: cacheMaxItems,
113 CacheMaxBodySize: cacheMaxBody,
114 Domain: domain,
115 MaxAssetSize: maxAssetSize,
116 MaxSize: maxSize,
117 MaxSpecialFileSize: maxSpecialFileSize,
118 SshHost: sshHost,
119 SshPort: sshPort,
120 TxtPrefix: "pgs",
121 WebPort: port,
122 WebProtocol: protocol,
123
124 CacheClearingQueue: make(chan string, 100),
125 DB: dbpool,
126 Logger: logger,
127 Storage: st,
128 Pubsub: pubsub,
129 }
130
131 return &cfg
132}