repos / pico

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

commit
47c751f
parent
c0a4aba
author
Eric Bower
date
2025-06-09 12:12:55 -0400 EDT
refactor(pgs): "lite" version of pgs with cache and proxy to ash.pgs
2 files changed,  +116, -24
A cmd/pgs/lite/main.go
+88, -0
 1@@ -0,0 +1,88 @@
 2+package main
 3+
 4+import (
 5+	"context"
 6+	"fmt"
 7+	"net"
 8+	"net/http"
 9+	"net/http/httputil"
10+	"net/url"
11+	"strings"
12+
13+	"github.com/darkweak/souin/pkg/middleware"
14+	"github.com/hashicorp/golang-lru/v2/expirable"
15+	"github.com/picosh/pico/pkg/apps/pgs"
16+	"github.com/picosh/pico/pkg/cache"
17+	"github.com/picosh/pico/pkg/shared"
18+)
19+
20+func main() {
21+	logger := shared.CreateLogger("pgs-web-lite")
22+	ctx := context.Background()
23+	cfg := pgs.NewPgsConfig(logger, nil, nil)
24+	httpCache := pgs.SetupCache(cfg)
25+	router := &pgs.WebRouter{
26+		Cfg:            cfg,
27+		RedirectsCache: expirable.NewLRU[string, []*pgs.RedirectRule](2048, nil, cache.CacheTimeout),
28+		HeadersCache:   expirable.NewLRU[string, []*pgs.HeaderRule](2048, nil, cache.CacheTimeout),
29+	}
30+	cacher := &cachedHttp{
31+		handler: httpCache,
32+		routes:  router,
33+	}
34+
35+	go router.WatchCacheClear()
36+	go router.CacheMgmt(ctx, httpCache, cfg.CacheClearingQueue)
37+
38+	portStr := fmt.Sprintf(":%s", cfg.WebPort)
39+	cfg.Logger.Info(
40+		"starting server on port",
41+		"port", cfg.WebPort,
42+		"domain", cfg.Domain,
43+	)
44+	err := http.ListenAndServe(portStr, cacher)
45+	cfg.Logger.Error("listen and serve", "err", err)
46+}
47+
48+type cachedHttp struct {
49+	handler *middleware.SouinBaseHandler
50+	routes  *pgs.WebRouter
51+}
52+
53+func (c *cachedHttp) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
54+	_ = c.handler.ServeHTTP(writer, req, func(w http.ResponseWriter, r *http.Request) error {
55+		url, _ := url.Parse(fullURL(r))
56+		c.routes.Cfg.Logger.Info("proxying request to ash.pgs.sh", "url", url.String())
57+		defaultTransport := http.DefaultTransport.(*http.Transport)
58+		newTransport := defaultTransport.Clone()
59+		oldDialContext := newTransport.DialContext
60+		newTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
61+			return oldDialContext(ctx, "tcp", "ash.pgs.sh:443")
62+		}
63+		proxy := httputil.NewSingleHostReverseProxy(url)
64+		proxy.Transport = newTransport
65+
66+		proxy.ServeHTTP(w, r)
67+		return nil
68+	})
69+}
70+
71+func fullURL(r *http.Request) string {
72+	builder := strings.Builder{}
73+	if r.TLS != nil {
74+		builder.WriteString("https://")
75+	} else {
76+		builder.WriteString("http://")
77+	}
78+	builder.WriteString(r.Host)
79+	builder.WriteString(r.URL.Path)
80+
81+	if r.URL.RawQuery != "" {
82+		builder.WriteString("?" + r.URL.RawQuery)
83+	}
84+	if r.URL.Fragment != "" {
85+		builder.WriteString("#" + r.URL.Fragment)
86+	}
87+
88+	return builder.String()
89+}
M pkg/apps/pgs/web.go
+28, -24
  1@@ -43,9 +43,7 @@ func (c *CachedHttp) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
  2 	})
  3 }
  4 
  5-func StartApiServer(cfg *PgsConfig) {
  6-	ctx := context.Background()
  7-
  8+func SetupCache(cfg *PgsConfig) *middleware.SouinBaseHandler {
  9 	ttl := configurationtypes.Duration{Duration: cfg.CacheTTL}
 10 	stale := configurationtypes.Duration{Duration: cfg.CacheTTL * 2}
 11 	c := &middleware.BaseConfiguration{
 12@@ -68,16 +66,22 @@ func StartApiServer(cfg *PgsConfig) {
 13 			DefaultCacheControl: cfg.CacheControl,
 14 		},
 15 	}
 16-	c.SetLogger(&CompatLogger{cfg.Logger})
 17+	c.SetLogger(&CompatLogger{Logger: cfg.Logger})
 18 	storages.InitFromConfiguration(c)
 19-	httpCache := middleware.NewHTTPCacheHandler(c)
 20+	return middleware.NewHTTPCacheHandler(c)
 21+}
 22+
 23+func StartApiServer(cfg *PgsConfig) {
 24+	ctx := context.Background()
 25+
 26+	httpCache := SetupCache(cfg)
 27 	routes := NewWebRouter(cfg)
 28 	cacher := &CachedHttp{
 29 		handler: httpCache,
 30 		routes:  routes,
 31 	}
 32 
 33-	go routes.cacheMgmt(ctx, httpCache, cfg.CacheClearingQueue)
 34+	go routes.CacheMgmt(ctx, httpCache, cfg.CacheClearingQueue)
 35 
 36 	portStr := fmt.Sprintf(":%s", cfg.WebPort)
 37 	cfg.Logger.Info(
 38@@ -109,11 +113,11 @@ func NewWebRouter(cfg *PgsConfig) *WebRouter {
 39 		HeadersCache:   expirable.NewLRU[string, []*HeaderRule](2048, nil, cache.CacheTimeout),
 40 	}
 41 	router.initRouters()
 42-	go router.watchCacheClear()
 43+	go router.WatchCacheClear()
 44 	return router
 45 }
 46 
 47-func (web *WebRouter) watchCacheClear() {
 48+func (web *WebRouter) WatchCacheClear() {
 49 	for key := range web.Cfg.CacheClearingQueue {
 50 		web.Cfg.Logger.Info("lru cache clear request", "key", key)
 51 		rKey := filepath.Join(key, "_redirects")
 52@@ -277,7 +281,7 @@ func (web *WebRouter) checkHandler(w http.ResponseWriter, r *http.Request) {
 53 	w.WriteHeader(http.StatusNotFound)
 54 }
 55 
 56-func (web *WebRouter) cacheMgmt(ctx context.Context, httpCache *middleware.SouinBaseHandler, notify chan string) {
 57+func (web *WebRouter) CacheMgmt(ctx context.Context, httpCache *middleware.SouinBaseHandler, notify chan string) {
 58 	storer := httpCache.Storers[0]
 59 	drain := createSubCacheDrain(ctx, web.Cfg.Logger)
 60 
 61@@ -554,7 +558,7 @@ func (web *WebRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 62 }
 63 
 64 type CompatLogger struct {
 65-	logger *slog.Logger
 66+	Logger *slog.Logger
 67 }
 68 
 69 func (cl *CompatLogger) marshall(int ...interface{}) string {
 70@@ -568,44 +572,44 @@ func (cl *CompatLogger) marshall(int ...interface{}) string {
 71 	return res
 72 }
 73 func (cl *CompatLogger) DPanic(int ...interface{}) {
 74-	cl.logger.Error("panic", "output", cl.marshall(int))
 75+	cl.Logger.Error("panic", "output", cl.marshall(int))
 76 }
 77 func (cl *CompatLogger) DPanicf(st string, int ...interface{}) {
 78-	cl.logger.Error(fmt.Sprintf(st, int...))
 79+	cl.Logger.Error(fmt.Sprintf(st, int...))
 80 }
 81 func (cl *CompatLogger) Debug(int ...interface{}) {
 82-	cl.logger.Debug("debug", "output", cl.marshall(int))
 83+	cl.Logger.Debug("debug", "output", cl.marshall(int))
 84 }
 85 func (cl *CompatLogger) Debugf(st string, int ...interface{}) {
 86-	cl.logger.Debug(fmt.Sprintf(st, int...))
 87+	cl.Logger.Debug(fmt.Sprintf(st, int...))
 88 }
 89 func (cl *CompatLogger) Error(int ...interface{}) {
 90-	cl.logger.Error("error", "output", cl.marshall(int))
 91+	cl.Logger.Error("error", "output", cl.marshall(int))
 92 }
 93 func (cl *CompatLogger) Errorf(st string, int ...interface{}) {
 94-	cl.logger.Error(fmt.Sprintf(st, int...))
 95+	cl.Logger.Error(fmt.Sprintf(st, int...))
 96 }
 97 func (cl *CompatLogger) Fatal(int ...interface{}) {
 98-	cl.logger.Error("fatal", "outpu", cl.marshall(int))
 99+	cl.Logger.Error("fatal", "outpu", cl.marshall(int))
100 }
101 func (cl *CompatLogger) Fatalf(st string, int ...interface{}) {
102-	cl.logger.Error(fmt.Sprintf(st, int...))
103+	cl.Logger.Error(fmt.Sprintf(st, int...))
104 }
105 func (cl *CompatLogger) Info(int ...interface{}) {
106-	cl.logger.Info("info", "output", cl.marshall(int))
107+	cl.Logger.Info("info", "output", cl.marshall(int))
108 }
109 func (cl *CompatLogger) Infof(st string, int ...interface{}) {
110-	cl.logger.Info(fmt.Sprintf(st, int...))
111+	cl.Logger.Info(fmt.Sprintf(st, int...))
112 }
113 func (cl *CompatLogger) Panic(int ...interface{}) {
114-	cl.logger.Error("panic", "output", cl.marshall(int))
115+	cl.Logger.Error("panic", "output", cl.marshall(int))
116 }
117 func (cl *CompatLogger) Panicf(st string, int ...interface{}) {
118-	cl.logger.Error(fmt.Sprintf(st, int...))
119+	cl.Logger.Error(fmt.Sprintf(st, int...))
120 }
121 func (cl *CompatLogger) Warn(int ...interface{}) {
122-	cl.logger.Warn("warn", "output", cl.marshall(int))
123+	cl.Logger.Warn("warn", "output", cl.marshall(int))
124 }
125 func (cl *CompatLogger) Warnf(st string, int ...interface{}) {
126-	cl.logger.Warn(fmt.Sprintf(st, int...))
127+	cl.Logger.Warn(fmt.Sprintf(st, int...))
128 }