blog/server.go

96 lines
2.5 KiB
Go

// 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)
}
}