-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.go
148 lines (130 loc) · 3.58 KB
/
main.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
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"
"sync"
"time"
"github.com/decred/dcrlnlpd/internal/version"
"github.com/decred/dcrlnlpd/server"
"github.com/gorilla/mux"
)
func indexHandler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "%s\n%s\n", appName, version.String())
}
func newInfoHandler(server *server.Server) func(w http.ResponseWriter, req *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
if !isReqFromLocalhost(req) {
w.WriteHeader(http.StatusForbidden)
log.Warnf("Forbidden request for info from %s", requestAddr(req))
return
}
info, err := server.FetchManagedChannels(req.Context())
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "error fetching managed channels: %v\n", err)
log.Errorf("Unable to fetch managed channels: %v", err)
return
}
err = json.NewEncoder(w).Encode(info)
if err != nil {
log.Errorf("Unable to encode info: %v", err)
}
}
}
func handler(s *server.Server) http.Handler {
router := mux.NewRouter().StrictSlash(true)
router.Methods("GET").Path("/").Name("index").HandlerFunc(indexHandler)
router.Methods("GET").Path("/info").Name("info").HandlerFunc(newInfoHandler(s))
server.NewV1Handler(s, router)
logRouterConfig(router)
return router
}
func _main() error {
// Load configuration and parse command line. This function also
// initializes logging and configures it accordingly.
cfg, _, err := loadConfig()
if err != nil {
return err
}
// Start the main context for the app
ctx := shutdownListener()
var wg sync.WaitGroup
log.Infof("Initing %s v%s on %s", appName, version.String(), cfg.activeNet)
// Enable http profiling server if requested.
if cfg.Profile != "" {
go func() {
listenAddr := cfg.Profile
log.Infof("Creating profiling server "+
"listening on %s", listenAddr)
profileRedirect := http.RedirectHandler("/debug/pprof",
http.StatusSeeOther)
http.Handle("/", profileRedirect)
err := http.ListenAndServe(listenAddr, nil)
if err != nil && !errors.Is(err, context.Canceled) {
log.Errorf("Fatal error running the http profiler: %v", err)
requestShutdown()
}
}()
}
// Create and start the server server.
svrCfg, err := cfg.serverConfig()
if err != nil {
return err
}
drsvr, err := server.New(svrCfg)
if err != nil {
return err
}
wg.Add(1)
go func() {
// Errors other than context canceled are fatal.
err := drsvr.Run(ctx)
if err != nil && !errors.Is(err, context.Canceled) {
log.Errorf("Fatal error running the server instance: %v", err)
requestShutdown()
}
wg.Done()
}()
// Create and start all http listening interfaces.
svr := &http.Server{
Handler: handler(drsvr),
}
listeners, err := cfg.listeners()
if err != nil {
log.Error(err.Error())
return err
}
for _, l := range listeners {
wg.Add(1)
go func(l net.Listener) {
log.Infof("Listening on %s", l.Addr().String())
svr.Serve(l)
wg.Done()
}(l)
}
// Wait until the app is commanded to shutdown to close the server.
<-ctx.Done()
// Wait up to 5 seconds until all connections are gracefully closed
// before terminating the process.
timeout, cancel := context.WithTimeout(context.Background(), time.Second*5)
err = svr.Shutdown(timeout)
cancel() // Prevent context leak.
if errors.Is(err, context.Canceled) {
log.Warnf("Terminating process before all connections were done")
}
// Wait for all goroutines to finish.
wg.Wait()
return nil
}
func main() {
if err := _main(); err != nil && err != errCmdDone {
fmt.Println(err)
os.Exit(1)
}
}