-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
118 lines (103 loc) · 2.95 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
package main
import (
"context"
_ "embed"
"errors"
"html/template"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/akash-network/rpc-proxy/internal/config"
"github.com/akash-network/rpc-proxy/internal/proxy"
"github.com/akash-network/rpc-proxy/internal/seed"
"golang.org/x/crypto/acme/autocert"
)
//go:embed index.html
var index []byte
func main() {
cfg := config.Must()
am := autocert.Manager{
Cache: autocert.DirCache("."),
Prompt: autocert.AcceptTOS,
}
if addr := cfg.AutocertEmail; addr != "" {
am.Email = addr
}
if hosts := cfg.AutocertHosts; len(hosts) > 0 {
am.HostPolicy = autocert.HostWhitelist(hosts...)
}
rpcListener := make(chan seed.Seed, 1)
restListener := make(chan seed.Seed, 1)
updater := seed.New(cfg, rpcListener, restListener)
rpcProxyHandler := proxy.New(proxy.RPC, rpcListener, cfg)
restProxyHandler := proxy.New(proxy.Rest, restListener, cfg)
ctx, proxyCtxCancel := context.WithCancel(context.Background())
defer proxyCtxCancel()
updater.Start(ctx)
rpcProxyHandler.Start(ctx)
restProxyHandler.Start(ctx)
indexTpl := template.Must(template.New("stats").Parse(string(index)))
m := http.NewServeMux()
m.Handle("/health/ready", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !rpcProxyHandler.Ready() || !restProxyHandler.Ready() {
w.WriteHeader(http.StatusServiceUnavailable)
}
}))
m.Handle("/health/live", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !rpcProxyHandler.Live() || !restProxyHandler.Live() {
w.WriteHeader(http.StatusServiceUnavailable)
}
}))
m.Handle("/rpc", rpcProxyHandler)
m.Handle("/rest", restProxyHandler)
m.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := indexTpl.Execute(w, map[string][]proxy.ServerStat{
"RPC": rpcProxyHandler.Stats(),
"Rest": restProxyHandler.Stats(),
}); err != nil {
slog.Error("could render stats", "err", err)
}
}))
srv := &http.Server{
Addr: cfg.Listen,
Handler: m,
TLSConfig: am.TLSConfig(),
ReadTimeout: time.Second * 10,
IdleTimeout: time.Second * 10,
WriteTimeout: time.Second * 10,
}
if cfg.TLSCert != "" && cfg.TLSKey != "" {
srv.TLSConfig = nil
}
go func() {
slog.Info("starting server", "addr", cfg.Listen)
var err error
// TODO: find a better way to set this.
if cfg.Listen == ":https" {
err = srv.ListenAndServeTLS(cfg.TLSCert, cfg.TLSKey)
} else {
err = srv.ListenAndServe()
}
if err != nil {
if errors.Is(err, http.ErrServerClosed) {
slog.Info("server shut down")
return
}
slog.Error("could not start server", "err", err)
os.Exit(1)
}
}()
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-done
proxyCtxCancel()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
slog.Error("could not close server", "err", err)
os.Exit(1)
}
}