package main import ( "context" "database/sql" "log" "net/http" "os" "os/signal" "time" "code.osinet.fr/fgm/kurz/web/ui" "github.com/spf13/viper" "code.osinet.fr/fgm/kurz/domain" "code.osinet.fr/fgm/kurz/infrastructure" "code.osinet.fr/fgm/kurz/web/api" "github.com/gorilla/mux" "github.com/spf13/cobra" ) var cmdServe = &cobra.Command{ Args: cobra.NoArgs, Long: "Start HTTP Server", Run: serveHandler, Short: "Top-level command for HTTP Serving.", Use: "serve", } // db is the database connection shared by "serve *" commands. var db *sql.DB func init() { cmd.AddCommand(cmdServe) } func ensureInfrastructure(db *sql.DB) *sql.DB { if db != nil { err := db.Ping() if err != nil { db = nil } } if db != nil { return db } dbDriver, dbDsn := infrastructure.ParseDbCred() db, err := infrastructure.DbDial(dbDriver, dbDsn) if err != nil { panic(err) } domain.RegisterRepositories( infrastructure.MySQLShortURLRepository{DB: db}, infrastructure.MySQLTargetURLRepository{DB: db}, ) return db } // serveHandler handles Web paths. func serveHandler(_ *cobra.Command, args []string) { db = ensureInfrastructure(db) defer db.Close() // Set up globals from configuration, providing a few defaults. siteBaseURL := viper.Get("web.siteBaseUrl").(string) // This default is the relative position of the assets from the project root during development. viper.SetDefault("web.assetsPath", "web/ui/public") assetsPath := viper.Get("web.assetsPath").(string) webConfig := viper.Get("web").(map[string]interface{}) ui.SetupGlobals(webConfig) // Set up Web API and UI routes. router := mux.NewRouter() api.SetupRoutes(router) ui.SetupUI(router, assetsPath) http.Handle("/", router) // Start a server that can handle a SIGINT to shutdown. stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt) listenAddress := viper.Get("web.listenAddress").(string) server := &http.Server{Addr: listenAddress, Handler: router} go func() { log.Printf("Listening on %s, exposed as %s", listenAddress, siteBaseURL) err := server.ListenAndServe() log.Fatal(err) }() <-stop // Shutdown cleanly. log.Println("Shutting down server") ctx, _ := context.WithTimeout(context.Background(), 1*time.Second) server.Shutdown(ctx) log.Println("Server gracefully stopped") }