/
app.go
136 lines (116 loc) · 3.21 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 flamingo
import (
"context"
"fmt"
"net/http"
"os"
"time"
"flamingo.me/flamingo/core/cmd"
"flamingo.me/flamingo/core/zap"
"flamingo.me/flamingo/framework"
"flamingo.me/flamingo/framework/config"
"flamingo.me/flamingo/framework/dingo"
"flamingo.me/flamingo/framework/event"
"flamingo.me/flamingo/framework/flamingo"
"flamingo.me/flamingo/framework/router"
"github.com/spf13/cobra"
)
type (
appmodule struct {
root *config.Area
router *router.Router
server *http.Server
logger flamingo.Logger
}
// AppShutdownEvent is dispatched on app startup
AppStartupEvent struct {
AppModule dingo.Module
}
// AppShutdownEvent is dispatched on app shutdown
AppShutdownEvent struct {
AppModule dingo.Module
}
)
func (a *appmodule) Inject(root *config.Area, router *router.Router, logger flamingo.Logger) {
a.root = root
a.router = router
a.logger = logger
a.server = &http.Server{
Addr: ":3322",
Handler: a.router,
}
}
// Configure dependency injection
func (a *appmodule) Configure(injector *dingo.Injector) {
injector.BindMulti((*event.Subscriber)(nil)).ToInstance(a)
//pass a function that returns the Command
injector.BindMulti(new(cobra.Command)).ToProvider(func() *cobra.Command {
return serveProvider(a, a.logger)
})
}
func serveProvider(a *appmodule, logger flamingo.Logger) *cobra.Command {
var addr string
cmd := &cobra.Command{
Use: "serve",
Short: "Default serve command - starts on Port 3322",
Run: func(cmd *cobra.Command, args []string) {
a.router.Init(a.root)
logger.Info(fmt.Sprintf("Starting HTTP Server at %s .....", addr))
err := a.server.ListenAndServe()
if err != nil {
if err == http.ErrServerClosed {
logger.Error(err)
} else {
logger.Fatal("unexpected error in serving:", err)
}
}
},
}
cmd.Flags().StringVarP(&a.server.Addr, "addr", "a", ":3322", "addr on which flamingo runs")
return cmd
}
func (a *appmodule) Notify(event event.Event) {
switch event.(type) {
case *AppShutdownEvent:
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
a.logger.Info("Shutdown server on ", a.server.Addr)
err := a.server.Shutdown(ctx)
if err != nil {
a.logger.Error("unexpected error on server shutdown: ", err)
}
}
}
type option func(config *appconfig)
func ConfigDir(configdir string) option {
return func(config *appconfig) {
config.configDir = configdir
}
}
type appconfig struct {
configDir string
}
// App is a simple app-runner for flamingo
func App(modules []dingo.Module, options ...option) {
app := new(appmodule)
root := config.NewArea("root", modules)
root.Modules = append([]dingo.Module{
new(framework.InitModule),
new(framework.Module),
new(zap.Module),
new(cmd.Module),
}, root.Modules...)
root.Modules = append(root.Modules, app)
cfg := &appconfig{
configDir: "config",
}
for _, option := range options {
option(cfg)
}
config.Load(root, cfg.configDir)
cmd := root.Injector.GetAnnotatedInstance(new(cobra.Command), "flamingo").(*cobra.Command)
root.Injector.GetInstance(new(router.EventRouterProvider)).(router.EventRouterProvider)().Dispatch(context.Background(), &flamingo.AppStartupEvent{AppModule: nil})
if err := cmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}