server

package
v0.2.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Cmd = &cobra.Command{
	Use:     "serve",
	Aliases: []string{"run"},
	Short:   "Starts the DRS Object API server",
	Run: func(cmd *cobra.Command, args []string) {
		logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
		slog.SetDefault(logger)
		fatal := func(msg string, args ...any) {
			logger.Error(msg, args...)
			os.Exit(1)
		}

		cfg, err := config.LoadConfig(configFile)
		if err != nil {
			fatal("failed to load config", "err", err)
		}
		if cfg.Auth.Mode == config.AuthModeGen3 && cfg.Database.Postgres == nil && !isMockAuthEnabled() {
			fatal("auth.mode=gen3 requires postgres database")
		}

		// Init DB
		var database db.DatabaseInterface
		var errDb error

		if cfg.Database.Sqlite != nil {
			dbPath := cfg.Database.Sqlite.File
			if dbPath == "" {
				dbPath = "drs.db"
				cfg.Database.Sqlite.File = dbPath
			}
			logger.Info("initializing sqlite database", "file", dbPath)
			database, errDb = sqlite.NewSqliteDB(dbPath)
		} else if cfg.Database.Postgres != nil {
			dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s",
				cfg.Database.Postgres.User,
				cfg.Database.Postgres.Password,
				cfg.Database.Postgres.Host,
				cfg.Database.Postgres.Port,
				cfg.Database.Postgres.Database,
				cfg.Database.Postgres.SSLMode,
			)
			logger.Info("initializing postgres database", "host", cfg.Database.Postgres.Host, "database", cfg.Database.Postgres.Database)
			database, errDb = postgres.NewPostgresDB(dsn)
		} else {
			fatal("no database configuration provided")
		}

		if errDb != nil {
			fatal("failed to initialize database", "err", errDb)
		}

		applyCredentialEncryptionConfig(cfg)

		if len(cfg.S3Credentials) > 0 {
			encryptionEnabled, encErr := crypto.CredentialEncryptionEnabled()
			if encErr != nil {
				fatal("invalid credential encryption configuration", "env", crypto.CredentialMasterKeyEnv, "err", encErr)
			}
			if !encryptionEnabled {
				fatal("s3 credential encryption key is required", "env", crypto.CredentialMasterKeyEnv)
			}

			logger.Info("loading configured s3 credentials", "count", len(cfg.S3Credentials))

			for _, c := range cfg.S3Credentials {
				cred := &models.S3Credential{
					Bucket:           c.Bucket,
					Provider:         c.Provider,
					Region:           c.Region,
					AccessKey:        c.AccessKey,
					SecretKey:        c.SecretKey,
					Endpoint:         c.Endpoint,
					BillingLogBucket: c.BillingLogBucket,
					BillingLogPrefix: c.BillingLogPrefix,
				}
				if c.ProviderBillingLogsEnabled() {
					if err := metricapi.ValidateProviderTransferLogSource(cmd.Context(), *cred); err != nil {
						fatal("invalid provider billing log configuration", "bucket", c.Bucket, "err", err)
					}
				} else {
					logger.Info("provider billing log validation disabled", "bucket", c.Bucket, "provider", c.Provider)
				}
				if err := database.SaveS3Credential(cmd.Context(), cred); err != nil {
					logger.Error("failed to save s3 credential", "bucket", c.Bucket, "err", err)
				}
			}
		}

		needsUrlManager := cfg.Routes.Ga4gh || cfg.Routes.Internal || cfg.Routes.LFS
		var uM *urlmanager.Manager
		if needsUrlManager {
			uM = urlmanager.NewManager(database, cfg.Signing)
			uM.RegisterSigner(common.S3Provider, s3.NewS3Signer(database))
			uM.RegisterSigner(common.GCSProvider, gcs.NewGCSSigner(database))
			uM.RegisterSigner(common.AzureProvider, azure.NewAzureSigner(database))
			fSigner, fErr := file.NewFileSigner("/")
			if fErr == nil {
				uM.RegisterSigner(common.FileProvider, fSigner)
			} else {
				logger.Warn("failed to initialize file signer", "err", fErr)
			}
		}

		om := core.NewObjectManager(database, uM)

		app := fiber.New(fiber.Config{
			ReadTimeout:    30 * time.Second,
			WriteTimeout:   120 * time.Second,
			IdleTimeout:    120 * time.Second,
			ReadBufferSize: 64 * 1024,
			AppName:        "Syfon DRS Server",
		})
		app.Use(recover.New())

		slogLogger := logger
		authzMiddleware := middleware.NewAuthzMiddleware(
			slogLogger,
			cfg.Auth.Mode,
			cfg.Auth.Basic.Username,
			cfg.Auth.Basic.Password,
		)
		requestIDMiddleware := middleware.NewRequestIDMiddleware(slogLogger)

		rt := &serverRuntime{
			app:                 app,
			cfg:                 cfg,
			database:            database,
			om:                  om,
			uM:                  uM,
			authzMiddleware:     authzMiddleware,
			requestIDMiddleware: requestIDMiddleware,
		}
		applyServerOptions(rt, buildServerOptions(cfg)...)

		addr := fmt.Sprintf(":%d", cfg.Port)
		logger.Info("server starting", "addr", addr)

		errCh := make(chan error, 1)
		go func() {
			if err := app.Listen(addr); err != nil {
				errCh <- err
			}
		}()

		sigCh := make(chan os.Signal, 1)
		signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
		defer signal.Stop(sigCh)

		select {
		case err := <-errCh:
			fatal("server listen failed", "err", err)
		case sig := <-sigCh:
			logger.Info("shutdown signal received", "signal", sig.String())
		case <-cmd.Context().Done():
			logger.Info("shutdown requested by context cancellation")
		}

		shutdownCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
		defer cancel()
		if err := app.ShutdownWithContext(shutdownCtx); err != nil {
			fatal("server shutdown failed", "err", err)
		}
		logger.Info("server shutdown complete")
	},
}

Functions

This section is empty.

Types

type ServerOption added in v0.2.0

type ServerOption func(*serverRuntime)

func WithDocsRoutes added in v0.2.0

func WithDocsRoutes() ServerOption

func WithGa4ghRoutes added in v0.2.0

func WithGa4ghRoutes() ServerOption

func WithHealthzRoute added in v0.2.0

func WithHealthzRoute() ServerOption

func WithInternalRoutes added in v0.2.0

func WithInternalRoutes() ServerOption

func WithLFSRoutes added in v0.2.0

func WithLFSRoutes() ServerOption

func WithMetricsRoutes added in v0.2.0

func WithMetricsRoutes() ServerOption

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL