Build the image pipeline in pixad's fx graph (closes #313)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
internal/app now provides the cache, the fetcher, the processor, the image service, the session manager and the encrypted URL generator, and handlers.New receives them built. database.New opens the database, so these parts can read it while fx builds them; the cache's stop hook still runs before the database's. Each setting's default is declared in internal/config, the default cache_max_bytes included, which internal/app works out before it builds the cache. The cache's MaxBytes is the one value for the disk cache limit, and 0 turns the disk cache off. The fetcher and the processor take explicit values. The server tests build the pipeline themselves, as they cannot import internal/app. Model: opus-5-5
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/netip"
|
||||
@@ -17,11 +19,16 @@ import (
|
||||
|
||||
"sneak.berlin/go/pixa/internal/config"
|
||||
"sneak.berlin/go/pixa/internal/database"
|
||||
"sneak.berlin/go/pixa/internal/encurl"
|
||||
"sneak.berlin/go/pixa/internal/globals"
|
||||
"sneak.berlin/go/pixa/internal/handlers"
|
||||
"sneak.berlin/go/pixa/internal/healthcheck"
|
||||
"sneak.berlin/go/pixa/internal/httpfetcher"
|
||||
"sneak.berlin/go/pixa/internal/imageprocessor"
|
||||
"sneak.berlin/go/pixa/internal/imgcache"
|
||||
"sneak.berlin/go/pixa/internal/logger"
|
||||
"sneak.berlin/go/pixa/internal/middleware"
|
||||
"sneak.berlin/go/pixa/internal/session"
|
||||
)
|
||||
|
||||
// testSigningKey is a throwaway signing key; submitting it logs in.
|
||||
@@ -80,9 +87,14 @@ func newTestServer(t *testing.T) *Server {
|
||||
t.Fatalf("healthcheck.New() error = %v", err)
|
||||
}
|
||||
|
||||
svc, sessMgr, encGen, err := newImagePipeline(cfg, db, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("newImagePipeline() error = %v", err)
|
||||
}
|
||||
|
||||
h, err := handlers.New(lc, handlers.Params{
|
||||
Logger: log, Healthcheck: hc, Database: db, Config: cfg,
|
||||
MetricsRegistry: prometheus.NewRegistry(),
|
||||
Logger: log, Healthcheck: hc, Config: cfg,
|
||||
ImageService: svc, SessionManager: sessMgr, EncryptedURLGenerator: encGen,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("handlers.New() error = %v", err)
|
||||
@@ -102,6 +114,66 @@ func newTestServer(t *testing.T) *Server {
|
||||
return s
|
||||
}
|
||||
|
||||
// newImagePipeline builds from cfg and db the parts handlers.New takes
|
||||
// that pixad's fx app builds with the providers of internal/app: the image
|
||||
// service, the session manager and the encrypted URL generator. These
|
||||
// tests cannot import internal/app, as it imports this package. The
|
||||
// upstream fetcher connects with dialContext when that is not nil, as
|
||||
// httpfetcher.Config says. The disk cache has the limit cache_max_bytes
|
||||
// sets, and is off when it is omitted, so that no test sizes it from the
|
||||
// host's free disk space. The cache's background goroutines do not run.
|
||||
func newImagePipeline(
|
||||
cfg *config.Config,
|
||||
db *database.Database,
|
||||
dialContext func(ctx context.Context, network, addr string) (net.Conn, error),
|
||||
) (*imgcache.Service, *session.Manager, *encurl.Generator, error) {
|
||||
cache, err := imgcache.NewCache(db.DB(), imgcache.CacheConfig{
|
||||
StateDir: cfg.StateDir,
|
||||
NegativeTTL: imgcache.DefaultNegativeTTL,
|
||||
MaxBytes: cfg.CacheMaxBytes,
|
||||
}, prometheus.NewRegistry())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
svc, err := imgcache.NewService(&imgcache.ServiceConfig{
|
||||
Cache: cache,
|
||||
Fetcher: httpfetcher.New(&httpfetcher.Config{
|
||||
Timeout: cfg.UpstreamFetchTimeout,
|
||||
MaxResponseSize: cfg.UpstreamMaxResponseSize,
|
||||
AllowHTTP: cfg.AllowHTTP,
|
||||
MaxConnectionsPerHost: cfg.UpstreamConnectionsPerHost,
|
||||
MaxConnections: cfg.UpstreamConnections,
|
||||
BlockedNetworks: cfg.BlockedNetworks,
|
||||
DialContext: dialContext,
|
||||
}),
|
||||
Processor: imageprocessor.New(imageprocessor.Params{
|
||||
MaxInputBytes: cfg.UpstreamMaxResponseSize,
|
||||
MaxConcurrentProcessing: cfg.MaxConcurrentProcessing,
|
||||
}),
|
||||
SigningKey: cfg.SigningKey,
|
||||
Allowlist: cfg.AllowlistHosts,
|
||||
AllowHTTP: cfg.AllowHTTP,
|
||||
MaxResponseSize: cfg.UpstreamMaxResponseSize,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
sessMgr, err := session.NewManagerWithDatabase(
|
||||
context.Background(), cfg.SigningKey, db.DB())
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
encGen, err := encurl.NewGenerator(cfg.SigningKey)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return svc, sessMgr, encGen, nil
|
||||
}
|
||||
|
||||
// clientRequest builds a request for / arriving from remoteAddr, carrying
|
||||
// forwardedFor as its X-Forwarded-For header when that is not empty.
|
||||
func clientRequest(
|
||||
|
||||
Reference in New Issue
Block a user