diff --git a/config/config.go b/config/config.go index 308763f..89caf4e 100644 --- a/config/config.go +++ b/config/config.go @@ -14,7 +14,7 @@ import ( // Config holds all application configuration. type Config struct { Database DatabaseConfig `yaml:"database"` - Port string `yaml:"port"` + Web WebConfig `yaml:"web"` Path string `yaml:"path"` Secret string `yaml:"secret"` } @@ -25,6 +25,12 @@ type DatabaseConfig struct { DSN string `yaml:"dsn"` // MySQL connection string (required when type is "mysql") } +// WebConfig holds web-server listening configuration. +type WebConfig struct { + Port string `yaml:"port"` // TCP port, "" or "0" to disable + Socket string `yaml:"socket"` // Unix socket path, "" to disable +} + const defaultPort = "8080" // mysqlExampleDSN is written into new config files as a reference. @@ -64,6 +70,13 @@ func generateSecret() string { return fmt.Sprintf("%x", hash) } +// getDefaultSocketPath returns the OS-aware default unix socket path. +func getDefaultSocketPath() string { + if runtime.GOOS == "linux" { + return "/opt/blog_go/web.sock" + } + return "" +} // LoadConfig reads the config file or creates one with defaults. func LoadConfig() *Config { configDir, configFile := getConfigPath() @@ -81,7 +94,10 @@ func LoadConfig() *Config { Type: "sqlite", DSN: mysqlExampleDSN, }, - Port: defaultPort, + Web: WebConfig{ + Port: defaultPort, + Socket: getDefaultSocketPath(), + }, Path: defaultPath, Secret: generateSecret(), } @@ -116,8 +132,8 @@ func LoadConfig() *Config { // applyDefaults fills zero-value fields with sensible defaults. func applyDefaults(cfg *Config, defaultPath string) *Config { - if cfg.Port == "" { - cfg.Port = defaultPort + if cfg.Web.Port == "" { + cfg.Web.Port = defaultPort } if cfg.Database.Type == "" { cfg.Database.Type = "sqlite" diff --git a/main.go b/main.go index bff7894..f7799da 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,8 @@ package main import ( "fmt" "log" + "net" + "os" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" @@ -161,9 +163,39 @@ func main() { } // 9. Start the server. - addr := fmt.Sprintf(":%s", cfg.Port) - log.Printf("Go Blog starting on http://localhost%s", addr) - if err := router.Run(addr); err != nil { - log.Fatalf("Failed to start server: %v", err) + webPort := cfg.Web.Port + socketPath := cfg.Web.Socket + usePort := webPort != "" && webPort != "0" + useSocket := socketPath != "" + + if !usePort && !useSocket { + log.Fatalf("Neither port nor socket is configured — at least one must be enabled") } + + if usePort { + go func() { + addr := fmt.Sprintf(":%s", webPort) + log.Printf("Go Blog starting on http://localhost%s", addr) + if err := router.Run(addr); err != nil { + log.Fatalf("Failed to start HTTP server: %v", err) + } + }() + } + + if useSocket { + go func() { + os.Remove(socketPath) // remove stale socket file if exists + listener, err := net.Listen("unix", socketPath) + if err != nil { + log.Fatalf("Failed to listen on unix socket %s: %v", socketPath, err) + } + log.Printf("Go Blog starting on unix socket %s", socketPath) + if err := router.RunListener(listener); err != nil { + log.Fatalf("Failed to serve on unix socket: %v", err) + } + }() + } + + // Block forever. + select {} }