// server.go package main import ( "fmt" "log" "net/http" "path/filepath" "strings" ) var globalRoutes RouteMap // StartServer initializes the routing and starts the HTTP listener. func StartServer() { // InitCache() - Removed // Initial Scan (Optional, just to valid startup) var err error globalRoutes, err = ScanContent("content") if err != nil { log.Fatalf("Failed to scan content: %v", err) } // SINGLE ENTRY POINT http.HandleFunc("/", handleRequest) fmt.Println("Server is online at http://localhost:8080") if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal(err) } } func handleRequest(w http.ResponseWriter, r *http.Request) { // 1. Scan Content on Every Request (Dynamic) // This ensures we always have the latest file list. // In a high-traffic production env, we'd use fsnotify, but for a personal blog, this is fine. routes, err := ScanContent("content") if err != nil { http.Error(w, "Failed to scan content", http.StatusInternalServerError) log.Printf("Scan error: %v", err) return } globalRoutes = routes // 2. Normalize Request Path reqPath := strings.ToLower(r.URL.Path) // Handle /Favicon.svg directly if needed, or rely on it being in content? // If Favicon.svg is in content/Favicon.svg, it will be in routes as /favicon.svg // 3. Look up in Route Map file, found := globalRoutes[reqPath] if !found { // Try default file if this is a directory? // Global routes scan handles index.md -> / http.NotFound(w, r) return } // 4. Render Content contentBytes, err := RenderContent(file) if err != nil { log.Printf("Error rendering %s: %v", file.OriginalPath, err) http.Error(w, "Internal Server Error", 500) return } // 5. Serve Content // Detect Content-Type based on extension for non-markdown if !file.IsMarkdown { ext := strings.ToLower(filepath.Ext(file.OriginalPath)) switch ext { case ".css": w.Header().Set("Content-Type", "text/css") case ".js": w.Header().Set("Content-Type", "application/javascript") case ".svg": w.Header().Set("Content-Type", "image/svg+xml") case ".png": w.Header().Set("Content-Type", "image/png") case ".jpg", ".jpeg": w.Header().Set("Content-Type", "image/jpeg") } } else { w.Header().Set("Content-Type", "text/html; charset=utf-8") } // Disable browser caching to ensure changes are seen immediately w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") if _, err := w.Write(contentBytes); err != nil { log.Printf("Error writing response: %v", err) } }