package components import ( "context" "sort" "go-micro.dev/v4" "go-micro.dev/v4/errors" "go-micro.dev/v4/server" "github.com/urfave/cli/v2" ) var ( errorRetrievingComponents = errors.InternalServerError("RETRIEVING_COMPONENTS", "error while retrieving components") errorComponentsIsNil = errors.InternalServerError("COMPONENTS_NIL", "components is nil") ) type HealthInfo struct { Message string `json:"message"` IsError bool `json:"is_error"` } type HealthInfoMap map[string]HealthInfo type ComponentsKey struct{} type Components struct { components map[string]Component service micro.Service } func Context(ctx context.Context) (*Components, error) { c, ok := ctx.Value(ComponentsKey{}).(*Components) if !ok { return nil, errorRetrievingComponents } if c == nil { return nil, errorComponentsIsNil } return c, nil } func Must(ctx context.Context) *Components { c, err := Context(ctx) if err != nil { panic(err) } return c } func New(components ...Component) *Components { com := &Components{components: make(map[string]Component)} com.Add(components...) return com } func (c *Components) SetService(service micro.Service) { c.service = service } func (c *Components) Service() micro.Service { return c.service } func (c *Components) Add(components ...Component) { for _, component := range components { if component == nil { continue } if _, ok := c.components[component.Name()]; ok { continue } c.components[component.Name()] = component } } func (c *Components) Get(name string) (Component, error) { if component, ok := c.components[name]; ok { return component, nil } return nil, errors.InternalServerError("COMPONENT_NOT_FOUND", "component '%s' has not been found", name) } func (c *Components) Must(name string) Component { component, err := c.Get(name) if err != nil { panic(err) } return component } func (c *Components) MergeFlags(flags []cli.Flag) []cli.Flag { for _, component := range c.components { flags = component.MergeFlags(flags) } return flags } func (c *Components) Initialized() bool { for _, component := range c.components { if !component.Initialized() { return false } } return true } func (c *Components) Init(context *cli.Context) error { // Sort Components by Priority ASC components := make([]Component, len(c.components)) for _, com := range c.components { components = append(components, com) } sort.SliceStable(components, func(i, j int) bool { if components[i] == nil || components[j] == nil { return false } return components[i].Priority() < components[j].Priority() }) // Init them sorted now for _, component := range components { if c == nil { continue } if err := component.Init(c, context); err != nil { return err } } return nil } func (c *Components) Health(context context.Context) HealthInfoMap { result := make(HealthInfoMap, len(c.components)) for _, component := range c.components { m, e := component.Health(context) result[component.Name()] = HealthInfo{Message: m, IsError: e} } return result } func (c *Components) Wrapper() server.HandlerWrapper { return func(h server.HandlerFunc) server.HandlerFunc { return func(ctx context.Context, req server.Request, rsp interface{}) error { ctx = context.WithValue(ctx, ComponentsKey{}, c) for _, component := range c.components { if err := component.WrapperFunc(ctx, req, rsp); err != nil { return err } } return h(ctx, req, rsp) } } }