refactor: re-implement logic of notify

This commit is contained in:
Fu Diwei 2024-11-10 18:03:20 +08:00
parent 150b666d4b
commit 5d93334426
10 changed files with 166 additions and 269 deletions

2
go.mod
View File

@ -113,7 +113,7 @@ require (
github.com/cloudflare/cloudflare-go v0.104.0 // indirect github.com/cloudflare/cloudflare-go v0.104.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/disintegration/imaging v1.6.2 // indirect github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect github.com/domodwyer/mailyak/v3 v3.6.2
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.17.0 // indirect github.com/fatih/color v1.17.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/gabriel-vasile/mimetype v1.4.6 // indirect

View File

@ -1,12 +1,12 @@
package domain package domain
const ( const (
NotifyChannelDingtalk = "dingtalk" NotifyChannelEmail = "email"
NotifyChannelWebhook = "webhook" NotifyChannelWebhook = "webhook"
NotifyChannelTelegram = "telegram" NotifyChannelDingtalk = "dingtalk"
NotifyChannelLark = "lark" NotifyChannelLark = "lark"
NotifyChannelTelegram = "telegram"
NotifyChannelServerChan = "serverchan" NotifyChannelServerChan = "serverchan"
NotifyChannelMail = "mail"
NotifyChannelBark = "bark" NotifyChannelBark = "bark"
) )

View File

@ -12,19 +12,13 @@ import (
"github.com/usual2970/certimate/internal/utils/xtime" "github.com/usual2970/certimate/internal/utils/xtime"
) )
type msg struct {
subject string
message string
}
const ( const (
defaultExpireSubject = "您有{COUNT}张证书即将过期" defaultExpireSubject = "您有 {COUNT} 张证书即将过期"
defaultExpireMsg = "有{COUNT}张证书即将过期,域名分别为{DOMAINS},请保持关注!" defaultExpireMessage = "有 {COUNT} 张证书即将过期,域名分别为 {DOMAINS},请保持关注!"
) )
func PushExpireMsg() { func PushExpireMsg() {
// 查询即将过期的证书 // 查询即将过期的证书
records, err := app.GetApp().Dao().FindRecordsByFilter("domains", "expiredAt<{:time}&&certUrl!=''", "-created", 500, 0, records, err := app.GetApp().Dao().FindRecordsByFilter("domains", "expiredAt<{:time}&&certUrl!=''", "-created", 500, 0,
dbx.Params{"time": xtime.GetTimeAfter(24 * time.Hour * 15)}) dbx.Params{"time": xtime.GetTimeAfter(24 * time.Hour * 15)})
if err != nil { if err != nil {
@ -34,12 +28,12 @@ func PushExpireMsg() {
// 组装消息 // 组装消息
msg := buildMsg(records) msg := buildMsg(records)
if msg == nil { if msg == nil {
return return
} }
if err := Send(msg.subject, msg.message); err != nil { // 发送通知
if err := SendToAllChannels(msg.Subject, msg.Message); err != nil {
app.GetApp().Logger().Error("send expire msg", "error", err) app.GetApp().Logger().Error("send expire msg", "error", err)
} }
} }
@ -53,22 +47,27 @@ type notifyTemplate struct {
Content string `json:"content"` Content string `json:"content"`
} }
func buildMsg(records []*models.Record) *msg { type notifyMessage struct {
Subject string
Message string
}
func buildMsg(records []*models.Record) *notifyMessage {
if len(records) == 0 { if len(records) == 0 {
return nil return nil
} }
// 查询模板信息 // 查询模板信息
templateRecord, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='templates'") templateRecord, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='templates'")
title := defaultExpireSubject subject := defaultExpireSubject
content := defaultExpireMsg message := defaultExpireMessage
if err == nil { if err == nil {
var templates *notifyTemplates var templates *notifyTemplates
templateRecord.UnmarshalJSONField("content", templates) templateRecord.UnmarshalJSONField("content", templates)
if templates != nil && len(templates.NotifyTemplates) > 0 { if templates != nil && len(templates.NotifyTemplates) > 0 {
title = templates.NotifyTemplates[0].Title subject = templates.NotifyTemplates[0].Title
content = templates.NotifyTemplates[0].Content message = templates.NotifyTemplates[0].Content
} }
} }
@ -81,17 +80,17 @@ func buildMsg(records []*models.Record) *msg {
} }
countStr := strconv.Itoa(count) countStr := strconv.Itoa(count)
domainStr := strings.Join(domains, ",") domainStr := strings.Join(domains, ";")
title = strings.ReplaceAll(title, "{COUNT}", countStr) subject = strings.ReplaceAll(subject, "{COUNT}", countStr)
title = strings.ReplaceAll(title, "{DOMAINS}", domainStr) subject = strings.ReplaceAll(subject, "{DOMAINS}", domainStr)
content = strings.ReplaceAll(content, "{COUNT}", countStr) message = strings.ReplaceAll(message, "{COUNT}", countStr)
content = strings.ReplaceAll(content, "{DOMAINS}", domainStr) message = strings.ReplaceAll(message, "{DOMAINS}", domainStr)
// 返回消息 // 返回消息
return &msg{ return &notifyMessage{
subject: title, Subject: subject,
message: content, Message: message,
} }
} }

