chatai/auth_v2.169.0/cmd/serve_cmd.go

112 lines
2.6 KiB
Go

package cmd
import (
"context"
"net"
"net/http"
"sync"
"time"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/supabase/auth/internal/api"
"github.com/supabase/auth/internal/conf"
"github.com/supabase/auth/internal/reloader"
"github.com/supabase/auth/internal/storage"
"github.com/supabase/auth/internal/utilities"
)
var serveCmd = cobra.Command{
Use: "serve",
Long: "Start API server",
Run: func(cmd *cobra.Command, args []string) {
serve(cmd.Context())
},
}
func serve(ctx context.Context) {
if err := conf.LoadFile(configFile); err != nil {
logrus.WithError(err).Fatal("unable to load config")
}
if err := conf.LoadDirectory(watchDir); err != nil {
logrus.WithError(err).Fatal("unable to load config from watch dir")
}
config, err := conf.LoadGlobalFromEnv()
if err != nil {
logrus.WithError(err).Fatal("unable to load config")
}
db, err := storage.Dial(config)
if err != nil {
logrus.Fatalf("error opening database: %+v", err)
}
defer db.Close()
addr := net.JoinHostPort(config.API.Host, config.API.Port)
logrus.Infof("GoTrue API started on: %s", addr)
opts := []api.Option{
api.NewLimiterOptions(config),
}
a := api.NewAPIWithVersion(config, db, utilities.Version, opts...)
ah := reloader.NewAtomicHandler(a)
baseCtx, baseCancel := context.WithCancel(context.Background())
defer baseCancel()
httpSrv := &http.Server{
Addr: addr,
Handler: ah,
ReadHeaderTimeout: 2 * time.Second, // to mitigate a Slowloris attack
BaseContext: func(net.Listener) context.Context {
return baseCtx
},
}
log := logrus.WithField("component", "api")
var wg sync.WaitGroup
defer wg.Wait() // Do not return to caller until this goroutine is done.
if watchDir != "" {
wg.Add(1)
go func() {
defer wg.Done()
fn := func(latestCfg *conf.GlobalConfiguration) {
log.Info("reloading api with new configuration")
latestAPI := api.NewAPIWithVersion(
latestCfg, db, utilities.Version, opts...)
ah.Store(latestAPI)
}
rl := reloader.NewReloader(watchDir)
if err := rl.Watch(ctx, fn); err != nil {
log.WithError(err).Error("watcher is exiting")
}
}()
}
wg.Add(1)
go func() {
defer wg.Done()
<-ctx.Done()
defer baseCancel() // close baseContext
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), time.Minute)
defer shutdownCancel()
if err := httpSrv.Shutdown(shutdownCtx); err != nil && !errors.Is(err, context.Canceled) {
log.WithError(err).Error("shutdown failed")
}
}()
if err := httpSrv.ListenAndServe(); err != http.ErrServerClosed {
log.WithError(err).Fatal("http server listen failed")
}
}