Eric Bower
·
2025-07-04
web_cache.go
1package pgs
2
3import (
4 "context"
5 "fmt"
6 "io"
7 "log/slog"
8 "time"
9
10 "github.com/picosh/pico/pkg/shared"
11 "github.com/picosh/utils/pipe"
12)
13
14type PicoPubsub interface {
15 io.Reader
16 io.Writer
17 io.Closer
18}
19
20type PubsubPipe struct {
21 Pipe *pipe.ReconnectReadWriteCloser
22}
23
24func (p *PubsubPipe) Read(b []byte) (int, error) {
25 return p.Pipe.Read(b)
26}
27
28func (p *PubsubPipe) Write(b []byte) (int, error) {
29 return p.Pipe.Write(b)
30}
31
32func (p *PubsubPipe) Close() error {
33 return p.Pipe.Close()
34}
35
36func NewPubsubPipe(pipe *pipe.ReconnectReadWriteCloser) *PubsubPipe {
37 return &PubsubPipe{
38 Pipe: pipe,
39 }
40}
41
42type PubsubChan struct {
43 Chan chan []byte
44}
45
46func (p *PubsubChan) Read(b []byte) (int, error) {
47 n := copy(b, <-p.Chan)
48 return n, nil
49}
50
51func (p *PubsubChan) Write(b []byte) (int, error) {
52 p.Chan <- b
53 return len(b), nil
54}
55
56func (p *PubsubChan) Close() error {
57 close(p.Chan)
58 return nil
59}
60
61func NewPubsubChan() *PubsubChan {
62 return &PubsubChan{
63 Chan: make(chan []byte),
64 }
65}
66
67func getSurrogateKey(userName, projectName string) string {
68 return fmt.Sprintf("%s-%s", userName, projectName)
69}
70
71func CreatePubCacheDrain(ctx context.Context, logger *slog.Logger) *pipe.ReconnectReadWriteCloser {
72 info := shared.NewPicoPipeClient()
73 send := pipe.NewReconnectReadWriteCloser(
74 ctx,
75 logger,
76 info,
77 "pub to cache-drain",
78 "pub cache-drain -b=false",
79 100,
80 -1,
81 )
82 return send
83}
84
85func CreateSubCacheDrain(ctx context.Context, logger *slog.Logger) *pipe.ReconnectReadWriteCloser {
86 info := shared.NewPicoPipeClient()
87 send := pipe.NewReconnectReadWriteCloser(
88 ctx,
89 logger,
90 info,
91 "sub to cache-drain",
92 "sub cache-drain -k",
93 100,
94 -1,
95 )
96 return send
97}
98
99// purgeCache send a pipe pub to the pgs web instance which purges
100// cached entries for a given subdomain (like "fakeuser-www-proj"). We set a
101// "surrogate-key: <subdomain>" header on every pgs response which ensures all
102// cached assets for a given subdomain are grouped under a single key (which is
103// separate from the "GET-https-example.com-/path" key used for serving files
104// from the cache).
105func purgeCache(cfg *PgsConfig, writer io.Writer, surrogate string) error {
106 cfg.Logger.Info("purging cache", "surrogate", surrogate)
107 time.Sleep(1 * time.Second)
108 _, err := writer.Write([]byte(surrogate + "\n"))
109 return err
110}
111
112func purgeAllCache(cfg *PgsConfig, writer io.Writer) error {
113 return purgeCache(cfg, writer, "*")
114}