diff options
Diffstat (limited to 'handlers')
| -rw-r--r-- | handlers/admin.go | 54 | ||||
| -rw-r--r-- | handlers/php_proxy.go | 18 | ||||
| -rw-r--r-- | handlers/proxy.go | 13 |
3 files changed, 77 insertions, 8 deletions
diff --git a/handlers/admin.go b/handlers/admin.go index 44c36a5..61519fa 100644 --- a/handlers/admin.go +++ b/handlers/admin.go @@ -5,11 +5,22 @@ import ( "auth-proxy/logging" "auth-proxy/models" "auth-proxy/types" + "auth-proxy/worker" "encoding/json" + "fmt" "net/http" "strconv" + "sync" + "time" ) +var workerPool *types.WorkerPool + +// SetWorkerPool sets the package-level worker pool instance. +func SetWorkerPool(pool *types.WorkerPool) { + workerPool = pool +} + // AdminPageHandler serves the admin dashboard page. func AdminPageHandler(w http.ResponseWriter, r *http.Request) { // Fetch all users to render on the page @@ -24,12 +35,20 @@ func AdminPageHandler(w http.ResponseWriter, r *http.Request) { "Paths": config.Paths, "Users": users, } - if err := templates.ExecuteTemplate(w, "admin.html", data); err != nil { + if err := templates.ExecuteTemplate(w, "admin.html", data); err != nil { logging.AppLog.Error("Failed to execute admin template", "error", err) } } -// GetUsersHandler returns a list of all users. +// EnrichedUser is a wrapper for User with additional computed fields. +// Note: We use pointers to the original User to avoid copying large structs. +type EnrichedUser struct { + *types.User + TimeSinceLogin string `json:"time_since_login"` +} + +// GetUsersHandler returns a list of all users with enriched information. +// It uses a worker pool to calculate extra information for each user in parallel. func GetUsersHandler(w http.ResponseWriter, r *http.Request) { ip := logging.GetClientIP(r) users, err := models.GetAllUsers() @@ -39,8 +58,37 @@ func GetUsersHandler(w http.ResponseWriter, r *http.Request) { return } + enrichedUsers := make([]EnrichedUser, len(users)) + var wg sync.WaitGroup + + for i, user := range users { + wg.Add(1) + // Create copies of loop variables to avoid race conditions in the closure + index := i + userCopy := user + + task := func() { + defer wg.Done() + // Simulate some work, e.g., calculating a value or fetching related data. + time.Sleep(5 * time.Millisecond) + + timeSinceLogin := "N/A" + if userCopy.LastLoginAt.Valid { + timeSinceLogin = fmt.Sprintf("%.0fm ago", time.Since(userCopy.LastLoginAt.Time).Minutes()) + } + + enrichedUsers[index] = EnrichedUser{ + User: &userCopy, + TimeSinceLogin: timeSinceLogin, + } + } + worker.Submit(workerPool, task) + } + + wg.Wait() // Wait for all tasks to complete + w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(users); err != nil { + if err := json.NewEncoder(w).Encode(enrichedUsers); err != nil { logging.AppLog.Error("Failed to encode users to JSON", "error", err, "ip", ip) } } diff --git a/handlers/php_proxy.go b/handlers/php_proxy.go index 98b62ba..d30f363 100644 --- a/handlers/php_proxy.go +++ b/handlers/php_proxy.go @@ -3,6 +3,7 @@ package handlers import ( "auth-proxy/config" "auth-proxy/logging" + "auth-proxy/worker" "bytes" "io" "io/ioutil" @@ -28,6 +29,11 @@ func NewPhpProxyHandler(scriptName string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fcgi, err := fcgiclient.Dial("unix", phpFpmSocket) if err != nil { + errStr := err.Error() + ip := logging.GetClientIP(r) + worker.Submit(workerPool, func() { + logging.AppLog.Error("Failed to connect to php-fpm", "error", errStr, "ip", ip) + }) http.Error(w, "Failed to connect to php-fpm: "+err.Error(), http.StatusInternalServerError) return } @@ -73,7 +79,10 @@ func NewPhpProxyHandler(scriptName string) http.Handler { env["AUTH_ASSETS_PATH"] = config.Paths.Assets - logging.AppLog.Debug("Proxying to PHP-FPM", "script_filename", scriptFilename, "doc_root", finalDocRoot) + // Asynchronously log the proxying action to avoid blocking the request. + worker.Submit(workerPool, func() { + logging.AppLog.Debug("Proxying to PHP-FPM", "script_filename", scriptFilename, "doc_root", finalDocRoot) + }) env["REQUEST_METHOD"] = r.Method env["SERVER_SOFTWARE"] = "go / auth-proxy" @@ -99,7 +108,12 @@ func NewPhpProxyHandler(scriptName string) http.Handler { resp, err := fcgi.Request(env, body) if err != nil { - http.Error(w, "FastCGI request failed: "+err.Error(), http.StatusInternalServerError) + ip := logging.GetClientIP(r) + errStr := err.Error() + worker.Submit(workerPool, func() { + logging.AppLog.Error("FastCGI request failed", "error", errStr, "ip", ip) + }) + http.Error(w, "FastCGI request failed: "+err.Error(), http.StatusInternalServerError) return } diff --git a/handlers/proxy.go b/handlers/proxy.go index 602fc78..d1f6def 100644 --- a/handlers/proxy.go +++ b/handlers/proxy.go @@ -2,6 +2,7 @@ package handlers import ( "auth-proxy/logging" + "auth-proxy/worker" "net/http" "net/http/httputil" "net/url" @@ -22,15 +23,21 @@ func NewProxy(targetURL string) http.Handler { director(req) // Run the default director req.Host = target.Host // Set the Host header to the target's host - // Log the proxying action + // Asynchronously log the proxying action to avoid blocking the request. + urlStr := req.URL.String() ip := logging.GetClientIP(req) - logging.AppLog.Info("Proxying request", "url", req.URL.String(), "ip", ip) + worker.Submit(workerPool, func() { + logging.AppLog.Info("Proxying request", "url", urlStr, "ip", ip) + }) } // Custom error handler for logging proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) { ip := logging.GetClientIP(r) - logging.AppLog.Error("Proxy error", "error", err, "ip", ip) + // Asynchronously log the proxy error to avoid blocking the response. + worker.Submit(workerPool, func() { + logging.AppLog.Error("Proxy error", "error", err, "ip", ip) + }) http.Error(w, "Proxy Error", http.StatusBadGateway) } |
