package main import ( "context" "crypto/tls" "flag" "math/rand" "net" "net/http" "os" "os/signal" "sync" "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")) } wg := &sync.WaitGroup{} go setupQuic(ctx, wg, s, scfg) go setupTLS(ctx, wg, s, scfg) go setupHTTP(ctx, wg, 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() wg.Wait() } func setupHTTP(ctx context.Context, wg *sync.WaitGroup, s *Server, scfg Config) { // listen on HTTP listener l, err := net.Listen("tcp", scfg.WebAddr) if err != nil { ln.FatalErr(ctx, err, ln.Action("listening on HTTP port"), ln.F{"addr": scfg.WebAddr}) } defer l.Close() hs := &http.Server{ Handler: s.Manager.HTTPHandler(http.HandlerFunc(insecureRedirect)), Addr: scfg.WebAddr, } go ln.FatalErr(ctx, hs.Serve(l)) for { select { case <-ctx.Done(): ln.Log(ctx, ln.F{"kind": "http"}, ln.Action("shutdown signal recieved")) hs.SetKeepAlivesEnabled(false) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() hs.Shutdown(ctx) wg.Done() return } } } func setupQuic(ctx context.Context, wg *sync.WaitGroup, s *Server, scfg Config) { qs := &h2quic.Server{ Server: &http.Server{ Handler: middleware.Trace(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()) wg.Add(1) for { select { case <-ctx.Done(): ln.Log(ctx, ln.F{"kind": "quic"}, ln.Action("shutdown signal recieved")) qs.SetKeepAlivesEnabled(false) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() qs.Shutdown(ctx) wg.Done() return } } } func setupTLS(ctx context.Context, wg *sync.WaitGroup, s *Server, scfg Config) { hs := &http.Server{ Handler: middleware.Trace(s), Addr: scfg.SSLAddr, TLSConfig: &tls.Config{ GetCertificate: s.GetCertificate, }, IdleTimeout: 5 * time.Minute, ReadHeaderTimeout: time.Second, } go ln.FatalErr(context.Background(), hs.ListenAndServeTLS("", "")) wg.Add(1) for { select { case <-ctx.Done(): ln.Log(ctx, ln.F{"kind": "https"}, ln.Action("shutdown signal recieved")) hs.SetKeepAlivesEnabled(false) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() hs.Shutdown(ctx) wg.Done() return } } }