package main import ( "context" "errors" "flag" "fmt" "net/http" "os" "path/filepath" "go.jolheiser.com/vanity/server/database" "go.jolheiser.com/vanity/server/router" "github.com/peterbourgon/ff/v3" "github.com/peterbourgon/ff/v3/ffcli" "github.com/peterbourgon/ff/v3/fftoml" "github.com/rs/zerolog/log" ) func New() *ffcli.Command { fs := flag.NewFlagSet("vanity", flag.ExitOnError) portFlag := fs.Int("port", 3333, "Port to run the vanity server on") domainFlag := fs.String("domain", "", "The Go module domain (e.g. go.jolheiser.com)") tokenFlag := fs.String("token", "", "vanity auth token to use") dbFlag := fs.String("database", dbPath(), "The path to the database") cmd := &ffcli.Command{ Name: "vanity", ShortUsage: "vanity", ShortHelp: "Vanity Server", LongHelp: "Vanity Server to serve the Go module vanity domain", FlagSet: fs, Options: []ff.Option{ ff.WithEnvVarPrefix("VANITY"), ff.WithAllowMissingConfigFile(true), ff.WithConfigFileFlag("config"), ff.WithConfigFileParser(fftoml.New().Parse), }, Exec: server(portFlag, domainFlag, tokenFlag, dbFlag), } return cmd } func server(port *int, domain, token, dbPath *string) func(context.Context, []string) error { return func(ctx context.Context, args []string) error { if *token == "" || *domain == "" { return errors.New("vanity server requires --token and --domain") } db, err := database.Load(*dbPath) if err != nil { log.Fatal().Msgf("could not load database at %s: %v", *dbPath, err) } log.Info().Msgf("Running vanity server at http://localhost:%d", *port) if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), router.New(*token, *domain, db)); err != nil { return err } return nil } } func dbPath() string { fn := "vanity.db" home, err := os.UserHomeDir() if err != nil { bin, err := os.Executable() if err != nil { return fn } return filepath.Join(filepath.Dir(bin), fn) } return filepath.Join(home, fn) }