task/1.12
Raw Download raw file
  1package main
  2
  3import (
  4	"flag"
  5	"log"
  6	"net/http"
  7	"os"
  8	"strconv"
  9)
 10
 11func main() {
 12	// Declare an instance of the config struct to hold configuration settings
 13	var cfg config
 14
 15	// Parse command-line flags with sensible defaults
 16	flag.IntVar(&cfg.port, "port", 4000, "HTTP server port")
 17	flag.StringVar(&cfg.env, "env", "development", "Environment (development|staging|production)")
 18	flag.StringVar(&cfg.staticDir, "static-dir", "./ui/static", "Path to static assets")
 19	flag.StringVar(&cfg.htmlDir, "html-dir", "./ui/html", "Path to HTML templates")
 20	flag.Parse()
 21
 22	// Check for environment variable overrides
 23	if envPort := os.Getenv("PORT"); envPort != "" {
 24		if port, err := strconv.Atoi(envPort); err == nil {
 25			cfg.port = port
 26		}
 27	}
 28	if envEnv := os.Getenv("ENV"); envEnv != "" {
 29		cfg.env = envEnv
 30	}
 31	if envStaticDir := os.Getenv("STATIC_DIR"); envStaticDir != "" {
 32		cfg.staticDir = envStaticDir
 33	}
 34	if envHtmlDir := os.Getenv("HTML_DIR"); envHtmlDir != "" {
 35		cfg.htmlDir = envHtmlDir
 36	}
 37
 38	// Create loggers for different types of messages
 39	infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
 40	errorLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
 41
 42	// Log startup configuration
 43	infoLog.Printf("Configuration loaded: port=%d, env=%s, staticDir=%s, htmlDir=%s", 
 44		cfg.port, cfg.env, cfg.staticDir, cfg.htmlDir)
 45
 46	// Create an instance of the application struct, containing the application-wide
 47	// dependencies and configuration settings.
 48	app := &application{
 49		config: cfg,
 50		logger: struct {
 51			info  *log.Logger
 52			error *log.Logger
 53		}{
 54			info:  infoLog,
 55			error: errorLog,
 56		},
 57		serviceName: "buylater.email",
 58	}
 59
 60	// Initialize a new servemux (router) - this stores the mapping between
 61	// URL patterns and their corresponding handlers.
 62	mux := http.NewServeMux()
 63
 64	// Create a file server which serves files out of the configured static directory.
 65	// Note that the path given to the http.Dir function is relative to the project
 66	// directory root.
 67	fileServer := http.FileServer(http.Dir(app.config.staticDir))
 68
 69	// Use the mux.Handle() function to register the file server as the handler for
 70	// all URL paths that start with "/static/". For matching paths, we strip the
 71	// "/static" prefix before the request reaches the file server.
 72	mux.Handle("GET /static/", http.StripPrefix("/static", fileServer))
 73
 74	// Register handlers for buylater.email routes - demonstrating different handler patterns:
 75
 76	// 1. Method handler converted to http.Handler using http.HandlerFunc
 77	mux.Handle("GET /{$}", http.HandlerFunc(app.home))
 78
 79	// 2. Custom handler type that implements http.Handler interface directly
 80	mux.Handle("GET /submit", &TemplateHandler{
 81		app:          app,
 82		templateName: "submit.tmpl",
 83		pageName:     "submit",
 84		title:        "Submit",
 85	})
 86
 87	// 3. Method handler with business logic
 88	mux.Handle("POST /submit", http.HandlerFunc(app.processSubmit))
 89
 90	// 4. Simple function handler converted to http.Handler
 91	mux.Handle("GET /confirm/{token}", http.HandlerFunc(confirmWithToken))
 92
 93	// 5. Another custom handler type instance for the about page
 94	mux.Handle("GET /about", &TemplateHandler{
 95		app:          app,
 96		templateName: "about.tmpl",
 97		pageName:     "about",
 98		title:        "About",
 99	})
100
101	// Print a log message to indicate the server is starting.
102	app.logger.info.Printf("Starting server on http://localhost:%d in %s mode", app.config.port, app.config.env)
103
104	// Start the web server on the configured port. If ListenAndServe returns an error
105	// we use log.Fatal() to log the error and terminate the program.
106	err := http.ListenAndServe(":"+strconv.Itoa(app.config.port), mux)
107	log.Fatal(err)
108}