main pico / pkg / apps / pgs / config.go
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}