187 lines
3.8 KiB
Go
187 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"flag"
|
|
"fmt"
|
|
"math/rand"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
|
|
_ "git.xeserv.us/xena/route/internal"
|
|
"git.xeserv.us/xena/route/internal/middleware"
|
|
"git.xeserv.us/xena/route/internal/routecrypto"
|
|
"github.com/Xe/ln"
|
|
"github.com/caarlos0/env"
|
|
"github.com/facebookgo/flagenv"
|
|
_ "github.com/joho/godotenv/autoload"
|
|
"github.com/lucas-clemente/quic-go/h2quic"
|
|
)
|
|
|
|
var (
|
|
sslCertKey = flag.String("ssl-cert-key", "", "if set encrypt SSL certs with this key")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
flagenv.Parse()
|
|
rand.Seed(time.Now().Unix())
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
certKey, err := routecrypto.ParseKey(*sslCertKey)
|
|
if err != nil {
|
|
ln.FatalErr(ctx, err, ln.Action("parse cert key"))
|
|
}
|
|
|
|
scfg := Config{}
|
|
err = env.Parse(&scfg)
|
|
if err != nil {
|
|
ln.FatalErr(ctx, err, ln.Action("parsing environment for config"))
|
|
}
|
|
scfg.CertKey = certKey
|
|
|
|
s, err := New(scfg)
|
|
if err != nil {
|
|
ln.FatalErr(ctx, err, ln.Action("create server instance"))
|
|
}
|
|
|
|
go setupQuic(ctx, s, scfg)
|
|
go setupTLS(ctx, s, scfg)
|
|
go setupHTTP(ctx, s, scfg)
|
|
|
|
ch := make(chan os.Signal, 2)
|
|
|
|
go func() {
|
|
val := <-ch
|
|
|
|
ln.Log(ctx, ln.F{"signal": val.String()}, ln.Action("signal recieved"))
|
|
cancel()
|
|
}()
|
|
|
|
signal.Notify(ch, os.Interrupt)
|
|
|
|
<-ctx.Done()
|
|
|
|
fmt.Printf("%s is now waiting for final shutdown, press ^C again to kill it now\n", os.Args[0])
|
|
time.Sleep(30 * time.Second)
|
|
}
|
|
|
|
func setupHTTP(ctx context.Context, s *Server, scfg Config) {
|
|
f := ln.F{
|
|
"kind": "http",
|
|
"addr": scfg.WebAddr,
|
|
}
|
|
|
|
// listen on HTTP listener
|
|
l, err := net.Listen("tcp", scfg.WebAddr)
|
|
if err != nil {
|
|
ln.FatalErr(ctx, err, f, ln.Action("listening on HTTP port"))
|
|
}
|
|
defer l.Close()
|
|
|
|
hs := &http.Server{
|
|
Handler: s.Manager.HTTPHandler(http.HandlerFunc(insecureRedirect)),
|
|
Addr: scfg.WebAddr,
|
|
}
|
|
|
|
go ln.FatalErr(ctx, hs.Serve(l))
|
|
ln.Log(ctx, f, ln.Action("http server listen"))
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
ln.Log(ctx, f, ln.Action("shutdown signal recieved"))
|
|
hs.SetKeepAlivesEnabled(false)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
hs.Shutdown(ctx)
|
|
|
|
ln.Log(ctx, f, ln.Action("shutdown complete"))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupQuic(ctx context.Context, s *Server, scfg Config) {
|
|
f := ln.F{
|
|
"kind": "quic",
|
|
"addr": scfg.QuicAddr,
|
|
}
|
|
|
|
qs := &h2quic.Server{
|
|
Server: &http.Server{
|
|
Handler: middleware.Trace("http-quic")(s),
|
|
Addr: scfg.QuicAddr,
|
|
TLSConfig: &tls.Config{
|
|
GetCertificate: s.GetCertificate,
|
|
},
|
|
|
|
IdleTimeout: 5 * time.Minute,
|
|
ReadHeaderTimeout: time.Second,
|
|
},
|
|
}
|
|
|
|
s.QuicServer = qs
|
|
|
|
go ln.FatalErr(context.Background(), qs.ListenAndServe())
|
|
ln.Log(ctx, f, ln.Action("http server listen"))
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
ln.Log(ctx, f, ln.Action("shutdown signal recieved"))
|
|
qs.SetKeepAlivesEnabled(false)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
qs.Shutdown(ctx)
|
|
|
|
ln.Log(ctx, f, ln.Action("shutdown complete"))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func setupTLS(ctx context.Context, s *Server, scfg Config) {
|
|
f := ln.F{
|
|
"kind": "https",
|
|
"addr": scfg.SSLAddr,
|
|
}
|
|
|
|
hs := &http.Server{
|
|
Handler: middleware.Trace("https")(s),
|
|
Addr: scfg.SSLAddr,
|
|
TLSConfig: &tls.Config{
|
|
GetCertificate: s.GetCertificate,
|
|
},
|
|
|
|
IdleTimeout: 5 * time.Minute,
|
|
ReadHeaderTimeout: time.Second,
|
|
}
|
|
|
|
go ln.FatalErr(context.Background(), hs.ListenAndServeTLS("", ""))
|
|
ln.Log(ctx, f, ln.Action("http server listen"))
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
ln.Log(ctx, f, ln.Action("shutdown signal recieved"))
|
|
hs.SetKeepAlivesEnabled(false)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
hs.Shutdown(ctx)
|
|
|
|
ln.Log(ctx, f, ln.Action("shutdown complete"))
|
|
return
|
|
}
|
|
}
|
|
}
|