Merge pull request #579 from catfishlty/feat/gotify

feat(notify): add gotify
This commit is contained in:
Yoan.liu
2025-04-03 17:42:00 +08:00
committed by GitHub
11 changed files with 262 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ const (
NotifyChannelTypeBark = NotifyChannelType("bark")
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
NotifyChannelTypeEmail = NotifyChannelType("email")
NotifyChannelTypeGotify = NotifyChannelType("gotify")
NotifyChannelTypeLark = NotifyChannelType("lark")
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")

View File

@@ -8,6 +8,7 @@ import (
pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
@@ -46,6 +47,13 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
ReceiverAddress: maputil.GetString(channelConfig, "receiverAddress"),
})
case domain.NotifyChannelTypeGotify:
return pGotify.NewNotifier(&pGotify.NotifierConfig{
Url: maputil.GetString(channelConfig, "url"),
Token: maputil.GetString(channelConfig, "token"),
Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1),
})
case domain.NotifyChannelTypeLark:
return pLark.NewNotifier(&pLark.NotifierConfig{
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),

View File

@@ -0,0 +1,104 @@
package gotify
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/notifier"
)
type NotifierConfig struct {
// Gotify 服务地址
// 示例https://gotify.example.com
Url string `json:"url"`
// Gotify Token
Token string `json:"token"`
// Gotify 消息优先级
Priority int64 `json:"priority"`
}
type NotifierProvider struct {
config *NotifierConfig
logger *slog.Logger
// 未来将移除
httpClient *http.Client
}
var _ notifier.Notifier = (*NotifierProvider)(nil)
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
if config == nil {
panic("config is nil")
}
return &NotifierProvider{
config: config,
httpClient: http.DefaultClient,
}, nil
}
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
if logger == nil {
n.logger = slog.Default()
} else {
n.logger = logger
}
return n
}
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
// Gotify 原生实现, notify 库没有实现, 等待合并
reqBody := &struct {
Title string `json:"title"`
Message string `json:"message"`
Priority int64 `json:"priority"`
}{
Title: subject,
Message: message,
Priority: n.config.Priority,
}
// Make request
body, err := json.Marshal(reqBody)
if err != nil {
return nil, errors.Wrap(err, "encode message body")
}
req, err := http.NewRequestWithContext(
ctx,
http.MethodPost,
fmt.Sprintf("%s/message", n.config.Url),
bytes.NewReader(body),
)
if err != nil {
return nil, errors.Wrap(err, "create new request")
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.config.Token))
req.Header.Set("Content-Type", "application/json; charset=utf-8")
// Send request to gotify service
resp, err := n.httpClient.Do(req)
if err != nil {
return nil, errors.Wrapf(err, "send request to gotify server")
}
defer resp.Body.Close()
// Read response and verify success
result, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "read response")
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("gotify returned status code %d: %s", resp.StatusCode, string(result))
}
return &notifier.NotifyResult{}, nil
}

View File

@@ -0,0 +1,68 @@
package gotify_test
import (
"context"
"flag"
"fmt"
"strings"
"testing"
provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
)
const (
mockSubject = "test_subject"
mockMessage = "test_message"
)
var (
fUrl string
fToken string
fPriority int64
)
func init() {
argsPrefix := "CERTIMATE_NOTIFIER_GOTIFY_"
flag.StringVar(&fUrl, argsPrefix+"URL", "", "")
flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
flag.Int64Var(&fPriority, argsPrefix+"PRIORITY", 0, "")
}
/*
Shell command to run this test:
go test -v ./gotify_test.go -args \
--CERTIMATE_NOTIFIER_GOTIFY_URL="https://example.com" \
--CERTIMATE_NOTIFIER_GOTIFY_TOKEN="your-gotify-application-token" \
--CERTIMATE_NOTIFIER_GOTIFY_PRIORITY="your-message-priority"
*/
func TestNotify(t *testing.T) {
flag.Parse()
t.Run("Notify", func(t *testing.T) {
t.Log(strings.Join([]string{
"args:",
fmt.Sprintf("URL: %v", fUrl),
fmt.Sprintf("TOKEN: %v", fToken),
fmt.Sprintf("PRIORITY: %d", fPriority),
}, "\n"))
notifier, err := provider.NewNotifier(&provider.NotifierConfig{
Url: fUrl,
Token: fToken,
Priority: fPriority,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
res, err := notifier.Notify(context.Background(), mockSubject, mockMessage)
if err != nil {
t.Errorf("err: %+v", err)
return
}
t.Logf("ok: %v", res)
})
}