View File

@ -0,0 +1,66 @@
package notify
import (
"errors"
"github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/core/notifier"
notifierBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark"
notifierDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
notifierEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
notifierLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
notifierServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan"
notifierTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram"
notifierWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
"github.com/usual2970/certimate/internal/pkg/utils/maps"
)
func createNotifier(channel string, channelConfig map[string]any) (notifier.Notifier, error) {
switch channel {
case domain.NotifyChannelEmail:
return notifierEmail.New(&notifierEmail.EmailNotifierConfig{
SmtpHost: maps.GetValueAsString(channelConfig, "smtpHost"),
SmtpPort: maps.GetValueAsInt32(channelConfig, "smtpPort"),
SmtpTLS: maps.GetValueOrDefaultAsBool(channelConfig, "smtpTLS", true),
Username: maps.GetValueOrDefaultAsString(channelConfig, "username", maps.GetValueAsString(channelConfig, "senderAddress")),
Password: maps.GetValueAsString(channelConfig, "password"),
SenderAddress: maps.GetValueAsString(channelConfig, "senderAddress"),
ReceiverAddress: maps.GetValueAsString(channelConfig, "receiverAddress"),
})
case domain.NotifyChannelWebhook:
return notifierWebhook.New(&notifierWebhook.WebhookNotifierConfig{
Url: maps.GetValueAsString(channelConfig, "url"),
})
case domain.NotifyChannelDingtalk:
return notifierDingTalk.New(&notifierDingTalk.DingTalkNotifierConfig{
AccessToken: maps.GetValueAsString(channelConfig, "accessToken"),
Secret: maps.GetValueAsString(channelConfig, "secret"),
})
case domain.NotifyChannelLark:
return notifierLark.New(&notifierLark.LarkNotifierConfig{
WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"),
})
case domain.NotifyChannelTelegram:
return notifierTelegram.New(&notifierTelegram.TelegramNotifierConfig{
ApiToken: maps.GetValueAsString(channelConfig, "apiToken"),
ChatId: maps.GetValueAsInt64(channelConfig, "chatId"),
})
case domain.NotifyChannelServerChan:
return notifierServerChan.New(&notifierServerChan.ServerChanNotifierConfig{
Url: maps.GetValueAsString(channelConfig, "url"),
})
case domain.NotifyChannelBark:
return notifierBark.New(&notifierBark.BarkNotifierConfig{
DeviceKey: maps.GetValueAsString(channelConfig, "deviceKey"),
ServerUrl: maps.GetValueAsString(channelConfig, "serverUrl"),
})
}
return nil, errors.New("unsupported notifier channel")
}

View File

