refactored for maintainability
This commit is contained in:
63
internal/notify/notify.go
Normal file
63
internal/notify/notify.go
Normal 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
53
internal/notify/util.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user