From 4fdb77c8337e35950009bbbeb915eb71d553728c Mon Sep 17 00:00:00 2001 From: dragon Date: Thu, 29 Jan 2026 13:44:00 +0800 Subject: [PATCH] refactor: Use functional options pattern for NewPageServer --- cmd/local/main.go | 16 ++++--- cmd/server/main.go | 14 +++--- pkg/server.go | 109 +++++++++++++++++++++++++++++++++++++++------ tests/core/test.go | 16 +++---- 4 files changed, 119 insertions(+), 36 deletions(-) diff --git a/cmd/local/main.go b/cmd/local/main.go index 9d17cf2..764fe67 100644 --- a/cmd/local/main.go +++ b/cmd/local/main.go @@ -71,19 +71,25 @@ func main() { zap.L().Fatal("failed to init memory provider", zap.Error(err)) } subscriber := subscribe.NewMemorySubscriber() - server, err := pkg.NewPageServer(http.DefaultClient, - provider, domain, memory, subscriber, memory, 0, &nopCache{}, 0, - func(w http.ResponseWriter, r *http.Request, err error) { + server, err := pkg.NewPageServer( + provider, domain, memory, + pkg.WithClient(http.DefaultClient), + pkg.WithEvent(subscriber), + pkg.WithMetaCache(memory, 0), + pkg.WithBlobCache(&nopCache{}, 0), + pkg.WithErrorHandler(func(w http.ResponseWriter, r *http.Request, err error) { if errors.Is(err, os.ErrNotExist) { http.Error(w, "page not found.", http.StatusNotFound) } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } - }, map[string]map[string]any{ + }), + pkg.WithFilterConfig(map[string]map[string]any{ "redirect": { "scheme": "http", }, - }) + }), + ) if err != nil { zap.L().Fatal("failed to init page", zap.Error(err)) } diff --git a/cmd/server/main.go b/cmd/server/main.go index fbd25ad..017a217 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -74,17 +74,15 @@ func main() { config.Filters = make(map[string]map[string]any) } pageServer, err := pkg.NewPageServer( - http.DefaultClient, backend, config.Domain, cdb, - event, - cacheMeta, - config.Cache.MetaTTL, - cacheBlob.Child("filter"), - config.Cache.BlobTTL, - config.ErrorHandler, - config.Filters, + pkg.WithClient(http.DefaultClient), + pkg.WithEvent(event), + pkg.WithMetaCache(cacheMeta, config.Cache.MetaTTL), + pkg.WithBlobCache(cacheBlob.Child("filter"), config.Cache.BlobTTL), + pkg.WithErrorHandler(config.ErrorHandler), + pkg.WithFilterConfig(config.Filters), ) if err != nil { log.Fatalln(err) diff --git a/pkg/server.go b/pkg/server.go index 0e8f38a..bde641c 100644 --- a/pkg/server.go +++ b/pkg/server.go @@ -40,27 +40,108 @@ type Server struct { errorHandler func(w http.ResponseWriter, r *http.Request, err error) } +type serverConfig struct { + client *http.Client + event subscribe.Subscriber + cacheMeta kv.KV + cacheMetaTTL time.Duration + cacheBlob cache.Cache + cacheBlobTTL time.Duration + errorHandler func(w http.ResponseWriter, r *http.Request, err error) + filterConfig map[string]map[string]any +} + +type ServerOption func(*serverConfig) + +func WithClient(client *http.Client) ServerOption { + return func(c *serverConfig) { + c.client = client + } +} + +func WithEvent(event subscribe.Subscriber) ServerOption { + return func(c *serverConfig) { + c.event = event + } +} + +func WithMetaCache(cache kv.KV, ttl time.Duration) ServerOption { + return func(c *serverConfig) { + c.cacheMeta = cache + c.cacheMetaTTL = ttl + } +} + +func WithBlobCache(cache cache.Cache, ttl time.Duration) ServerOption { + return func(c *serverConfig) { + c.cacheBlob = cache + c.cacheBlobTTL = ttl + } +} + +func WithErrorHandler(handler func(w http.ResponseWriter, r *http.Request, err error)) ServerOption { + return func(c *serverConfig) { + c.errorHandler = handler + } +} + +func WithFilterConfig(config map[string]map[string]any) ServerOption { + return func(c *serverConfig) { + c.filterConfig = config + } +} + func NewPageServer( - client *http.Client, backend core.Backend, domain string, db kv.CursorPagedKV, - event subscribe.Subscriber, - cacheMeta kv.KV, - cacheMetaTTL time.Duration, - cacheBlob cache.Cache, - cacheBlobTTL time.Duration, - errorHandler func(w http.ResponseWriter, r *http.Request, err error), - filterConfig map[string]map[string]any, + opts ...ServerOption, ) (*Server, error) { + cfg := &serverConfig{ + client: http.DefaultClient, + filterConfig: make(map[string]map[string]any), + } + for _, opt := range opts { + opt(cfg) + } + + if cfg.event == nil { + cfg.event = subscribe.NewMemorySubscriber() + } + + if cfg.cacheMeta == nil { + var err error + cfg.cacheMeta, err = kv.NewMemory("") + if err != nil { + return nil, err + } + } + + if cfg.cacheBlob == nil { + var err error + cfg.cacheBlob, err = cache.NewMemoryCache(cache.MemoryCacheConfig{ + MaxCapacity: 128, + CleanupInt: time.Minute, + }) + if err != nil { + return nil, err + } + } + + if cfg.errorHandler == nil { + cfg.errorHandler = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + alias := core.NewDomainAlias(db.Child("config", "alias")) - svcMeta := core.NewServerMeta(client, backend, domain, alias, cacheMeta, cacheMetaTTL) + svcMeta := core.NewServerMeta(cfg.client, backend, domain, alias, cfg.cacheMeta, cfg.cacheMetaTTL) pageMeta := core.NewPageDomain(svcMeta, domain) globCache, err := lru.New[string, glob.Glob](512) if err != nil { return nil, err } - defaultFilters, err := filters.DefaultFilters(filterConfig) + defaultFilters, err := filters.DefaultFilters(cfg.filterConfig) if err != nil { return nil, err } @@ -70,10 +151,10 @@ func NewPageServer( db: db, globCache: globCache, filterMgr: defaultFilters, - errorHandler: errorHandler, - cacheBlob: cacheBlob, - cacheBlobTTL: cacheBlobTTL, - event: event, + errorHandler: cfg.errorHandler, + cacheBlob: cfg.cacheBlob, + cacheBlobTTL: cfg.cacheBlobTTL, + event: cfg.event, }, nil } diff --git a/tests/core/test.go b/tests/core/test.go index c3c5637..6d68608 100644 --- a/tests/core/test.go +++ b/tests/core/test.go @@ -48,23 +48,21 @@ func NewTestServer(domain string) *TestServer { }) memoryKV, _ := kv.NewMemory("") server, err := pkg.NewPageServer( - http.DefaultClient, dummy, domain, memoryKV, - subscribe.NewMemorySubscriber(), - memoryKV.Child("cache"), - 0, - memoryCache, - 0, - func(w http.ResponseWriter, r *http.Request, err error) { + pkg.WithClient(http.DefaultClient), + pkg.WithEvent(subscribe.NewMemorySubscriber()), + pkg.WithMetaCache(memoryKV.Child("cache"), 0), + pkg.WithBlobCache(memoryCache, 0), + pkg.WithErrorHandler(func(w http.ResponseWriter, r *http.Request, err error) { if errors.Is(err, os.ErrNotExist) { http.Error(w, "page not found.", http.StatusNotFound) } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } - }, - make(map[string]map[string]any), + }), + pkg.WithFilterConfig(make(map[string]map[string]any)), ) if err != nil { panic(err)