keyproofs/main.go

213 lines
4.7 KiB
Go
Raw Permalink Normal View History

2020-11-23 13:58:19 -07:00
package main
import (
"context"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
lru "github.com/hashicorp/golang-lru"
_ "github.com/joho/godotenv/autoload"
"github.com/rs/cors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"gosrc.io/xmpp"
"github.com/sour-is/keyproofs/pkg/cache"
"github.com/sour-is/keyproofs/pkg/config"
2020-11-23 20:49:53 -07:00
"github.com/sour-is/keyproofs/pkg/graceful"
2020-11-23 13:58:19 -07:00
"github.com/sour-is/keyproofs/pkg/keyproofs"
)
var (
// AppVersion Application Version Number
AppVersion string
// AppBuild Application Build Hash
BuildHash string
// AppDate Application Build Date
BuildDate string
)
func main() {
2020-11-23 20:49:53 -07:00
log := zerolog.New(zerolog.NewConsoleWriter()).
With().
Timestamp().
Caller().
Logger()
2020-11-23 13:58:19 -07:00
ctx := context.Background()
ctx = log.WithContext(ctx)
2020-11-23 20:49:53 -07:00
ctx = graceful.WithInterupt(ctx)
ctx, _ = graceful.WithWaitGroup(ctx)
2020-11-23 13:58:19 -07:00
cfg := config.New()
cfg.Set("app-name", "KeyProofs")
cfg.Set("app-version", AppVersion)
cfg.Set("build-hash", BuildHash)
cfg.Set("build-date", BuildDate)
ctx = cfg.Apply(ctx)
if err := run(ctx); err != nil {
2020-11-23 20:49:53 -07:00
log.Error().Stack().Err(err).Msg("Application Failed")
2020-11-23 13:58:19 -07:00
os.Exit(1)
}
}
func run(ctx context.Context) error {
log := log.Ctx(ctx)
2020-11-23 20:49:53 -07:00
wg := graceful.WaitGroup(ctx)
2020-11-23 13:58:19 -07:00
// derive baseURL from listener options
listen := env("HTTP_LISTEN", ":9061")
host, _ := os.Hostname()
if strings.HasPrefix(listen, ":") {
host += listen
}
baseURL := fmt.Sprintf("http://%s", host)
// Set config values
cfg := config.FromContext(ctx)
cfg.Set("base-url", env("BASE_URL", baseURL))
cfg.Set("dns-url", env("DNS_URL", baseURL))
cfg.Set("xmpp-url", env("XMPP_URL", baseURL))
cfg.Set("reddit.api-key", os.Getenv("REDDIT_APIKEY"))
cfg.Set("reddit.secret", os.Getenv("REDDIT_SECRET"))
cfg.Set("xmpp-config", &xmpp.Config{
Jid: os.Getenv("XMPP_USERNAME"),
Credential: xmpp.Password(os.Getenv("XMPP_PASSWORD")),
})
mux := chi.NewRouter()
mux.Use(
cfg.ApplyHTTP,
2020-11-23 20:49:53 -07:00
secHeaders,
2020-11-28 15:11:49 -07:00
cors.New(cors.Options{
AllowCredentials: true,
AllowedMethods: strings.Fields(env("CORS_METHODS", "GET")),
AllowedOrigins: strings.Fields(env("CORS_ORIGIN", "*")),
}).Handler,
2020-11-23 13:58:19 -07:00
middleware.RequestID,
middleware.RealIP,
middleware.RequestLogger(&middleware.DefaultLogFormatter{Logger: accessLog(log.Info)}),
middleware.Recoverer,
)
2020-11-28 15:11:49 -07:00
if env("DISABLE_KEYPROOF", "false") == "false" {
// Create cache for promise engine
arc, _ := lru.NewARC(4096)
c := cache.New(arc)
keyproofs.NewKeyProofApp(ctx, c).Routes(mux)
}
2020-11-23 20:49:53 -07:00
2020-11-28 15:11:49 -07:00
if env("DISABLE_DNS", "false") == "false" {
keyproofs.NewDNSApp(ctx).Routes(mux)
2020-11-23 13:58:19 -07:00
}
2020-11-28 15:11:49 -07:00
if env("DISABLE_AVATAR", "false") == "false" {
avatarApp, err := keyproofs.NewAvatarApp(ctx, env("AVATAR_PATH", "pub"))
if err != nil {
return err
}
avatarApp.Routes(mux)
}
if env("DISABLE_VCARD", "false") == "false" {
vcardApp, err := keyproofs.NewVCardApp(ctx)
if err != nil {
return err
}
vcardApp.Routes(mux)
}
2020-11-23 13:58:19 -07:00
log.Info().
Str("app", cfg.GetString("app-name")).
Str("version", cfg.GetString("app-version")).
Str("build-hash", cfg.GetString("build-hash")).
Str("build-date", cfg.GetString("build-date")).
Str("listen", listen).
Msg("startup")
2020-11-28 15:11:49 -07:00
err := New(&http.Server{
2020-11-23 13:58:19 -07:00
Addr: listen,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
Handler: mux,
}).Run(ctx)
if err != nil {
return err
}
2020-11-23 20:49:53 -07:00
return wg.Wait(5 * time.Second)
2020-11-23 13:58:19 -07:00
}
type Server struct {
srv *http.Server
}
func New(s *http.Server) *Server {
return &Server{srv: s}
}
func (s *Server) Run(ctx context.Context) error {
log := log.Ctx(ctx)
2020-11-23 20:49:53 -07:00
wg := graceful.WaitGroup(ctx)
2020-11-23 13:58:19 -07:00
2020-11-23 20:49:53 -07:00
wg.Go(func() error {
2020-11-23 13:58:19 -07:00
<-ctx.Done()
log.Info().Msg("Shutdown HTTP")
2020-11-23 20:49:53 -07:00
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
2020-11-23 13:58:19 -07:00
defer cancel()
err := s.srv.Shutdown(ctx)
2020-11-23 20:49:53 -07:00
if err != nil && err != http.ErrServerClosed {
return err
2020-11-23 13:58:19 -07:00
}
log.Info().Msg("Stopped HTTP")
2020-11-23 20:49:53 -07:00
return nil
})
err := s.srv.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
return err
}
2020-11-23 13:58:19 -07:00
2020-11-23 20:49:53 -07:00
return nil
2020-11-23 13:58:19 -07:00
}
func env(name, defaultValue string) string {
if value := os.Getenv(name); value != "" {
return value
}
return defaultValue
}
2020-11-23 20:49:53 -07:00
func secHeaders(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Content-Security-Policy", "font-src https://pagecdn.io")
2020-11-23 13:58:19 -07:00
2020-11-23 20:49:53 -07:00
h.ServeHTTP(w, r)
})
2020-11-23 13:58:19 -07:00
}
type accessLog func() *zerolog.Event
func (a accessLog) Print(v ...interface{}) {
a().Msg(fmt.Sprint(v...))
}