-
Notifications
You must be signed in to change notification settings - Fork 11
/
framework.go
187 lines (147 loc) · 4.82 KB
/
framework.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package glacier
import (
"fmt"
"reflect"
"sync"
"time"
"github.com/mylxsw/glacier/infra"
"github.com/mylxsw/go-ioc"
)
// framework is the Glacier framework
type framework struct {
version string
startTime time.Time
cc ioc.Container
logger infra.Logger
lock sync.RWMutex
providers []*providerEntry
services []*serviceEntry
// asyncRunnerCount 异步任务执行器数量
asyncRunnerCount int
asyncJobs []asyncJob
asyncJobChannel chan asyncJob
init func(fc infra.FlagContext) error
preBinder func(binder infra.Binder)
beforeServerStop func(resolver infra.Resolver) error
onServerReadyHooks []namedFunc
gracefulBuilder func() infra.Graceful
flagContextInit interface{}
singletons []interface{}
prototypes []interface{}
status Status
nodes infra.GraphvizNodes
nodeLock sync.Mutex
}
// New a new framework server
func New(version string, asyncJobRunnerCount int) infra.Glacier {
impl := &framework{startTime: time.Now()}
impl.version = version
impl.singletons = make([]interface{}, 0)
impl.prototypes = make([]interface{}, 0)
impl.providers = make([]*providerEntry, 0)
impl.services = make([]*serviceEntry, 0)
impl.asyncJobs = make([]asyncJob, 0)
impl.asyncRunnerCount = asyncJobRunnerCount
impl.status = Unknown
impl.flagContextInit = func(flagCtx infra.FlagContext) infra.FlagContext { return flagCtx }
impl.nodes = make(infra.GraphvizNodes, 0)
impl.nodes = append(impl.nodes, &infra.GraphvizNode{Name: "start"})
return impl
}
func (impl *framework) pushGraphvizNode(name string, async bool, parent ...*infra.GraphvizNode) *infra.GraphvizNode {
if !infra.DEBUG {
return nil
}
impl.nodeLock.Lock()
defer impl.nodeLock.Unlock()
if len(parent) == 0 {
parentNode := impl.nodes[len(impl.nodes)-1]
if parentNode.Type != infra.GraphvizNodeTypeNode {
if len(parentNode.ParentNode) > 0 {
parentNode = parentNode.ParentNode[0]
}
}
parent = []*infra.GraphvizNode{parentNode}
}
node := infra.GraphvizNode{Name: name, ParentNode: parent, Async: async, Type: infra.GraphvizNodeTypeNode}
impl.nodes = append(impl.nodes, &node)
return &node
}
func (impl *framework) updateGlacierStatus(status Status) {
if infra.DEBUG {
impl.pushGraphvizNode(fmt.Sprintf("update framework status to %s", status.String()), false)
}
impl.lock.Lock()
defer impl.lock.Unlock()
impl.status = status
}
func (impl *framework) WithFlagContext(fn interface{}) infra.Glacier {
fnType := reflect.TypeOf(fn)
if fnType.Kind() != reflect.Func || fnType.NumOut() != 1 || fnType.Out(0) != reflect.TypeOf(infra.FlagContext(nil)) {
panic("[glacier] invalid argument for WithFlagContext: must be a function like `func(...) infra.FlagContext`")
}
impl.flagContextInit = fn
return impl
}
// Graceful 设置优雅停机实现
func (impl *framework) Graceful(builder func() infra.Graceful) infra.Glacier {
impl.gracefulBuilder = builder
return impl
}
// SetLogger set default logger for glacier
func (impl *framework) SetLogger(logger infra.Logger) infra.Glacier {
impl.logger = logger
return impl
}
// Singleton add a singleton instance to container
func (impl *framework) Singleton(ins ...interface{}) infra.Glacier {
if impl.status >= Initialized {
panic("[glacier] can not invoke this method after Glacier has been initialize")
}
impl.singletons = append(impl.singletons, ins...)
return impl
}
// Prototype add a prototype to container
func (impl *framework) Prototype(ins ...interface{}) infra.Glacier {
if impl.status >= Initialized {
panic("[glacier] can not invoke this method after Glacier has been initialize")
}
impl.prototypes = append(impl.prototypes, ins...)
return impl
}
// Resolve is a proxy to container's Resolve function
func (impl *framework) Resolve(resolver interface{}) error {
return impl.cc.Resolve(resolver)
}
// MustResolve is a proxy to container's MustResolve function
func (impl *framework) MustResolve(resolver interface{}) {
impl.cc.MustResolve(resolver)
}
// Container return container instance
func (impl *framework) Container() infra.Container {
return impl.cc
}
// Resolver return container instance
func (impl *framework) Resolver() infra.Resolver {
return impl.cc
}
// Binder return container instance
func (impl *framework) Binder() infra.Binder {
return impl.cc
}
func (impl *framework) shouldLoadModule(pValue reflect.Value) bool {
shouldLoadMethod := pValue.MethodByName("ShouldLoad")
if shouldLoadMethod.IsValid() && !shouldLoadMethod.IsZero() {
res, err := impl.cc.Call(shouldLoadMethod)
if err != nil {
panic(fmt.Errorf("[glacier] call %s.ShouldLoad method failed: %v", pValue.Kind().String(), err))
}
if len(res) > 1 {
if err, ok := res[1].(error); ok && err != nil {
panic(fmt.Errorf("[glacier] call %s.Should method return an error value: %v", pValue.Kind().String(), err))
}
}
return res[0].(bool)
}
return true
}