refactored for maintainability

This commit is contained in:
2026-02-08 17:19:45 +11:00
parent 860cae3977
commit c16a82f2ad
40 changed files with 1211 additions and 920 deletions

63
internal/notify/notify.go Normal file
View File

@@ -0,0 +1,63 @@
// Package notify provides utility functions for sending notifications to clients
package notify
import (
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/notify"
"git.haelnorr.com/h/oslstats/internal/throw"
"github.com/pkg/errors"
)
func notifyClient(
s *hws.Server,
w http.ResponseWriter,
r *http.Request,
level notify.Level,
title, message, details string,
action any,
) {
subCookie, err := r.Cookie("ws_sub_id")
if err != nil {
throw.InternalServiceError(s, w, r, "Notification failed. Do you have cookies enabled?", errors.Wrap(err, "r.Cookie"))
return
}
subID := notify.Target(subCookie.Value)
nt := notify.Notification{
Target: subID,
Title: title,
Message: message,
Details: details,
Action: action,
Level: level,
}
s.NotifySub(nt)
}
// InternalServiceError notifies with error level
func InternalServiceError(s *hws.Server, w http.ResponseWriter, r *http.Request, msg string, err error) {
notifyClient(s, w, r, notify.LevelError, "Internal Service Error", msg,
SerializeErrorDetails(http.StatusInternalServerError, err), nil)
}
// ServiceUnavailable notifies with error level
func ServiceUnavailable(s *hws.Server, w http.ResponseWriter, r *http.Request, msg string, err error) {
notifyClient(s, w, r, notify.LevelError, "Service Unavailable", msg,
SerializeErrorDetails(http.StatusServiceUnavailable, err), nil)
}
// Warn notifies with warn level
func Warn(s *hws.Server, w http.ResponseWriter, r *http.Request, title, msg string, action any) {
notifyClient(s, w, r, notify.LevelWarn, title, msg, "", action)
}
// Info notifies with info level
func Info(s *hws.Server, w http.ResponseWriter, r *http.Request, title, msg string, action any) {
notifyClient(s, w, r, notify.LevelInfo, title, msg, "", action)
}
// Success notifies with success level
func Success(s *hws.Server, w http.ResponseWriter, r *http.Request, title, msg string, action any) {
notifyClient(s, w, r, notify.LevelSuccess, title, msg, "", action)
}

53
internal/notify/util.go Normal file
View File

@@ -0,0 +1,53 @@
package notify
import (
"encoding/json"
"fmt"
)
// ErrorDetails contains structured error information for WebSocket error modals
type ErrorDetails struct {
Code int `json:"code"`
Stacktrace string `json:"stacktrace"`
}
// SerializeErrorDetails creates a JSON string with code and stacktrace
// This is exported so it can be used when creating error notifications
func SerializeErrorDetails(code int, err error) string {
details := ErrorDetails{
Code: code,
Stacktrace: FormatErrorDetails(err),
}
jsonData, jsonErr := json.Marshal(details)
if jsonErr != nil {
// Fallback if JSON encoding fails
return fmt.Sprintf(`{"code":%d,"stacktrace":"Failed to serialize error"}`, code)
}
return string(jsonData)
}
// ParseErrorDetails extracts code and stacktrace from JSON Details field
// Returns (code, stacktrace). If parsing fails, returns (500, original details string)
func ParseErrorDetails(details string) (int, string) {
if details == "" {
return 500, ""
}
var errDetails ErrorDetails
err := json.Unmarshal([]byte(details), &errDetails)
if err != nil {
// Not JSON or malformed - treat as plain stacktrace with default code
return 500, details
}
return errDetails.Code, errDetails.Stacktrace
}
// FormatErrorDetails extracts and formats error details from wrapped errors
func FormatErrorDetails(err error) string {
if err == nil {
return ""
}
// Use %+v format to get stack trace from github.com/pkg/errors
return fmt.Sprintf("%+v", err)
}