@ -1,56 +0,0 @@
package notify
import (
"context"
"fmt"
"net/mail"
"strconv"
"github.com/pocketbase/pocketbase/tools/mailer"
)
const defaultSmtpHostPort = "25"
type Mail struct {
username string
to string
client *mailer.SmtpClient
}
func NewMail(senderAddress, receiverAddresses, smtpHostAddr, smtpHostPort, password string) (*Mail, error) {
if smtpHostPort == "" {
smtpHostPort = defaultSmtpHostPort
}
port, err := strconv.Atoi(smtpHostPort)
if err != nil {
return nil, fmt.Errorf("invalid smtp port: %w", err)
}
client := mailer.SmtpClient{
Host: smtpHostAddr,
Port: port,
Username: senderAddress,
Password: password,
Tls: true,
}
return &Mail{
username: senderAddress,
client: &client,
to: receiverAddresses,
}, nil
}
func (m *Mail) Send(ctx context.Context, subject, content string) error {
message := &mailer.Message{
From: mail.Address{
Address: m.username,
},
To: []mail.Address{{Address: m.to}},
Subject: subject,
Text: content,
}
return m.client.Send(message)
}

View File

@ -4,22 +4,15 @@ import (
"context" "context"
"fmt" "fmt"
stdhttp "net/http" "golang.org/x/sync/errgroup"
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/notifier"
"github.com/usual2970/certimate/internal/pkg/utils/maps"
"github.com/usual2970/certimate/internal/utils/app" "github.com/usual2970/certimate/internal/utils/app"
notifyPackage "github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/bark"
"github.com/nikoksr/notify/service/dingding"
"github.com/nikoksr/notify/service/http"
"github.com/nikoksr/notify/service/lark"
"github.com/nikoksr/notify/service/telegram"
) )
func Send(title, content string) error { func SendToAllChannels(subject, message string) error {
// 获取所有的推送渠道 notifiers, err := getEnabledNotifiers()
notifiers, err := getNotifiers()
if err != nil { if err != nil {
return err return err
} }
@ -27,161 +20,56 @@ func Send(title, content string) error {
return nil return nil
} }
n := notifyPackage.New() var eg errgroup.Group
// 添加推送渠道 for _, n := range notifiers {
n.UseServices(notifiers...) if n == nil {
continue
}
// 发送消息 eg.Go(func() error {
return n.Send(context.Background(), title, content) _, err := n.Notify(context.Background(), subject, message)
return err
})
}
err = eg.Wait()
return err
} }
type sendTestParam struct { func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error {
Title string `json:"title"` notifier, err := createNotifier(channel, channelConfig)
Content string `json:"content"`
Channel string `json:"channel"`
Conf map[string]any `json:"conf"`
}
func SendTest(param *sendTestParam) error {
notifier, err := getNotifier(param.Channel, param.Conf)
if err != nil { if err != nil {
return err return err
} }
n := notifyPackage.New() _, err = notifier.Notify(context.Background(), subject, message)
return err
// 添加推送渠道
n.UseServices(notifier)
// 发送消息
return n.Send(context.Background(), param.Title, param.Content)
} }
func getNotifiers() ([]notifyPackage.Notifier, error) { func getEnabledNotifiers() ([]notifier.Notifier, error) {
resp, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='notifyChannels'") settings, err := app.GetApp().Dao().FindFirstRecordByFilter("settings", "name='notifyChannels'")
if err != nil { if err != nil {
return nil, fmt.Errorf("find notifyChannels error: %w", err) return nil, fmt.Errorf("find notifyChannels error: %w", err)
} }
notifiers := make([]notifyPackage.Notifier, 0)
rs := make(map[string]map[string]any) rs := make(map[string]map[string]any)
if err := settings.UnmarshalJSONField("content", &rs); err != nil {
if err := resp.UnmarshalJSONField("content", &rs); err != nil {
return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err) return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err)
} }
notifiers := make([]notifier.Notifier, 0)
for k, v := range rs { for k, v := range rs {
if !maps.GetValueAsBool(v, "enabled") {
if !getConfigAsBool(v, "enabled") {
continue continue
} }
notifier, err := getNotifier(k, v) notifier, err := createNotifier(k, v)
if err != nil { if err != nil {
continue continue
} }
notifiers = append(notifiers, notifier) notifiers = append(notifiers, notifier)
} }
return notifiers, nil return notifiers, nil
} }
func getNotifier(channel string, conf map[string]any) (notifyPackage.Notifier, error) {
switch channel {
case domain.NotifyChannelTelegram:
temp := getTelegramNotifier(conf)
if temp == nil {
return nil, fmt.Errorf("telegram notifier config error")
}
return temp, nil
case domain.NotifyChannelDingtalk:
return getDingTalkNotifier(conf), nil
case domain.NotifyChannelLark:
return getLarkNotifier(conf), nil
case domain.NotifyChannelWebhook:
return getWebhookNotifier(conf), nil
case domain.NotifyChannelServerChan:
return getServerChanNotifier(conf), nil
case domain.NotifyChannelMail:
return getMailNotifier(conf)
case domain.NotifyChannelBark:
return getBarkNotifier(conf), nil
}
return nil, fmt.Errorf("notifier not found")
}
func getWebhookNotifier(conf map[string]any) notifyPackage.Notifier {
rs := http.New()
rs.AddReceiversURLs(getConfigAsString(conf, "url"))
return rs
}
func getTelegramNotifier(conf map[string]any) notifyPackage.Notifier {
rs, err := telegram.New(getConfigAsString(conf, "apiToken"))
if err != nil {
return nil
}
rs.AddReceivers(getConfigAsInt64(conf, "chatId"))
return rs
}
func getServerChanNotifier(conf map[string]any) notifyPackage.Notifier {
rs := http.New()
rs.AddReceivers(&http.Webhook{
URL: getConfigAsString(conf, "url"),
Header: stdhttp.Header{},
ContentType: "application/json",
Method: stdhttp.MethodPost,
BuildPayload: func(subject, message string) (payload any) {
return map[string]string{
"text": subject,
"desp": message,
}
},
})
return rs
}
func getBarkNotifier(conf map[string]any) notifyPackage.Notifier {
deviceKey := getConfigAsString(conf, "deviceKey")
serverURL := getConfigAsString(conf, "serverUrl")
if serverURL == "" {
return bark.New(deviceKey)
}
return bark.NewWithServers(deviceKey, serverURL)
}
func getDingTalkNotifier(conf map[string]any) notifyPackage.Notifier {
return dingding.New(&dingding.Config{
Token: getConfigAsString(conf, "accessToken"),
Secret: getConfigAsString(conf, "secret"),
})
}
func getLarkNotifier(conf map[string]any) notifyPackage.Notifier {
return lark.NewWebhookService(getConfigAsString(conf, "webhookUrl"))
}
func getMailNotifier(conf map[string]any) (notifyPackage.Notifier, error) {
rs, err := NewMail(getConfigAsString(conf, "senderAddress"),
getConfigAsString(conf, "receiverAddresses"),
getConfigAsString(conf, "smtpHostAddr"),
getConfigAsString(conf, "smtpHostPort"),
getConfigAsString(conf, "password"),
)
if err != nil {
return nil, err
}
return rs, nil
}

