Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove DIContainer abstraction #196

Merged
merged 4 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions c.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ package core

import (
"context"
"errors"
"fmt"
"reflect"
"regexp"

"github.com/DoNewsCode/core/codec/yaml"
"github.com/DoNewsCode/core/config"
Expand All @@ -23,10 +21,11 @@ import (
"github.com/go-kit/kit/log"
"github.com/knadh/koanf/providers/confmap"
"github.com/knadh/koanf/providers/file"
"go.uber.org/dig"
)

// C stands for the core of the application. It contains service definitions and
// dependencies. C is mean to be used in the boostrap phase of the application.
// dependencies. C means to be used in the boostrap phase of the application.
// Do not pass C into services and use it as a service locator.
type C struct {
AppName contract.AppName
Expand All @@ -35,7 +34,7 @@ type C struct {
logging.LevelLogger
contract.Container
contract.Dispatcher
di contract.DIContainer
di *dig.Container
}

// ConfParser models a parser for configuration. For example, yaml.Parser.
Expand All @@ -56,8 +55,8 @@ type ConfigProvider func(configStack []config.ProviderSet, configWatcher contrac
// EventDispatcherProvider provides contract.Dispatcher to the core.
type EventDispatcherProvider func(conf contract.ConfigUnmarshaler) contract.Dispatcher

// DiProvider provides the DiContainer to the core.
type DiProvider func(conf contract.ConfigUnmarshaler) contract.DIContainer
// DiProvider provides the *dig.Container to the core.
type DiProvider func(conf contract.ConfigUnmarshaler) *dig.Container

// AppNameProvider provides the contract.AppName to the core.
type AppNameProvider func(conf contract.ConfigUnmarshaler) contract.AppName
Expand Down Expand Up @@ -249,8 +248,15 @@ func (c *C) Provide(deps di.Deps) {
}

func (c *C) provide(constructor interface{}) {

var shouldMakeFunc bool
var (
options []dig.ProvideOption
shouldMakeFunc bool
)

if op, ok := constructor.(di.OptionalProvider); ok {
constructor = op.Constructor
options = op.Options
}

ftype := reflect.TypeOf(constructor)
if ftype == nil {
Expand Down Expand Up @@ -284,7 +290,7 @@ func (c *C) provide(constructor interface{}) {

// no cleanup or module, we can use normal dig.
if !shouldMakeFunc {
err := c.di.Provide(constructor)
err := c.di.Provide(constructor, options...)
if err != nil {
panic(err)
}
Expand All @@ -309,7 +315,8 @@ func (c *C) provide(constructor interface{}) {
}
return filteredOuts
})
err := c.di.Provide(fn.Interface())
options = append(options, dig.LocationForPC(reflect.ValueOf(constructor).Pointer()))
err := c.di.Provide(fn.Interface(), options...)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -408,8 +415,6 @@ func (c *C) AddModuleFunc(constructor interface{}) {
func (c *C) Invoke(function interface{}) {
err := c.di.Invoke(function)
if err != nil {
re := regexp.MustCompile(` missing dependencies for function "reflect"\.makeFuncStub \(.+?\):`)
err = errors.New(re.ReplaceAllString(err.Error(), ""))
panic(err)
}
}
Expand Down
20 changes: 1 addition & 19 deletions contract/di.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
package contract

// DIProvider is an interface that models a container to which users can add
// dependencies. See di.Graph for the implementation requirement.
type DIProvider interface {
Provide(constructor interface{}) error
}

// DIInvoker is an interface that models a container to which users can fetch
// dependencies. See di.Graph for the implementation requirement.
type DIInvoker interface {
Invoke(function interface{}) error
}

// DIPopulator is an interface that models a container to which users can fetch
// dependencies. It is an syntax sugar to DIInvoker. See di.Graph for the
// dependencies. It is a syntax sugar to dig.Container. See dig.Container for the
// implementation requirement.
type DIPopulator interface {
// Populate is just another way of fetching dependencies from container. It
// accepts a ptr to target, and populates the target from the container.
Populate(target interface{}) error
}

// DIContainer is a container roughly modeled after dig.Container.
type DIContainer interface {
DIProvider
DIInvoker
}
6 changes: 3 additions & 3 deletions default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (

"github.com/DoNewsCode/core/config"
"github.com/DoNewsCode/core/contract"
"github.com/DoNewsCode/core/di"
"github.com/DoNewsCode/core/events"
"github.com/DoNewsCode/core/logging"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/rawbytes"
"go.uber.org/dig"
)

const defaultConfig = `
Expand Down Expand Up @@ -100,8 +100,8 @@ func ProvideLogger(conf contract.ConfigUnmarshaler, appName contract.AppName, en
}

// ProvideDi is the default DiProvider for package Core.
func ProvideDi(conf contract.ConfigUnmarshaler) contract.DIContainer {
return di.NewGraph()
func ProvideDi(conf contract.ConfigUnmarshaler) *dig.Container {
return dig.New()
}

// ProvideEventDispatcher is the default EventDispatcherProvider for package Core.
Expand Down
133 changes: 0 additions & 133 deletions di/graph.go

This file was deleted.

72 changes: 72 additions & 0 deletions di/optional_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package di

import (
"reflect"

"go.uber.org/dig"
)

// OptionalProvider is a struct with constructor and dig options. When
// OptionalProvider is used as the element in di.Deps, the options are applied to
// the inner dig.Container automatically.
type OptionalProvider struct {
Constructor interface{}
Options []dig.ProvideOption
}

// LocationForPC sets the constructor pointer to a specified location. Use this
// Options to reduce vague debug message when constructor are made by
// reflect.makeFunc. For example:
// LocationForPC(reflect.makeFunc(...), reflect.ValueOf(realConstructor).Pointer())
func LocationForPC(constructor interface{}, pc uintptr) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.LocationForPC(pc))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.LocationForPC(pc)},
}
}

// As constructs the instance and bind it to another interface. As means to be used as an argument to graph.Provide.
// For example:
// As(MyConstructor, new(MyAbstractInterface))
func As(constructor interface{}, as interface{}) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.As(as))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.As(as)},
}
}

// Name constructs a named instance. Name means to be used as an argument to graph.Provide.
// For example:
// Name(MyConstructor, "foo")
func Name(constructor interface{}, name string) interface{} {
if op, ok := constructor.(OptionalProvider); ok {
op.Options = append(op.Options, dig.Name(name))
return op
}
return OptionalProvider{
Constructor: constructor,
Options: []dig.ProvideOption{dig.Name(name)},
}
}

// Bind binds a type to another. Useful when binding implementation to
// interfaces. The arguments should be a ptr to the binding types, rather than
// the types themselves. For example:
// Bind(new(MyConcreteStruct), new(MyAbstractInterface))
func Bind(from interface{}, to interface{}) interface{} {
fromTypes := []reflect.Type{reflect.TypeOf(from).Elem()}
toTypes := []reflect.Type{reflect.TypeOf(to).Elem()}
fnType := reflect.FuncOf(fromTypes, toTypes, false /* variadic */)
fn := reflect.MakeFunc(fnType, func(args []reflect.Value) []reflect.Value {
return args
})
return fn.Interface()
}
Loading