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