View File

@ -29,18 +29,13 @@ func NewNotifyService(settingRepo SettingRepository) *NotifyService {
func (n *NotifyService) Test(ctx context.Context, req *domain.NotifyTestPushReq) error { func (n *NotifyService) Test(ctx context.Context, req *domain.NotifyTestPushReq) error {
setting, err := n.settingRepo.GetByName(ctx, "notifyChannels") setting, err := n.settingRepo.GetByName(ctx, "notifyChannels")
if err != nil { if err != nil {
return fmt.Errorf("get notify channels setting failed: %w", err) return fmt.Errorf("failed to get notify channels settings: %w", err)
} }
conf, err := setting.GetChannelContent(req.Channel) channelConfig, err := setting.GetChannelContent(req.Channel)
if err != nil { if err != nil {
return fmt.Errorf("get notify channel %s config failed: %w", req.Channel, err) return fmt.Errorf("failed to get notify channel \"%s\" config: %w", req.Channel, err)
} }
return SendTest(&sendTestParam{ return SendToChannel(notifyTestTitle, notifyTestBody, req.Channel, channelConfig)
Title: notifyTestTitle,
Content: notifyTestBody,
Channel: req.Channel,
Conf: conf,
})
} }

View File

@ -1,21 +0,0 @@
package notify
import (
"github.com/usual2970/certimate/internal/pkg/utils/maps"
)
func getConfigAsString(conf map[string]any, key string) string {
return maps.GetValueAsString(conf, key)
}
func getConfigAsInt32(conf map[string]any, key string) int32 {
return maps.GetValueAsInt32(conf, key)
}
func getConfigAsInt64(conf map[string]any, key string) int64 {
return maps.GetValueAsInt64(conf, key)
}
func getConfigAsBool(conf map[string]any, key string) bool {
return maps.GetValueAsBool(conf, key)
}

View File

@ -2,10 +2,10 @@
import ( import (
"context" "context"
"crypto/tls"
"errors" "errors"
"fmt" "fmt"
"net/smtp" "net/smtp"
"os"
"github.com/domodwyer/mailyak/v3" "github.com/domodwyer/mailyak/v3"
@ -44,15 +44,25 @@ func (n *EmailNotifier) Notify(ctx context.Context, subject string, message stri
smtpAuth = smtp.PlainAuth("", n.config.Username, n.config.Password, n.config.SmtpHost) smtpAuth = smtp.PlainAuth("", n.config.Username, n.config.Password, n.config.SmtpHost)
} }
var smtpAddr string
if n.config.SmtpPort == 0 {
if n.config.SmtpTLS {
smtpAddr = fmt.Sprintf("%s:465", n.config.SmtpHost)
} else {
smtpAddr = fmt.Sprintf("%s:25", n.config.SmtpHost)
}
} else {
smtpAddr = fmt.Sprintf("%s:%d", n.config.SmtpHost, n.config.SmtpPort)
}
var yak *mailyak.MailYak var yak *mailyak.MailYak
if n.config.SmtpTLS { if n.config.SmtpTLS {
os.Setenv("GODEBUG", "tlsrsakex=1") // Fix for TLS handshake error yak, err = mailyak.NewWithTLS(smtpAddr, smtpAuth, newTlsConfig())
yak, err = mailyak.NewWithTLS(fmt.Sprintf("%s:%d", n.config.SmtpHost, n.config.SmtpPort), smtpAuth, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else { } else {
yak = mailyak.New(fmt.Sprintf("%s:%d", n.config.SmtpHost, n.config.SmtpPort), smtpAuth) yak = mailyak.New(smtpAddr, smtpAuth)
} }
yak.From(n.config.SenderAddress) yak.From(n.config.SenderAddress)
@ -67,3 +77,19 @@ func (n *EmailNotifier) Notify(ctx context.Context, subject string, message stri
return &notifier.NotifyResult{}, nil return &notifier.NotifyResult{}, nil
} }
func newTlsConfig() *tls.Config {
var suiteIds []uint16
for _, suite := range tls.CipherSuites() {
suiteIds = append(suiteIds, suite.ID)
}
for _, suite := range tls.InsecureCipherSuites() {
suiteIds = append(suiteIds, suite.ID)
}
// 为兼容国内部分低版本 TLS 的 SMTP 服务商
return &tls.Config{
MinVersion: tls.VersionTLS10,
CipherSuites: suiteIds,
}
}

View File

@ -9,7 +9,7 @@ import "strconv"
// - key: 键。 // - key: 键。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是字符串,则返回空字符串。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是字符串,则返回空字符串。
func GetValueAsString(dict map[string]any, key string) string { func GetValueAsString(dict map[string]any, key string) string {
return GetValueOrDefaultAsString(dict, key, "") return GetValueOrDefaultAsString(dict, key, "")
} }
@ -22,7 +22,7 @@ func GetValueAsString(dict map[string]any, key string) string {
// - defaultValue: 默认值。 // - defaultValue: 默认值。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是字符串,则返回默认值。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是字符串,则返回默认值。
func GetValueOrDefaultAsString(dict map[string]any, key string, defaultValue string) string { func GetValueOrDefaultAsString(dict map[string]any, key string, defaultValue string) string {
if dict == nil { if dict == nil {
return defaultValue return defaultValue
@ -44,7 +44,7 @@ func GetValueOrDefaultAsString(dict map[string]any, key string, defaultValue str
// - key: 键。 // - key: 键。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是 32 位整数,则返回 0。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是 32 位整数,则返回 0。
func GetValueAsInt32(dict map[string]any, key string) int32 { func GetValueAsInt32(dict map[string]any, key string) int32 {
return GetValueOrDefaultAsInt32(dict, key, 0) return GetValueOrDefaultAsInt32(dict, key, 0)
} }
@ -57,7 +57,7 @@ func GetValueAsInt32(dict map[string]any, key string) int32 {
// - defaultValue: 默认值。 // - defaultValue: 默认值。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是 32 位整数,则返回默认值。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是 32 位整数,则返回默认值。
func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int32) int32 { func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int32) int32 {
if dict == nil { if dict == nil {
return defaultValue return defaultValue
@ -69,8 +69,8 @@ func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int3
} }
// 兼容字符串类型的值 // 兼容字符串类型的值
if s, ok := value.(string); ok { if str, ok := value.(string); ok {
if result, err := strconv.ParseInt(s, 10, 32); err == nil { if result, err := strconv.ParseInt(str, 10, 32); err == nil {
return int32(result) return int32(result)
} }
} }
@ -86,7 +86,7 @@ func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int3
// - key: 键。 // - key: 键。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是 64 位整数,则返回 0。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是 64 位整数,则返回 0。
func GetValueAsInt64(dict map[string]any, key string) int64 { func GetValueAsInt64(dict map[string]any, key string) int64 {
return GetValueOrDefaultAsInt64(dict, key, 0) return GetValueOrDefaultAsInt64(dict, key, 0)
} }
@ -99,7 +99,7 @@ func GetValueAsInt64(dict map[string]any, key string) int64 {
// - defaultValue: 默认值。 // - defaultValue: 默认值。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是 64 位整数,则返回默认值。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是 64 位整数,则返回默认值。
func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int64) int64 { func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int64) int64 {
if dict == nil { if dict == nil {
return defaultValue return defaultValue
@ -111,8 +111,8 @@ func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int6
} }
// 兼容字符串类型的值 // 兼容字符串类型的值
if s, ok := value.(string); ok { if str, ok := value.(string); ok {
if result, err := strconv.ParseInt(s, 10, 64); err == nil { if result, err := strconv.ParseInt(str, 10, 64); err == nil {
return result return result
} }
} }
@ -128,7 +128,7 @@ func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int6
// - key: 键。 // - key: 键。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是布尔,则返回 false。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是布尔,则返回 false。
func GetValueAsBool(dict map[string]any, key string) bool { func GetValueAsBool(dict map[string]any, key string) bool {
return GetValueOrDefaultAsBool(dict, key, false) return GetValueOrDefaultAsBool(dict, key, false)
} }
@ -141,7 +141,7 @@ func GetValueAsBool(dict map[string]any, key string) bool {
// - defaultValue: 默认值。 // - defaultValue: 默认值。
// //
// 出参: // 出参:
// - 字典中键对应的值。如果指定键不存在或者类型不是布尔,则返回默认值。 // - 字典中键对应的值。如果指定键不存在或者值的类型不是布尔,则返回默认值。
func GetValueOrDefaultAsBool(dict map[string]any, key string, defaultValue bool) bool { func GetValueOrDefaultAsBool(dict map[string]any, key string, defaultValue bool) bool {
if dict == nil { if dict == nil {
return defaultValue return defaultValue