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 } } }