From 28ad99b747f438d6d1918bfc85d4a3d525e633c0 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Thu, 25 Apr 2024 21:51:34 +0200 Subject: [PATCH] Decouple `structify` from `contracts` --- pkg/icingadb/history/sla.go | 10 +++++++++- pkg/icingadb/history/sync.go | 19 +++++++++++++++++-- pkg/icingadb/runtime_updates.go | 19 +++++++++++++++++-- pkg/structify/structify.go | 9 +++------ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/pkg/icingadb/history/sla.go b/pkg/icingadb/history/sla.go index e0d269043..6b53f5fde 100644 --- a/pkg/icingadb/history/sla.go +++ b/pkg/icingadb/history/sla.go @@ -1,6 +1,7 @@ package history import ( + "github.com/icinga/icingadb/pkg/contracts" "github.com/icinga/icingadb/pkg/icingadb/types" "github.com/icinga/icingadb/pkg/icingadb/v1/history" "github.com/icinga/icingadb/pkg/redis" @@ -8,7 +9,14 @@ import ( "reflect" ) -var slaStateStructify = structify.MakeMapStructifier(reflect.TypeOf((*history.SlaHistoryState)(nil)).Elem(), "json") +var slaStateStructify = structify.MakeMapStructifier( + reflect.TypeOf((*history.SlaHistoryState)(nil)).Elem(), + "json", + func(a any) { + if initer, ok := a.(contracts.Initer); ok { + initer.Init() + } + }) func stateHistoryToSlaEntity(entry redis.XMessage) ([]history.UpserterEntity, error) { slaStateInterface, err := slaStateStructify(entry.Values) diff --git a/pkg/icingadb/history/sync.go b/pkg/icingadb/history/sync.go index e7c3b4316..c370991f5 100644 --- a/pkg/icingadb/history/sync.go +++ b/pkg/icingadb/history/sync.go @@ -3,6 +3,7 @@ package history import ( "context" "github.com/icinga/icingadb/pkg/com" + "github.com/icinga/icingadb/pkg/contracts" "github.com/icinga/icingadb/pkg/database" v1types "github.com/icinga/icingadb/pkg/icingadb/v1" v1 "github.com/icinga/icingadb/pkg/icingadb/v1/history" @@ -177,7 +178,14 @@ type stageFunc func(ctx context.Context, s Sync, key string, in <-chan redis.XMe // For each history event it receives, it parses that event into a new instance of that entity type and writes it to // the database. It writes exactly one entity to the database for each history event. func writeOneEntityStage(structPtr interface{}) stageFunc { - structifier := structify.MakeMapStructifier(reflect.TypeOf(structPtr).Elem(), "json") + structifier := structify.MakeMapStructifier( + reflect.TypeOf(structPtr).Elem(), + "json", + func(a any) { + if initer, ok := a.(contracts.Initer); ok { + initer.Init() + } + }) return writeMultiEntityStage(func(entry redis.XMessage) ([]v1.UpserterEntity, error) { ptr, err := structifier(entry.Values) @@ -313,7 +321,14 @@ func userNotificationStage(ctx context.Context, s Sync, key string, in <-chan re UserIds types.String `structify:"users_notified_ids"` } - structifier := structify.MakeMapStructifier(reflect.TypeOf((*NotificationHistory)(nil)).Elem(), "structify") + structifier := structify.MakeMapStructifier( + reflect.TypeOf((*NotificationHistory)(nil)).Elem(), + "structify", + func(a any) { + if initer, ok := a.(contracts.Initer); ok { + initer.Init() + } + }) return writeMultiEntityStage(func(entry redis.XMessage) ([]v1.UpserterEntity, error) { rawNotificationHistory, err := structifier(entry.Values) diff --git a/pkg/icingadb/runtime_updates.go b/pkg/icingadb/runtime_updates.go index 92e734c9e..fd2dcd3dc 100644 --- a/pkg/icingadb/runtime_updates.go +++ b/pkg/icingadb/runtime_updates.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/icinga/icingadb/pkg/com" "github.com/icinga/icingadb/pkg/common" + "github.com/icinga/icingadb/pkg/contracts" "github.com/icinga/icingadb/pkg/database" v1 "github.com/icinga/icingadb/pkg/icingadb/v1" "github.com/icinga/icingadb/pkg/icingaredis/telemetry" @@ -95,7 +96,14 @@ func (r *RuntimeUpdates) Sync( g.Go(structifyStream( ctx, updateMessages, upsertEntities, upsertedFifo, deleteIds, deletedFifo, - structify.MakeMapStructifier(reflect.TypeOf(s.Entity()).Elem(), "json"), + structify.MakeMapStructifier( + reflect.TypeOf(s.Entity()).Elem(), + "json", + func(a any) { + if initer, ok := a.(contracts.Initer); ok { + initer.Init() + } + }), )) g.Go(func() error { @@ -155,7 +163,14 @@ func (r *RuntimeUpdates) Sync( updateMessagesByKey["icinga:"+strcase.Delimited(cv.Name(), ':')] = updateMessages g.Go(structifyStream( ctx, updateMessages, upsertEntities, nil, deleteIds, nil, - structify.MakeMapStructifier(reflect.TypeOf(cv.Entity()).Elem(), "json"), + structify.MakeMapStructifier( + reflect.TypeOf(cv.Entity()).Elem(), + "json", + func(a any) { + if initer, ok := a.(contracts.Initer); ok { + initer.Init() + } + }), )) customvars, flatCustomvars, errs := v1.ExpandCustomvars(ctx, upsertEntities) diff --git a/pkg/structify/structify.go b/pkg/structify/structify.go index 2b2b5bbbe..94d75267e 100644 --- a/pkg/structify/structify.go +++ b/pkg/structify/structify.go @@ -3,7 +3,6 @@ package structify import ( "encoding" "fmt" - "github.com/icinga/icingadb/pkg/contracts" "github.com/pkg/errors" "golang.org/x/exp/constraints" "reflect" @@ -27,17 +26,15 @@ type MapStructifier = func(map[string]interface{}) (interface{}, error) // MakeMapStructifier builds a function which parses a map's string values into a new struct of type t // and returns a pointer to it. tag specifies which tag connects struct fields to map keys. // MakeMapStructifier panics if it detects an unsupported type (suitable for usage in init() or global vars). -func MakeMapStructifier(t reflect.Type, tag string) MapStructifier { +func MakeMapStructifier(t reflect.Type, tag string, initer func(any)) MapStructifier { tree := buildStructTree(t, tag) return func(kv map[string]interface{}) (interface{}, error) { vPtr := reflect.New(t) ptr := vPtr.Interface() - - if initer, ok := ptr.(contracts.Initer); ok { - initer.Init() + if initer != nil { + initer(ptr) } - vPtrElem := vPtr.Elem() err := errors.Wrapf(structifyMapByTree(kv, tree, vPtrElem, vPtrElem, new([]int)), "can't structify map %#v by tree %#v", kv, tree)