This commit is contained in:
yusing
2026-02-16 08:59:01 +08:00
parent 15b9635ee1
commit e4e6f6b3e8
242 changed files with 3953 additions and 3502 deletions

View File

@@ -304,9 +304,9 @@ The notif package integrates with:
```go
var (
ErrMissingNotifProvider = gperr.New("missing notification provider")
ErrInvalidNotifProviderType = gperr.New("invalid notification provider type")
ErrUnknownNotifProvider = gperr.New("unknown notification provider")
ErrMissingNotifProvider = errors.New("missing notification provider")
ErrInvalidNotifProviderType = errors.New("invalid notification provider type")
ErrUnknownNotifProvider = errors.New("unknown notification provider")
)
```

View File

@@ -1,6 +1,8 @@
package notif
import (
"errors"
"fmt"
"io"
"net/http"
"net/url"
@@ -23,13 +25,13 @@ func (e rawError) Error() string {
}
var (
ErrMissingToken = gperr.New("token is required")
ErrURLMissingScheme = gperr.New("url missing scheme, expect 'http://' or 'https://'")
ErrUnknownError = gperr.New("unknown error")
ErrMissingToken = errors.New("token is required")
ErrURLMissingScheme = errors.New("url missing scheme, expect 'http://' or 'https://'")
ErrUnknownError = errors.New("unknown error")
)
// Validate implements the utils.CustomValidator interface.
func (base *ProviderBase) Validate() gperr.Error {
func (base *ProviderBase) Validate() error {
switch base.Format {
case "":
base.Format = LogFormatMarkdown
@@ -48,7 +50,7 @@ func (base *ProviderBase) Validate() gperr.Error {
}
u, err := url.Parse(base.URL)
if err != nil {
return gperr.Wrap(err)
return fmt.Errorf("invalid url: %w", err)
}
base.URL = u.String()
return nil

View File

@@ -1,6 +1,9 @@
package notif
import (
"errors"
"strings"
"github.com/yusing/godoxy/internal/serialization"
gperr "github.com/yusing/goutils/errs"
)
@@ -11,13 +14,13 @@ type NotificationConfig struct {
}
var (
ErrMissingNotifProvider = gperr.New("missing notification provider")
ErrInvalidNotifProviderType = gperr.New("invalid notification provider type")
ErrUnknownNotifProvider = gperr.New("unknown notification provider")
ErrMissingNotifProvider = errors.New("missing notification provider")
ErrInvalidNotifProviderType = errors.New("invalid notification provider type")
ErrUnknownNotifProvider = errors.New("unknown notification provider")
)
// UnmarshalMap implements MapUnmarshaler.
func (cfg *NotificationConfig) UnmarshalMap(m map[string]any) (err gperr.Error) {
func (cfg *NotificationConfig) UnmarshalMap(m map[string]any) (err error) {
// extract provider name
providerName := m["provider"]
switch providerName := providerName.(type) {
@@ -41,9 +44,8 @@ func (cfg *NotificationConfig) UnmarshalMap(m map[string]any) (err gperr.Error)
case ProviderNtfy:
cfg.Provider = &Ntfy{}
default:
return ErrUnknownNotifProvider.
Subject(cfg.ProviderName).
Withf("expect %s or %s", ProviderWebhook, ProviderGotify)
return gperr.PrependSubject(ErrUnknownNotifProvider, cfg.ProviderName).
Withf("expect %s", strings.Join(AvailableProviders, ", "))
}
return serialization.MapUnmarshalValidate(m, cfg.Provider)

View File

@@ -19,14 +19,15 @@ type (
const gotifyMsgEndpoint = "/message"
func (client *GotifyClient) Validate() gperr.Error {
func (client *GotifyClient) Validate() error {
var errs gperr.Builder
if err := client.ProviderBase.Validate(); err != nil {
return err
errs.Add(err)
}
if client.Token == "" {
return gperr.New("token is required")
errs.Adds("token is required")
}
return nil
return errs.Error()
}
func (client *GotifyClient) GetURL() string {
@@ -58,7 +59,7 @@ func (client *GotifyClient) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
}
if client.Format == LogFormatMarkdown {
msg.Extras = map[string]interface{}{
msg.Extras = map[string]any{
"client::display": map[string]string{
"contentType": "text/markdown",
},

View File

@@ -14,20 +14,21 @@ type Ntfy struct {
}
// Validate implements the utils.CustomValidator interface.
func (n *Ntfy) Validate() gperr.Error {
func (n *Ntfy) Validate() error {
var errs gperr.Builder
if err := n.ProviderBase.Validate(); err != nil {
return err
errs.Add(err)
}
if n.URL == "" {
return gperr.New("url is required")
errs.Adds("url is required")
}
if n.Topic == "" {
return gperr.New("topic is required")
errs.Adds("topic is required")
}
if n.Topic[0] == '/' {
return gperr.New("topic should not start with a slash")
if n.Topic != "" && n.Topic[0] == '/' {
errs.Adds("topic should not start with a slash")
}
return nil
return errs.Error()
}
// GetURL implements Provider.

View File

@@ -9,7 +9,6 @@ import (
"time"
"github.com/yusing/godoxy/internal/serialization"
gperr "github.com/yusing/goutils/errs"
)
type (
@@ -27,7 +26,7 @@ type (
fmtError(respBody io.Reader) error
}
ProviderCreateFunc func(map[string]any) (Provider, gperr.Error)
ProviderCreateFunc func(map[string]any) (Provider, error)
ProviderConfig map[string]any
)
@@ -37,6 +36,8 @@ const (
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 {

View File

@@ -3,6 +3,7 @@ package notif
import (
_ "embed"
"encoding/json"
"errors"
"io"
"net/http"
"strings"
@@ -26,9 +27,11 @@ var webhookTemplates = map[string]string{
"discord": discordPayload,
}
func (webhook *Webhook) Validate() gperr.Error {
if err := webhook.ProviderBase.Validate(); err != nil && !err.Is(ErrMissingToken) {
return err
func (webhook *Webhook) Validate() error {
var errs gperr.Builder
if err := webhook.ProviderBase.Validate(); err != nil && !errors.Is(err, ErrMissingToken) {
errs.Add(err)
}
switch webhook.MIMEType {
@@ -36,18 +39,17 @@ func (webhook *Webhook) Validate() gperr.Error {
webhook.MIMEType = MimeTypeJSON
case MimeTypeJSON, MimeTypeForm, MimeTypeText:
default:
return gperr.Errorf("invalid mime_type, expect %s", strings.Join([]string{"empty", MimeTypeJSON, MimeTypeForm, MimeTypeText}, ", "))
errs.Addf("invalid mime_type, expect %s", strings.Join([]string{"empty", MimeTypeJSON, MimeTypeForm, MimeTypeText}, ", "))
}
switch webhook.Template {
case "":
if webhook.MIMEType == MimeTypeJSON {
if !validateJSONPayload(webhook.Payload) {
return gperr.New("invalid payload, expect valid JSON")
}
}
if webhook.Payload == "" {
return gperr.New("invalid payload, expect non-empty")
errs.Adds("invalid payload, expect non-empty")
} else if webhook.MIMEType == MimeTypeJSON {
if !validateJSONPayload(webhook.Payload) {
errs.Adds("invalid payload, expect valid JSON")
}
}
case "discord":
webhook.ColorMode = "dec"
@@ -57,7 +59,7 @@ func (webhook *Webhook) Validate() gperr.Error {
webhook.Payload = discordPayload
}
default:
return gperr.New("invalid template, expect empty or 'discord'")
errs.Adds("invalid template, expect empty or 'discord'")
}
switch webhook.Method {
@@ -65,7 +67,7 @@ func (webhook *Webhook) Validate() gperr.Error {
webhook.Method = http.MethodPost
case http.MethodGet, http.MethodPost, http.MethodPut:
default:
return gperr.New("invalid method, expect empty, 'GET', 'POST' or 'PUT'")
errs.Adds("invalid method, expect empty, 'GET', 'POST' or 'PUT'")
}
switch webhook.ColorMode {
@@ -73,10 +75,10 @@ func (webhook *Webhook) Validate() gperr.Error {
webhook.ColorMode = "hex"
case "hex", "dec":
default:
return gperr.New("invalid color_mode, expect empty, 'hex' or 'dec'")
errs.Adds("invalid color_mode, expect empty, 'hex' or 'dec'")
}
return nil
return errs.Error()
}
// GetMethod implements Provider.