Files
godoxy-yusing/internal/notif/providers.go
yusing 6da7227f9b refactor(errs): migrate from gperr.Error to standard Go error interface
This is a large-scale refactoring across the codebase that replaces the custom
`gperr.Error` type with Go's standard `error` interface. The changes include:

- Replacing `gperr.Error` return types with `error` in function signatures
- Using `errors.New()` and `fmt.Errorf()` instead of `gperr.New()` and `gperr.Errorf()`
- Using `%w` format verb for error wrapping instead of `.With()` method
- Replacing `gperr.Subject()` calls with `gperr.PrependSubject()`
- Converting error logging from `gperr.Log*()` functions to zerolog's `.Err().Msg()` pattern
- Update NewLogger to handle multiline error message
- Updating `goutils` submodule to latest commit

This refactoring aligns with Go idioms and removes the dependency on
custom error handling abstractions in favor of standard library patterns.
2026-02-08 12:07:36 +08:00

82 lines
1.6 KiB
Go

package notif
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"time"
"github.com/yusing/godoxy/internal/serialization"
)
type (
Provider interface {
serialization.CustomValidator
GetName() string
GetURL() string
GetToken() string
GetMethod() string
GetMIMEType() string
MarshalMessage(logMsg *LogMessage) ([]byte, error)
SetHeaders(logMsg *LogMessage, headers http.Header)
fmtError(respBody io.Reader) error
}
ProviderCreateFunc func(map[string]any) (Provider, error)
ProviderConfig map[string]any
)
const (
ProviderGotify = "gotify"
ProviderNtfy = "ntfy"
ProviderWebhook = "webhook"
)
var AvailableProviders = []string{ProviderGotify, ProviderNtfy, ProviderWebhook}
func (msg *LogMessage) notify(ctx context.Context, provider Provider) error {
body, err := provider.MarshalMessage(msg)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(
ctx,
provider.GetMethod(),
provider.GetURL(),
bytes.NewReader(body),
)
if err != nil {
return err
}
if mimeType := provider.GetMIMEType(); mimeType != "" {
req.Header.Set("Content-Type", mimeType)
}
if provider.GetToken() != "" {
req.Header.Set("Authorization", "Bearer "+provider.GetToken())
}
provider.SetHeaders(msg, req.Header)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent:
return nil
default:
return fmt.Errorf("http status %d: %w", resp.StatusCode, provider.fmtError(resp.Body))
}
}