This repository has been archived by the owner on Apr 9, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.go
136 lines (107 loc) · 3.17 KB
/
app.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package fw
import (
"time"
"github.com/go-kit/kit/log"
"github.com/goph/emperror"
"go.uber.org/dig"
)
// Option sets options in the Application.
type Option interface {
apply(*Application)
}
// optionFunc makes an Option from a function matching apply's signature.
type optionFunc func(*Application)
func (f optionFunc) apply(app *Application) { f(app) }
// Provide registers constructors in the application's dependency injection container.
//
// See the documentation at http://go.uber.org/dig for details about constructor function definitions.
func Provide(constructors ...interface{}) Option {
return provideOption(constructors)
}
type provideOption []interface{}
func (p provideOption) apply(app *Application) {
app.constructors = append(app.constructors, p...)
}
// Invoke registers functions that are executed on application initialization.
//
// See the documentation at http://go.uber.org/dig for details about invoke function definitions.
func Invoke(funcs ...interface{}) Option {
return invokeOption(funcs)
}
type invokeOption []interface{}
func (i invokeOption) apply(app *Application) {
app.invokes = append(app.invokes, i...)
}
// Logger sets the application logger used for logging application lifecycle.
func Logger(logger log.Logger) Option {
return optionFunc(func(app *Application) {
app.logger = logger
})
}
// ErrorHandler sets the error handler in the application.
func ErrorHandler(handler emperror.Handler) Option {
return optionFunc(func(a *Application) {
a.errorHandler = handler
})
}
// Options composes a collection of Option instances into a single Option.
func Options(opts ...Option) Option {
return options(opts)
}
type options []Option
func (o options) apply(app *Application) {
for _, opt := range o {
opt.apply(app)
}
}
// Application collects all dependencies and exposes them in a single context.
type Application struct {
container *dig.Container
constructors []interface{}
invokes []interface{}
lifecycle *lifecycle
lifecycleTimeout time.Duration
logger log.Logger
errorHandler emperror.Handler
}
func New(opts ...Option) (*Application, error) {
app := &Application{
container: dig.New(),
lifecycle: new(lifecycle),
}
// Apply options
for _, opt := range opts {
opt.apply(app)
}
// Default logger
if app.logger == nil {
app.logger = log.NewNopLogger()
}
// Default error handler
if app.errorHandler == nil {
app.errorHandler = emperror.NewNopHandler()
}
// Default lifecycle timeout
if app.lifecycleTimeout == 0 {
app.lifecycleTimeout = defaultTimeout
}
// Register the constructors in the container
for _, ctor := range app.constructors {
err := app.container.Provide(ctor)
if err != nil {
err = emperror.WithStack(emperror.WithMessage(err, "failed to register constructor in the container"))
return nil, err
}
}
// Register the lifecycle in the container.
app.container.Provide(func() Lifecycle { return app.lifecycle })
// Execute invoke functions
for _, fn := range app.invokes {
err := app.container.Invoke(fn)
if err != nil {
err = emperror.WithStack(emperror.WithMessage(err, "failed to invoke function"))
return nil, err
}
}
return app, nil
}