-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsputnik.go
172 lines (129 loc) · 3.44 KB
/
sputnik.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
package sputnik
import (
"fmt"
"time"
)
// Configuration
type ServerConfiguration any
// Configuration Factory
type ConfFactory func(confName string, result any) error
type Sputnik struct {
// Configuration factory
cnfFact ConfFactory
// Block descriptor of used finisher
fbd BlockDescriptor
// Application blocks
// Order in the list defines order of creation and initialization
appBlocks []BlockDescriptor
// Block Factories of the process
blkFacts BlockFactories
// Server connector plug-in
cnt ServerConnector
// Timeout for connect/reconnect/check connection
to time.Duration
// Descriptor of used connector block
cnd BlockDescriptor
}
type SputnikOption func(sp *Sputnik)
func WithConfFactory(cf ConfFactory) SputnikOption {
return func(sp *Sputnik) {
sp.cnfFact = cf
}
}
func WithFinisher(fbd BlockDescriptor) SputnikOption {
return func(sp *Sputnik) {
sp.fbd = fbd
}
}
func WithAppBlocks(appBlocks []BlockDescriptor) SputnikOption {
return func(sp *Sputnik) {
sp.appBlocks = appBlocks
}
}
func WithBlockFactories(blkFacts BlockFactories) SputnikOption {
return func(sp *Sputnik) {
sp.blkFacts = blkFacts
}
}
func WithConnector(cnt ServerConnector, to time.Duration) SputnikOption {
return func(sp *Sputnik) {
sp.cnt = cnt
sp.to = to
}
}
func (sp *Sputnik) isValid() bool {
return sp.cnfFact != nil && sp.appBlocks != nil
}
func NewSputnik(opts ...SputnikOption) (*Sputnik, error) {
sp := new(Sputnik)
// Pre-sets
WithFinisher(FinisherDescriptor())(sp)
WithBlockFactories(DefaultFactories())(sp)
sp.cnd = BlockDescriptor{DefaultConnectorName, DefaultConnectorResponsibility}
for _, opt := range opts {
opt(sp)
}
ok := sp.isValid()
if !ok {
return nil, fmt.Errorf("not enough options for sputnik creation")
}
return sp, nil
}
// sputnik launcher
type Launch func() error
// sputnik shooter
type ShootDown func()
// Creates and initializes all blocks.
//
// If creation and initialization of any block failed:
//
// - Finish is called on all already initialized blocks
//
// - Order of finish - reversal of initialization
//
// = Returned error describes reason of the failure
//
// Otherwise returned 2 functions for sputnik management:
//
// - lfn - Launch of the sputnik , exit from this function will be
// after signal for shutdown of the process or after call of
// second returned function (see below)
//
// - st - ShootDown of sputnik - abort flight
func (sputnik Sputnik) Prepare() (lfn Launch, st ShootDown, err error) {
inr := new(initiator)
inr.sputnik = sputnik
err = inr.init(nil)
if err != nil {
return nil, nil, err
}
return inr.runInternal, inr.abort, nil
}
func (sputnik *Sputnik) createActiveBlocks() (activeBlocks, error) {
dscrs := make([]BlockDescriptor, 0)
dscrs = append(dscrs, sputnik.fbd)
if sputnik.cnt != nil {
dscrs = append(dscrs, ConnectorDescriptor())
}
dscrs = append(dscrs, sputnik.appBlocks...)
abls := make(activeBlocks, 0)
for _, bd := range dscrs {
abl, err := sputnik.createByDescr(bd)
if err != nil {
return nil, err
}
abls = append(abls, abl)
}
return abls, nil
}
func (sputnik *Sputnik) createByDescr(bd BlockDescriptor) (*activeBlock, error) {
b, err := sputnik.blkFacts.createByDescr(&bd)
if err != nil {
return nil, err
}
if !b.isValid(sputnik.cnt != nil) {
return nil, fmt.Errorf("invalid callbacks in block: name = %s resp = %s", bd.Name, bd.Responsibility)
}
abl := newActiveBlock(bd, b)
return &abl, nil
}