1 Commits
Author SHA1 Message Date
sneak 11da311b8e Build the image pipeline in pixad's fx graph (closes #313)
check / check (push) Canceled after 0s
The new package internal/providers builds the cache, the fetcher, the
processor, the image service, the session manager and the encrypted URL
generator from the config. providers.Option gives them to pixad's fx
graph, and handlers.New receives them built. The server tests build the
same graph, with only the fetcher's dial function replaced. 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, and
internal/providers works out the default cache_max_bytes. 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.

Model: opus-5-5
2026-10-26 10:57:49 +00:00
6 changed files with 28 additions and 25 deletions

No files matched your search

+2 -2
View File
@@ -36,8 +36,8 @@ P2: security: per-origin rate limiting
`MaxBytes` is the one value for the disk cache limit, and 0 turns the disk `MaxBytes` is the one value for the disk cache limit, and 0 turns the disk
cache off. For an omitted `cache_max_bytes`, `internal/providers` works out cache off. For an omitted `cache_max_bytes`, `internal/providers` works out
`config.DefaultCacheMaxBytes` before it builds the cache. `internal/app` and `config.DefaultCacheMaxBytes` before it builds the cache. `internal/app` and
the server tests build the parts below with `providers.Constructors()`; the the server tests build the parts below with `providers.Option`; the image
image proxy test replaces only the fetcher's dial function. proxy test replaces only the fetcher's dial function.
- Built by the providers in `internal/providers`, and given to - Built by the providers in `internal/providers`, and given to
`handlers.New`: `handlers.New`:
- the cache - the cache
+1 -1
View File
@@ -66,7 +66,7 @@ func run(_ *cobra.Command, _ []string) {
// The registry /metrics serves // The registry /metrics serves
func() prometheus.Registerer { return prometheus.DefaultRegisterer }, func() prometheus.Registerer { return prometheus.DefaultRegisterer },
), ),
fx.Provide(providers.Constructors()...), providers.Option,
fx.Invoke( fx.Invoke(
func(log *logger.Logger) { log.Identify() }, func(log *logger.Logger) { log.Identify() },
func(*server.Server) {}, func(*server.Server) {},
@@ -1,4 +1,4 @@
package providers package app
import ( import (
"encoding/json" "encoding/json"
@@ -20,16 +20,20 @@ import (
"sneak.berlin/go/pixa/internal/handlers" "sneak.berlin/go/pixa/internal/handlers"
"sneak.berlin/go/pixa/internal/healthcheck" "sneak.berlin/go/pixa/internal/healthcheck"
"sneak.berlin/go/pixa/internal/logger" "sneak.berlin/go/pixa/internal/logger"
"sneak.berlin/go/pixa/internal/providers"
) )
// testSigningKey is a throwaway signing key.
const testSigningKey = "test-signing-key-0123456789abcdef"
// TestFetcherFromConfigRefusesBlockedNetworks builds the handlers as pixad // TestFetcherFromConfigRefusesBlockedNetworks builds the handlers as pixad
// does, in an fx app with the providers of pixad's fx app, and requests an // does, in an fx app with the providers of pixad's fx app, and requests an
// image from 192.0.2.10, which is on the allowlist and in blocked_networks. // image from 192.0.2.10, which is on the allowlist and in blocked_networks.
// The URL check accepts that address; only the dialer that refuses internal // The URL check accepts that address; only the dialer that refuses internal
// addresses checks blocked_networks, so the answer is 403 only if the // addresses checks blocked_networks, so the answer is 403 only if the
// fetcher this package builds from the config connects with that dialer. // fetcher providers.Option builds from the config connects with that
// Any other dialer would try to connect until the upstream fetch timeout, // dialer. Any other dialer would try to connect until the upstream fetch
// which is short so that the test then fails quickly. // timeout, which is short so that the test then fails quickly.
func TestFetcherFromConfigRefusesBlockedNetworks(t *testing.T) { func TestFetcherFromConfigRefusesBlockedNetworks(t *testing.T) {
t.Parallel() t.Parallel()
@@ -57,7 +61,7 @@ func TestFetcherFromConfigRefusesBlockedNetworks(t *testing.T) {
fx.Provide(globals.New, logger.New, database.New, healthcheck.New, fx.Provide(globals.New, logger.New, database.New, healthcheck.New,
handlers.New, handlers.New,
func() prometheus.Registerer { return prometheus.NewRegistry() }), func() prometheus.Registerer { return prometheus.NewRegistry() }),
fx.Provide(Constructors()...), providers.Option,
fx.Populate(&h), fx.Populate(&h),
) )
app.RequireStart() app.RequireStart()
+13 -14
View File
@@ -30,20 +30,19 @@ import (
"sneak.berlin/go/pixa/internal/session" "sneak.berlin/go/pixa/internal/session"
) )
// Constructors returns the constructors of the parts this package builds, // Option provides the parts this package builds. The fx graph must also
// for fx.Provide. The fx graph must also provide the prometheus.Registerer // provide the prometheus.Registerer the cache registers its counters on.
// the cache registers its counters on. //
func Constructors() []any { //nolint:gochecknoglobals // an fx option, built once and never changed
return []any{ var Option = fx.Provide(
newCache, newCache,
newFetcherConfig, newFetcherConfig,
httpfetcher.New, httpfetcher.New,
newProcessor, newProcessor,
newImageService, newImageService,
newSessionManager, newSessionManager,
newEncryptedURLGenerator, newEncryptedURLGenerator,
} )
}
// cacheParams defines dependencies for newCache. // cacheParams defines dependencies for newCache.
type cacheParams struct { type cacheParams struct {
+2 -2
View File
@@ -172,7 +172,7 @@ func startImageProxy(
middleware.New, middleware.New,
func() prometheus.Registerer { return prometheus.NewRegistry() }, func() prometheus.Registerer { return prometheus.NewRegistry() },
), ),
fx.Provide(providers.Constructors()...), providers.Option,
fx.Decorate(func(fetcherConfig *httpfetcher.Config) *httpfetcher.Config { fx.Decorate(func(fetcherConfig *httpfetcher.Config) *httpfetcher.Config {
fetcherConfig.DialContext = dialUpstream fetcherConfig.DialContext = dialUpstream
@@ -233,7 +233,7 @@ func startImageProxyWithBlockedNetworks(
middleware.New, middleware.New,
func() prometheus.Registerer { return prometheus.NewRegistry() }, func() prometheus.Registerer { return prometheus.NewRegistry() },
), ),
fx.Provide(providers.Constructors()...), providers.Option,
fx.Populate(&h, &mw), fx.Populate(&h, &mw),
) )
app.RequireStart() app.RequireStart()
+1 -1
View File
@@ -50,7 +50,7 @@ func startPixa(t *testing.T, cfg *config.Config) *Server {
middleware.New, middleware.New,
func() prometheus.Registerer { return prometheus.NewRegistry() }, func() prometheus.Registerer { return prometheus.NewRegistry() },
), ),
fx.Provide(providers.Constructors()...), providers.Option,
fx.Populate(&h, &mw), fx.Populate(&h, &mw),
) )
app.RequireStart() app.RequireStart()