diff --git a/.golangci.yml b/.golangci.yml index 7d341cd..1224225 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,6 @@ version: "2" run: - go: "1.25" + go: "1.24" modules-download-mode: readonly tests: false allow-parallel-runners: true @@ -81,7 +81,7 @@ linters: ignore-exported: false include-unexported: true disable: - - max-len + - max-len godot: scope: all exclude: @@ -196,7 +196,51 @@ linters: - fmt # https://staticcheck.dev/docs/configuration/options/#initialisms # Default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] - initialisms: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"] + initialisms: + [ + "ACL", + "API", + "ASCII", + "CPU", + "CSS", + "DNS", + "EOF", + "GUID", + "HTML", + "HTTP", + "HTTPS", + "ID", + "IP", + "JSON", + "QPS", + "RAM", + "RPC", + "SLA", + "SMTP", + "SQL", + "SSH", + "TCP", + "TLS", + "TTL", + "UDP", + "UI", + "GID", + "UID", + "UUID", + "URI", + "URL", + "UTF8", + "VM", + "XML", + "XMPP", + "XSRF", + "XSS", + "SIP", + "RTP", + "AMQP", + "DB", + "TS", + ] # https://staticcheck.dev/docs/configuration/options/#http_status_code_whitelist # Default: ["200", "400", "404", "500"] http-status-code-whitelist: ["200", "400", "404", "500"] diff --git a/cmd/joyproxy/main.go b/cmd/joyproxy/main.go index f80f5ce..7841d67 100644 --- a/cmd/joyproxy/main.go +++ b/cmd/joyproxy/main.go @@ -2,8 +2,11 @@ package main import ( + "errors" "net/http" "os" + "os/signal" + "syscall" "time" "joyproxy/internal/joyproxy" @@ -12,26 +15,74 @@ import ( // main application entry point. func main() { + var ( + err error + logfile *os.File + ) + joyproxy.LoadConf() - log.Init(joyproxy.Cfg.Loglevel, os.Stderr) + if joyproxy.Cfg.Logfile != "" { + logfile, err = os.OpenFile(joyproxy.Cfg.Logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) + if err != nil { + log.Fatalf("Unable to open %s: %s", joyproxy.Cfg.Logfile, err) + } + } else { + logfile = os.Stderr + } + + log.Init(joyproxy.Cfg.Loglevel, logfile) + + log.Info("Install handler to /joyproxy/ location") http.HandleFunc("/joyproxy/", joyproxy.JoyproxyHandler) + + log.Info("Install handler to /joyurl location") http.HandleFunc("/joyurl", joyproxy.JoyurlHandler) - log.Infof("Starting application on port %v\n", joyproxy.Cfg.Port) + // It's time to set up signal trapper. + signal.Notify(joyproxy.SigChan, + syscall.SIGINT, + syscall.SIGTERM, + syscall.SIGQUIT, + syscall.SIGHUP, + ) + + go joyproxy.SigHandler() + + log.Infof("Listening on port %v\n", joyproxy.Cfg.Port) // To prevent slow loris ddos, we have to define custom handler because builtin http.ListenAndServe() have no // timeout and sits here forever. - server := &http.Server{ + joyproxy.Server = &http.Server{ Addr: joyproxy.Cfg.Port, ReadHeaderTimeout: time.Duration(joyproxy.Cfg.Timeout) * time.Second, ReadTimeout: time.Duration(joyproxy.Cfg.Timeout) * time.Second, WriteTimeout: time.Duration(joyproxy.Cfg.Timeout) * time.Second, IdleTimeout: time.Duration(joyproxy.Cfg.Timeout) * time.Second, + ErrorLog: &log.Logger, } - log.Warn(server.ListenAndServe().Error()) + for { + if joyproxy.Shutdown { + time.Sleep(100 * time.Microsecond) + + continue + } + + err = joyproxy.Server.ListenAndServe() + + if errors.Is(err, http.ErrServerClosed) { + log.Info("Shutdown joyproxy") + + break + } + + log.Errorf("Listener error: %s", err) + } + + <-joyproxy.QuitChan + os.Exit(0) } /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ diff --git a/internal/joyproxy/globals.go b/internal/joyproxy/globals.go index fa5df47..dfdb760 100644 --- a/internal/joyproxy/globals.go +++ b/internal/joyproxy/globals.go @@ -1,6 +1,11 @@ // Package joyproxy is main appliction lib. package joyproxy +import ( + "net/http" + "os" +) + var ( // Cfg represents struct with application config settings. Cfg Config @@ -42,6 +47,18 @@ var ( } postForm = "\n
\n