/
smf4go.go
206 lines (151 loc) · 5.55 KB
/
smf4go.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package smf4go
import (
"sync"
"sync/atomic"
"github.com/libs4go/errors"
"github.com/libs4go/scf4go"
"github.com/libs4go/sdi4go"
"github.com/libs4go/slf4go"
)
// ScopeOfAPIError .
const errVendor = "smf4go"
// errors
var (
ErrInternal = errors.New("the internal error", errors.WithVendor(errVendor))
ErrAgent = errors.New("agent implement not found", errors.WithVendor(errVendor))
ErrExists = errors.New("target resource exists", errors.WithVendor(errVendor))
ErrNotFound = errors.New("target resource not found", errors.WithVendor(errVendor))
)
// Service smf4go service base interface has nothing
type Service interface{}
// Runnable smf4go service base interface has nothing
type Runnable interface {
Service
Start() error
}
// ServiceRegisterEntry .
type ServiceRegisterEntry struct {
Name string // service name
Service Service // service impl
}
// MeshBuilder .
type MeshBuilder interface {
RegisterService(extensionName string, serviceName string) error
RegisterExtension(extension Extension) error
Start(config scf4go.Config) error
FindService(name string, service interface{})
}
// Extension smf4go service handle extension
type Extension interface {
Name() string // extension name
Begin(config scf4go.Config, builder MeshBuilder) error
CreateSerivce(serviceName string, config scf4go.Config) (Service, error)
End() error
}
type meshBuilderImpl struct {
slf4go.Logger // mixin logger
injector sdi4go.Injector // injector context
registers map[string]string // registers services
orderServices []string //order service name
extensions map[string]Extension // extensions
orderExtensions []Extension // order extension names
started atomic.Value // started
}
// NewMeshBuilder create new mesh builder
func NewMeshBuilder() MeshBuilder {
impl := &meshBuilderImpl{
Logger: slf4go.Get("smf4go"),
registers: make(map[string]string),
extensions: make(map[string]Extension),
injector: sdi4go.New(),
}
impl.started.Store(false)
return impl
}
func (builder *meshBuilderImpl) RegisterService(extensionName string, serviceName string) error {
_, ok := builder.registers[serviceName]
if ok {
return errors.Wrap(ErrExists, "service %s exists", serviceName)
}
if _, ok := builder.extensions[extensionName]; !ok {
return errors.Wrap(ErrNotFound, "extension %s not found", extensionName)
}
builder.registers[serviceName] = extensionName
builder.orderServices = append(builder.orderServices, serviceName)
return nil
}
func (builder *meshBuilderImpl) RegisterExtension(extension Extension) error {
_, ok := builder.extensions[extension.Name()]
if ok {
return errors.Wrap(ErrExists, "extension %s exists", extension.Name())
}
builder.extensions[extension.Name()] = extension
builder.orderExtensions = append(builder.orderExtensions, extension)
return nil
}
func (builder *meshBuilderImpl) FindService(name string, service interface{}) {
if !builder.started.Load().(bool) {
builder.D("mesh builder processing, FindService not valid")
return
}
builder.injector.Create(name, service)
}
func (builder *meshBuilderImpl) Start(config scf4go.Config) error {
for _, extension := range builder.extensions {
subconfig := config.SubConfig("smf4go", "extension", extension.Name())
builder.D("call extension {@ext} initialize routine", extension.Name())
if err := extension.Begin(subconfig, builder); err != nil {
return errors.Wrap(err, "start extension %s error", extension.Name())
}
builder.D("call extension {@ext} initialize routine -- success", extension.Name())
}
var services []ServiceRegisterEntry
for _, serviceName := range builder.orderServices {
subconfig := config.SubConfig("smf4go", "service", serviceName)
extension := builder.extensions[builder.registers[serviceName]]
builder.D("create service {@service} by extension {@ext}", serviceName, extension.Name())
service, err := extension.CreateSerivce(serviceName, subconfig)
if err != nil {
return errors.Wrap(err, "create service %s by extension %s error", serviceName, extension.Name())
}
builder.D("create service {@service} by extension {@ext} -- success", serviceName, extension.Name())
services = append(services, ServiceRegisterEntry{Name: serviceName, Service: service})
}
for _, entry := range services {
builder.injector.Bind(entry.Name, sdi4go.Singleton(entry.Service))
}
for _, entry := range services {
builder.D("bind service {@service}", entry.Name)
if err := builder.injector.Inject(entry.Service); err != nil {
return errors.Wrap(err, "service %s bind error", entry.Name)
}
builder.D("bind service {@service} -- success", entry.Name)
}
for _, extension := range builder.extensions {
builder.D("call extension {@ext} finally routine", extension.Name())
if err := extension.End(); err != nil {
return errors.Wrap(err, "extension %s finally routine error", extension.Name())
}
builder.D("call extension {@ext} finally routine -- success", extension.Name())
}
for _, entry := range services {
if runnable, ok := entry.Service.(Runnable); ok {
builder.D("start runnable service {@service}", entry.Name)
if err := runnable.Start(); err != nil {
return errors.Wrap(err, "start service %s error", entry.Name)
}
builder.D("start runnable service {@service} -- success", entry.Name)
}
}
builder.started.Store(true)
return nil
}
var meshBuilder MeshBuilder
var once sync.Once
// Builder get mesh builder instance
func Builder() MeshBuilder {
once.Do(func() {
meshBuilder = NewMeshBuilder()
})
return meshBuilder
}