-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapplication.go
168 lines (142 loc) · 3.61 KB
/
application.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
package bone
import (
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/facebookgo/inject"
"google.golang.org/grpc"
)
// ApplicationOptions represents the options to create Bone Application
// instance.
type ApplicationOptions struct {
// Basic part
Debug bool
// HTTP part
HttpEnable bool
HttpHost string
HttpPort int
// gRPC part
GrpcEnable bool
GrpcHost string
GrpcPort int
}
// DefaultApplicationOptions returns the default options to create Bone
// Application instance. Enable HTTP Server and disable gRPC Server by default.
func DefaultApplicationOptions() *ApplicationOptions {
return &ApplicationOptions{
Debug: true,
HttpEnable: true,
HttpHost: "127.0.0.1",
HttpPort: 8080,
GrpcEnable: false, // Disable gRPC by default
GrpcHost: "127.0.0.1",
GrpcPort: 50051,
}
}
// Application defines the struct of Bone Application.
type Application struct {
o *ApplicationOptions
g *inject.Graph
httpRouter *Router
grpcServer *grpc.Server
}
// NewApplication returns the instance of Bone Application.
func NewApplication(options *ApplicationOptions) *Application {
app := &Application{
o: options,
g: &inject.Graph{},
httpRouter: NewRouter(),
grpcServer: grpc.NewServer(),
}
if app.o.Debug {
log.Println("WARNING: Running in debug mode.")
}
// Provide core components
app.Provide(&inject.Object{Name: "application.router", Value: app.httpRouter})
app.Provide(&inject.Object{Name: "application.grpc", Value: app.grpcServer})
return app
}
// Provide is a low-level API to provide *inject.Object to inject Bone
// Application. Do NOT use it except must to.
func (app *Application) Provide(obj *inject.Object) error {
return app.g.Provide(obj)
}
func (app *Application) register(component Component) {
if app.o.Debug {
log.Println("Registering Component: " + component.Name())
}
if err := component.Register(); err != nil {
panic(err)
}
}
func (app *Application) unregister(component Component) {
if app.o.Debug {
log.Println("Unregistering Component: " + component.Name())
}
component.Unregister()
}
// Use injects the components to the Bone Application, combines other
// component into a interconnected system.
func (app *Application) Use(components ...Component) {
for _, component := range components {
err := component.Init()
if err != nil {
panic(err)
}
app.g.Provide(&inject.Object{Name: component.Name(), Value: component})
}
if err := app.g.Populate(); err != nil {
panic(err)
}
for _, component := range components {
app.register(component)
}
go func() {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-ch
defer os.Exit(0)
if app.o.Debug {
defer log.Println("Application stopped")
}
for _, component := range components {
defer app.unregister(component)
}
}()
}
// Run starts up the Bone Application.
func (app *Application) Run() {
if app.o.HttpEnable {
go func() {
addr := fmt.Sprintf("%s:%d", app.o.HttpHost, app.o.HttpPort)
s := &http.Server{
Addr: addr,
Handler: app.httpRouter,
}
if app.o.Debug {
log.Println("HTTP Server listens on " + addr)
}
s.ListenAndServe()
}()
}
if app.o.GrpcEnable {
go func() {
addr := fmt.Sprintf("%s:%d", app.o.GrpcHost, app.o.GrpcPort)
lis, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
if app.o.Debug {
log.Println("GRPC Server listens on " + addr)
}
app.grpcServer.Serve(lis)
}()
}
select {
// Dothing to do, just block here, in order to keep this application on.
}
}