repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / apps / pgs
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}