From 49d0ac50724629f5916aa1c85e7ebd9d690a1c30 Mon Sep 17 00:00:00 2001 From: William Petit Date: Fri, 23 Jun 2023 17:53:56 -0600 Subject: [PATCH] feat: refactor layers registration --- internal/admin/layer_route.go | 14 ++++- internal/command/server/proxy/run.go | 2 +- .../director/layer}/queue/adapter.go | 0 .../director/layer}/queue/layer_options.go | 0 .../director/layer}/queue/options.go | 0 .../{ => proxy/director/layer}/queue/queue.go | 0 .../director/layer}/queue/redis/adapter.go | 2 +- internal/proxy/director/layer/queue/schema.go | 8 +++ .../layer}/queue/schema/layer-options.json | 0 internal/queue/schema.go | 20 ------- internal/schema/load.go | 6 +- internal/schema/registry.go | 56 ------------------- internal/schema/validate.go | 20 +++++++ internal/setup/default_registry.go | 18 ++++-- internal/setup/error.go | 5 ++ internal/setup/queue_layer.go | 20 +++++-- internal/setup/queue_repository.go | 20 ------- internal/setup/registry.go | 39 ++++++++++--- 18 files changed, 112 insertions(+), 118 deletions(-) rename internal/{ => proxy/director/layer}/queue/adapter.go (100%) rename internal/{ => proxy/director/layer}/queue/layer_options.go (100%) rename internal/{ => proxy/director/layer}/queue/options.go (100%) rename internal/{ => proxy/director/layer}/queue/queue.go (100%) rename internal/{ => proxy/director/layer}/queue/redis/adapter.go (97%) create mode 100644 internal/proxy/director/layer/queue/schema.go rename internal/{ => proxy/director/layer}/queue/schema/layer-options.json (100%) delete mode 100644 internal/queue/schema.go delete mode 100644 internal/schema/registry.go create mode 100644 internal/schema/validate.go create mode 100644 internal/setup/error.go delete mode 100644 internal/setup/queue_repository.go diff --git a/internal/admin/layer_route.go b/internal/admin/layer_route.go index e732142..d8af607 100644 --- a/internal/admin/layer_route.go +++ b/internal/admin/layer_route.go @@ -245,7 +245,19 @@ func (s *Server) updateLayer(w http.ResponseWriter, r *http.Request) { } if updateLayerReq.Options != nil { - if err := schema.ValidateLayerOptions(ctx, layer.Type, updateLayerReq.Options); err != nil { + layerOptionsSchema, err := setup.GetLayerOptionsSchema(layer.Type) + if err != nil { + logger.Error(r.Context(), "could not retrieve layer options schema", logger.E(errors.WithStack(err))) + api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) + + return + } + + rawOptions := func(opts *store.LayerOptions) map[string]any { + return *opts + }(updateLayerReq.Options) + + if err := schema.Validate(ctx, layerOptionsSchema, rawOptions); err != nil { logger.Error(r.Context(), "could not validate layer options", logger.E(errors.WithStack(err))) var invalidDataErr *schema.InvalidDataError diff --git a/internal/command/server/proxy/run.go b/internal/command/server/proxy/run.go index b0683d7..8c27bf3 100644 --- a/internal/command/server/proxy/run.go +++ b/internal/command/server/proxy/run.go @@ -28,7 +28,7 @@ func RunCommand() *cli.Command { logger.SetFormat(logger.Format(conf.Logger.Format)) logger.SetLevel(logger.Level(conf.Logger.Level)) - layers, err := setup.CreateLayers(ctx.Context, conf) + layers, err := setup.GetLayers(ctx.Context, conf) if err != nil { return errors.Wrap(err, "could not initialize director layers") } diff --git a/internal/queue/adapter.go b/internal/proxy/director/layer/queue/adapter.go similarity index 100% rename from internal/queue/adapter.go rename to internal/proxy/director/layer/queue/adapter.go diff --git a/internal/queue/layer_options.go b/internal/proxy/director/layer/queue/layer_options.go similarity index 100% rename from internal/queue/layer_options.go rename to internal/proxy/director/layer/queue/layer_options.go diff --git a/internal/queue/options.go b/internal/proxy/director/layer/queue/options.go similarity index 100% rename from internal/queue/options.go rename to internal/proxy/director/layer/queue/options.go diff --git a/internal/queue/queue.go b/internal/proxy/director/layer/queue/queue.go similarity index 100% rename from internal/queue/queue.go rename to internal/proxy/director/layer/queue/queue.go diff --git a/internal/queue/redis/adapter.go b/internal/proxy/director/layer/queue/redis/adapter.go similarity index 97% rename from internal/queue/redis/adapter.go rename to internal/proxy/director/layer/queue/redis/adapter.go index 7bb282e..515dae7 100644 --- a/internal/queue/redis/adapter.go +++ b/internal/proxy/director/layer/queue/redis/adapter.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "forge.cadoles.com/cadoles/bouncer/internal/queue" + "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue" "github.com/pkg/errors" "github.com/redis/go-redis/v9" ) diff --git a/internal/proxy/director/layer/queue/schema.go b/internal/proxy/director/layer/queue/schema.go new file mode 100644 index 0000000..d36cecc --- /dev/null +++ b/internal/proxy/director/layer/queue/schema.go @@ -0,0 +1,8 @@ +package queue + +import ( + _ "embed" +) + +//go:embed schema/layer-options.json +var RawLayerOptionsSchema []byte diff --git a/internal/queue/schema/layer-options.json b/internal/proxy/director/layer/queue/schema/layer-options.json similarity index 100% rename from internal/queue/schema/layer-options.json rename to internal/proxy/director/layer/queue/schema/layer-options.json diff --git a/internal/queue/schema.go b/internal/queue/schema.go deleted file mode 100644 index 941a8ba..0000000 --- a/internal/queue/schema.go +++ /dev/null @@ -1,20 +0,0 @@ -package queue - -import ( - _ "embed" - - "forge.cadoles.com/cadoles/bouncer/internal/schema" - "github.com/pkg/errors" -) - -//go:embed schema/layer-options.json -var rawLayerOptionsSchema []byte - -func init() { - layerOptionsSchema, err := schema.Parse(rawLayerOptionsSchema) - if err != nil { - panic(errors.Wrap(err, "could not parse queue layer options schema")) - } - - schema.RegisterLayerOptionsSchema(LayerType, layerOptionsSchema) -} diff --git a/internal/schema/load.go b/internal/schema/load.go index 31b924e..f1d398c 100644 --- a/internal/schema/load.go +++ b/internal/schema/load.go @@ -7,8 +7,10 @@ import ( "github.com/qri-io/jsonschema" ) -func Parse(data []byte) (*jsonschema.Schema, error) { - var schema jsonschema.Schema +type Schema = jsonschema.Schema + +func Parse(data []byte) (*Schema, error) { + var schema Schema if err := json.Unmarshal(data, &schema); err != nil { return nil, errors.WithStack(err) } diff --git a/internal/schema/registry.go b/internal/schema/registry.go deleted file mode 100644 index b243b41..0000000 --- a/internal/schema/registry.go +++ /dev/null @@ -1,56 +0,0 @@ -package schema - -import ( - "context" - - "forge.cadoles.com/cadoles/bouncer/internal/store" - "github.com/pkg/errors" - "github.com/qri-io/jsonschema" -) - -var defaultRegistry = NewRegistry() - -func RegisterLayerOptionsSchema(layerType store.LayerType, schema *jsonschema.Schema) { - defaultRegistry.RegisterLayerOptionsSchema(layerType, schema) -} - -func ValidateLayerOptions(ctx context.Context, layerType store.LayerType, options *store.LayerOptions) error { - if err := defaultRegistry.ValidateLayerOptions(ctx, layerType, options); err != nil { - return errors.WithStack(err) - } - - return nil -} - -type Registry struct { - layerOptionSchemas map[store.LayerType]*jsonschema.Schema -} - -func (r *Registry) RegisterLayerOptionsSchema(layerType store.LayerType, schema *jsonschema.Schema) { - r.layerOptionSchemas[layerType] = schema -} - -func (r *Registry) ValidateLayerOptions(ctx context.Context, layerType store.LayerType, options *store.LayerOptions) error { - schema, exists := r.layerOptionSchemas[layerType] - if !exists { - return errors.WithStack(ErrSchemaNotFound) - } - - rawOptions := func(opts *store.LayerOptions) map[string]any { - return *opts - }(options) - - state := schema.Validate(ctx, rawOptions) - - if len(*state.Errs) > 0 { - return errors.WithStack(NewInvalidDataError(*state.Errs...)) - } - - return nil -} - -func NewRegistry() *Registry { - return &Registry{ - layerOptionSchemas: make(map[store.LayerType]*jsonschema.Schema), - } -} diff --git a/internal/schema/validate.go b/internal/schema/validate.go new file mode 100644 index 0000000..c9b83f5 --- /dev/null +++ b/internal/schema/validate.go @@ -0,0 +1,20 @@ +package schema + +import ( + "context" + + "github.com/davecgh/go-spew/spew" + "github.com/pkg/errors" +) + +func Validate(ctx context.Context, schema *Schema, data map[string]any) error { + spew.Dump(data) + + state := schema.Validate(ctx, data) + + if len(*state.Errs) > 0 { + return errors.WithStack(NewInvalidDataError(*state.Errs...)) + } + + return nil +} diff --git a/internal/setup/default_registry.go b/internal/setup/default_registry.go index ace49c0..0ccd7e9 100644 --- a/internal/setup/default_registry.go +++ b/internal/setup/default_registry.go @@ -7,16 +7,26 @@ import ( "forge.cadoles.com/cadoles/bouncer/internal/proxy/director" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/pkg/errors" + "github.com/qri-io/jsonschema" ) var defaultRegistry = NewRegistry() -func RegisterLayer(layerType store.LayerType, setupFunc LayerSetupFunc) { - defaultRegistry.RegisterLayer(layerType, setupFunc) +func RegisterLayer(layerType store.LayerType, setupFunc LayerSetupFunc, rawOptionsSchema []byte) { + defaultRegistry.RegisterLayer(layerType, setupFunc, rawOptionsSchema) } -func CreateLayers(ctx context.Context, conf *config.Config) ([]director.Layer, error) { - layers, err := defaultRegistry.CreateLayers(ctx, conf) +func GetLayerOptionsSchema(layerType store.LayerType) (*jsonschema.Schema, error) { + schema, err := defaultRegistry.GetLayerOptionsSchema(layerType) + if err != nil { + return nil, errors.WithStack(err) + } + + return schema, nil +} + +func GetLayers(ctx context.Context, conf *config.Config) ([]director.Layer, error) { + layers, err := defaultRegistry.GetLayers(ctx, conf) if err != nil { return nil, errors.WithStack(err) } diff --git a/internal/setup/error.go b/internal/setup/error.go new file mode 100644 index 0000000..07db374 --- /dev/null +++ b/internal/setup/error.go @@ -0,0 +1,5 @@ +package setup + +import "errors" + +var ErrNotFound = errors.New("not found") diff --git a/internal/setup/queue_layer.go b/internal/setup/queue_layer.go index d34b08c..15ed188 100644 --- a/internal/setup/queue_layer.go +++ b/internal/setup/queue_layer.go @@ -1,21 +1,22 @@ package setup import ( - "context" "time" "forge.cadoles.com/cadoles/bouncer/internal/config" "forge.cadoles.com/cadoles/bouncer/internal/proxy/director" - "forge.cadoles.com/cadoles/bouncer/internal/queue" + "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue" + queueRedis "forge.cadoles.com/cadoles/bouncer/internal/proxy/director/layer/queue/redis" "github.com/pkg/errors" + "github.com/redis/go-redis/v9" ) func init() { - RegisterLayer(queue.LayerType, setupQueueLayer) + RegisterLayer(queue.LayerType, setupQueueLayer, queue.RawLayerOptionsSchema) } -func setupQueueLayer(ctx context.Context, conf *config.Config) (director.Layer, error) { - adapter, err := NewQueueAdapter(ctx, conf.Redis) +func setupQueueLayer(conf *config.Config) (director.Layer, error) { + adapter, err := newQueueAdapter(conf.Redis) if err != nil { return nil, errors.WithStack(err) } @@ -33,3 +34,12 @@ func setupQueueLayer(ctx context.Context, conf *config.Config) (director.Layer, options..., ), nil } + +func newQueueAdapter(redisConf config.RedisConfig) (queue.Adapter, error) { + rdb := redis.NewUniversalClient(&redis.UniversalOptions{ + Addrs: redisConf.Adresses, + MasterName: string(redisConf.Master), + }) + + return queueRedis.NewAdapter(rdb, 2), nil +} diff --git a/internal/setup/queue_repository.go b/internal/setup/queue_repository.go deleted file mode 100644 index a31c139..0000000 --- a/internal/setup/queue_repository.go +++ /dev/null @@ -1,20 +0,0 @@ -package setup - -import ( - "context" - - "forge.cadoles.com/cadoles/bouncer/internal/config" - "forge.cadoles.com/cadoles/bouncer/internal/queue" - "github.com/redis/go-redis/v9" - - queueRedis "forge.cadoles.com/cadoles/bouncer/internal/queue/redis" -) - -func NewQueueAdapter(ctx context.Context, redisConf config.RedisConfig) (queue.Adapter, error) { - rdb := redis.NewUniversalClient(&redis.UniversalOptions{ - Addrs: redisConf.Adresses, - MasterName: string(redisConf.Master), - }) - - return queueRedis.NewAdapter(rdb, 2), nil -} diff --git a/internal/setup/registry.go b/internal/setup/registry.go index 7a7a88c..f436fb2 100644 --- a/internal/setup/registry.go +++ b/internal/setup/registry.go @@ -5,25 +5,48 @@ import ( "forge.cadoles.com/cadoles/bouncer/internal/config" "forge.cadoles.com/cadoles/bouncer/internal/proxy/director" + "forge.cadoles.com/cadoles/bouncer/internal/schema" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/pkg/errors" ) +type layerEntry struct { + setup LayerSetupFunc + rawOptionsSchema []byte +} + type Registry struct { - layers map[store.LayerType]LayerSetupFunc + layers map[store.LayerType]layerEntry } -type LayerSetupFunc func(context.Context, *config.Config) (director.Layer, error) +type LayerSetupFunc func(*config.Config) (director.Layer, error) -func (r *Registry) RegisterLayer(layerType store.LayerType, layerSetup LayerSetupFunc) { - r.layers[layerType] = layerSetup +func (r *Registry) RegisterLayer(layerType store.LayerType, layerSetup LayerSetupFunc, rawOptionsSchema []byte) { + r.layers[layerType] = layerEntry{ + setup: layerSetup, + rawOptionsSchema: rawOptionsSchema, + } } -func (r *Registry) CreateLayers(ctx context.Context, conf *config.Config) ([]director.Layer, error) { +func (r *Registry) GetLayerOptionsSchema(layerType store.LayerType) (*schema.Schema, error) { + layerEntry, exists := r.layers[layerType] + if !exists { + return nil, errors.WithStack(ErrNotFound) + } + + schema, err := schema.Parse(layerEntry.rawOptionsSchema) + if err != nil { + return nil, errors.WithStack(err) + } + + return schema, nil +} + +func (r *Registry) GetLayers(ctx context.Context, conf *config.Config) ([]director.Layer, error) { layers := make([]director.Layer, 0, len(r.layers)) - for layerType, layerSetup := range r.layers { - layer, err := layerSetup(ctx, conf) + for layerType, layerEntry := range r.layers { + layer, err := layerEntry.setup(conf) if err != nil { return nil, errors.Wrapf(err, "could not create layer '%s'", layerType) } @@ -52,6 +75,6 @@ func (r *Registry) GetLayerTypes() []store.LayerType { func NewRegistry() *Registry { return &Registry{ - layers: make(map[store.LayerType]LayerSetupFunc), + layers: make(map[store.LayerType]layerEntry), } }