Skip to content

Commit 503c9f8

Browse files
committed
Implement Configure-Start-Stop module lifetime and non-global Registry object
container.Global is temporarily added until we start passing container during module initialization.
1 parent 21485e9 commit 503c9f8

File tree

103 files changed

+1305
-965
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+1305
-965
lines changed

framework/config/module/modconfig.go

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,18 @@ package modconfig
2828

2929
import (
3030
"fmt"
31-
"io"
3231
"reflect"
3332
"strings"
3433

3534
parser "github.com/foxcpp/maddy/framework/cfgparser"
3635
"github.com/foxcpp/maddy/framework/config"
37-
"github.com/foxcpp/maddy/framework/hooks"
36+
"github.com/foxcpp/maddy/framework/container"
3837
"github.com/foxcpp/maddy/framework/log"
3938
"github.com/foxcpp/maddy/framework/module"
4039
)
4140

4241
// createInlineModule is a helper function for config matchers that can create inline modules.
43-
func createInlineModule(preferredNamespace, modName string, args []string) (module.Module, error) {
42+
func createInlineModule(preferredNamespace, modName string) (module.Module, error) {
4443
var newMod module.FuncNewModule
4544
originalModName := modName
4645

@@ -61,26 +60,21 @@ func createInlineModule(preferredNamespace, modName string, args []string) (modu
6160
return nil, fmt.Errorf("unknown module: %s (namespace: %s)", originalModName, preferredNamespace)
6261
}
6362

64-
return newMod(modName, "", nil, args)
63+
return newMod(modName, "")
6564
}
6665

67-
// initInlineModule constructs "faked" config tree and passes it to module
66+
// configureInlineModule constructs "faked" config tree and passes it to module
6867
// Init function to make it look like it is defined at top-level.
6968
//
70-
// args must contain at least one argument, otherwise initInlineModule panics.
71-
func initInlineModule(modObj module.Module, globals map[string]interface{}, block config.Node) error {
72-
err := modObj.Init(config.NewMap(globals, block))
69+
// args must contain at least one argument, otherwise configureInlineModule panics.
70+
func configureInlineModule(modObj module.Module, args []string, globals map[string]interface{}, block config.Node) error {
71+
err := modObj.Configure(args, config.NewMap(globals, block))
7372
if err != nil {
7473
return err
7574
}
7675

77-
if closer, ok := modObj.(io.Closer); ok {
78-
hooks.AddHook(hooks.EventShutdown, func() {
79-
log.Debugf("close %s (%s)", modObj.Name(), modObj.InstanceName())
80-
if err := closer.Close(); err != nil {
81-
log.Printf("module %s (%s) close failed: %v", modObj.Name(), modObj.InstanceName(), err)
82-
}
83-
})
76+
if li, ok := modObj.(module.LifetimeModule); ok {
77+
container.Global.Lifetime.Add(li)
8478
}
8579

8680
return nil
@@ -117,11 +111,11 @@ func ModuleFromNode(preferredNamespace string, args []string, inlineCfg config.N
117111
if len(args) != 1 || inlineCfg.Children != nil {
118112
return parser.NodeErr(inlineCfg, "exactly one argument is required to use existing config block")
119113
}
120-
modObj, err = module.GetInstance(args[0][1:])
114+
modObj, err = container.Global.Modules.Get(args[0][1:])
121115
log.Debugf("%s:%d: reference %s", inlineCfg.File, inlineCfg.Line, args[0])
122116
} else {
123117
log.Debugf("%s:%d: new module %s %v", inlineCfg.File, inlineCfg.Line, args[0], args[1:])
124-
modObj, err = createInlineModule(preferredNamespace, args[0], args[1:])
118+
modObj, err = createInlineModule(preferredNamespace, args[0])
125119
}
126120
if err != nil {
127121
return err
@@ -144,7 +138,7 @@ func ModuleFromNode(preferredNamespace string, args []string, inlineCfg config.N
144138
reflect.ValueOf(moduleIface).Elem().Set(reflect.ValueOf(modObj))
145139

146140
if !referenceExisting {
147-
if err := initInlineModule(modObj, globals, inlineCfg); err != nil {
141+
if err := configureInlineModule(modObj, args[1:], globals, inlineCfg); err != nil {
148142
return err
149143
}
150144
}

framework/container/container.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
Maddy Mail Server - Composable all-in-one email server.
3+
Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
package container
20+
21+
import (
22+
"github.com/foxcpp/maddy/framework/log"
23+
"github.com/foxcpp/maddy/framework/module"
24+
)
25+
26+
type GlobalConfig struct {
27+
// StateDirectory contains the path to the directory that
28+
// should be used to store any data that should be
29+
// preserved between sessions.
30+
//
31+
// Value of this variable must not change after initialization
32+
// in cmd/maddy/main.go.
33+
StateDirectory string
34+
35+
// RuntimeDirectory contains the path to the directory that
36+
// should be used to store any temporary data.
37+
//
38+
// It should be preferred over os.TempDir, which is
39+
// global and world-readable on most systems, while
40+
// RuntimeDirectory can be dedicated for maddy.
41+
//
42+
// Value of this variable must not change after initialization
43+
// in cmd/maddy/main.go.
44+
RuntimeDirectory string
45+
46+
// LibexecDirectory contains the path to the directory
47+
// where helper binaries should be searched.
48+
//
49+
// Value of this variable must not change after initialization
50+
// in cmd/maddy/main.go.
51+
LibexecDirectory string
52+
}
53+
54+
type C struct {
55+
Config GlobalConfig
56+
DefaultLogger log.Logger
57+
Modules *module.Registry
58+
Lifetime *module.LifetimeTracker
59+
}
60+
61+
func New() *C {
62+
return &C{
63+
DefaultLogger: log.DefaultLogger,
64+
Modules: module.NewRegistry(log.DefaultLogger.Sublogger("registry")),
65+
Lifetime: module.NewLifetime(log.DefaultLogger.Sublogger("lifetime")),
66+
}
67+
}
68+
69+
// Global is the default instance while refactoring is in progress.
70+
var Global *C

framework/log/log.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,17 @@ func (l Logger) log(debug bool, s string) {
224224
// Logging is disabled - do nothing.
225225
}
226226

227+
func (l Logger) Sublogger(name string) Logger {
228+
if l.Name != "" {
229+
name = l.Name + "/" + name
230+
}
231+
return Logger{
232+
Out: l.Out,
233+
Name: name,
234+
Debug: l.Debug,
235+
}
236+
}
237+
227238
// DefaultLogger is the global Logger object that is used by
228239
// package-level logging functions.
229240
//

framework/module/delivery_target.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ import (
3333
// Modules implementing this interface should be registered with "target."
3434
// prefix in name.
3535
type DeliveryTarget interface {
36-
// Start starts the delivery of a new message.
36+
// StartDelivery starts the delivery of a new message.
3737
//
3838
// The domain part of the MAIL FROM address is assumed to be U-labels with
3939
// NFC normalization and case-folding applied. The message source should
4040
// ensure that by calling address.CleanDomain if necessary.
41-
Start(ctx context.Context, msgMeta *MsgMetadata, mailFrom string) (Delivery, error)
41+
StartDelivery(ctx context.Context, msgMeta *MsgMetadata, mailFrom string) (Delivery, error)
4242
}
4343

4444
type Delivery interface {
@@ -54,7 +54,7 @@ type Delivery interface {
5454
// however. They should be silently ignored.
5555
//
5656
// Implementation should do as much checks as possible here and reject
57-
// recipients that can't be used. Note: MsgMetadata object passed to Start
57+
// recipients that can't be used. Note: MsgMetadata object passed to StartDelivery
5858
// contains BodyLength field. If it is non-zero, it can be used to check
5959
// storage quota for the user before Body.
6060
AddRcpt(ctx context.Context, rcptTo string, opts smtp.RcptOptions) error

framework/module/dummy.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ func (d *Dummy) InstanceName() string {
5454
return d.instName
5555
}
5656

57-
func (d *Dummy) Init(_ *config.Map) error {
57+
func (d *Dummy) Configure(_ []string, _ *config.Map) error {
5858
return nil
5959
}
6060

61-
func (d *Dummy) Start(ctx context.Context, msgMeta *MsgMetadata, mailFrom string) (Delivery, error) {
61+
func (d *Dummy) StartDelivery(ctx context.Context, msgMeta *MsgMetadata, mailFrom string) (Delivery, error) {
6262
return dummyDelivery{}, nil
6363
}
6464

@@ -81,7 +81,7 @@ func (dd dummyDelivery) Commit(ctx context.Context) error {
8181
}
8282

8383
func init() {
84-
Register("dummy", func(_, instName string, _, _ []string) (Module, error) {
84+
Register("dummy", func(_, instName string) (Module, error) {
8585
return &Dummy{instName: instName}, nil
8686
})
8787
}

framework/module/instances.go

Lines changed: 0 additions & 105 deletions
This file was deleted.

0 commit comments

Comments
 (0)