Files
ai-agent/internal/services/wxwork_notify_service.go
T

154 lines
3.7 KiB
Go
Raw Normal View History

2026-04-19 18:11:34 +08:00
package services
import (
"context"
2026-04-19 18:11:34 +08:00
"fmt"
"strings"
"code.tczkiot.com/wlw/ai-agent/identity"
"code.tczkiot.com/wlw/ai-agent/internal/wxwork"
2026-04-19 18:11:34 +08:00
"github.com/mlogclub/simple/common/arrs"
2026-04-19 18:11:34 +08:00
wxmessage "github.com/silenceper/wechat/v2/work/message"
"github.com/spf13/cast"
2026-04-19 18:11:34 +08:00
)
var WxWorkNotifyService = newWxWorkNotifyService()
type wxWorkMessageSender interface {
SendText(request wxmessage.SendTextRequest) (*wxmessage.SendResponse, error)
}
type wxWorkNotifyService struct {
senderFactory func() (wxWorkMessageSender, error)
}
func newWxWorkNotifyService() *wxWorkNotifyService {
return &wxWorkNotifyService{
senderFactory: func() (wxWorkMessageSender, error) {
if !wxwork.Enabled() || wxwork.GetWorkCli() == nil {
return nil, fmt.Errorf("wxwork is not enabled")
}
return wxwork.GetWorkCli().GetMessage(), nil
},
}
}
func (s *wxWorkNotifyService) Enabled() bool {
if !wxwork.Enabled() {
return false
}
cfg, err := wxwork.CurrentConfig()
return err == nil && cfg.Notify.Enabled
2026-04-19 18:11:34 +08:00
}
func (s *wxWorkNotifyService) SendTextToAssigneeOrDefault(assigneeID int64, title, body string) error {
2026-04-19 18:11:34 +08:00
if !s.Enabled() {
return nil
}
toUsers := s.resolveToUsersByUserIDs([]int64{assigneeID})
if len(toUsers) == 0 {
toUsers = s.defaultToUsers()
2026-04-19 18:11:34 +08:00
}
if len(toUsers) == 0 {
2026-04-19 18:11:34 +08:00
return nil
}
return s.sendText(title, body, toUsers)
2026-04-19 18:11:34 +08:00
}
func (s *wxWorkNotifyService) sendText(title, body string, toUsers []string) error {
2026-04-19 18:11:34 +08:00
if !s.Enabled() {
return nil
}
content := s.buildTextContent(title, body)
if content == "" {
return nil
}
sender, err := s.senderFactory()
if err != nil {
return err
}
cfg, err := wxwork.CurrentConfig()
if err != nil {
return err
}
2026-04-19 18:11:34 +08:00
req := wxmessage.SendTextRequest{
SendRequestCommon: &wxmessage.SendRequestCommon{
ToUser: strings.Join(toUsers, "|"),
2026-04-19 18:11:34 +08:00
AgentID: strings.TrimSpace(cfg.AgentID),
Safe: cast.ToInt(cfg.Notify.Safe),
EnableDuplicateCheck: cast.ToInt(cfg.Notify.EnableDuplicateCheck),
2026-04-19 18:11:34 +08:00
DuplicateCheckInterval: s.normalizeDuplicateCheckInterval(cfg.Notify.DuplicateCheckInterval),
},
Text: wxmessage.TextField{Content: content},
}
_, err = sender.SendText(req)
return err
}
func (s *wxWorkNotifyService) resolveToUsersByUserIDs(userIDs []int64) []string {
userIDs = arrs.Distinct(userIDs)
2026-04-19 18:11:34 +08:00
if len(userIDs) == 0 {
return nil
2026-04-19 18:11:34 +08:00
}
subjects, err := SubjectService.Query(context.Background(), identity.Query{
Types: []identity.SubjectType{identity.SubjectAdmin},
IDs: userIDs,
EnabledOnly: true,
})
if err != nil {
return nil
}
toUsers := make([]string, 0, len(subjects))
for i := range subjects {
if receiver := strings.TrimSpace(subjects[i].Bindings["wxwork"]); receiver != "" {
toUsers = append(toUsers, receiver)
2026-04-19 18:11:34 +08:00
}
}
return arrs.Distinct(toUsers)
2026-04-19 18:11:34 +08:00
}
func (s *wxWorkNotifyService) defaultToUsers() []string {
cfg, err := wxwork.CurrentConfig()
if err != nil {
return nil
}
return s.resolveToUsersByUserIDs(cfg.Notify.ToUsers)
2026-04-19 18:11:34 +08:00
}
func (s *wxWorkNotifyService) buildTextContent(title, body string) string {
title = strings.TrimSpace(title)
body = strings.TrimSpace(body)
switch {
case title == "" && body == "":
return ""
case title == "":
return s.truncateRunes(body, 1024)
2026-04-19 18:11:34 +08:00
case body == "":
return s.truncateRunes(title, 1024)
2026-04-19 18:11:34 +08:00
default:
return s.truncateRunes(title+"\n\n"+body, 1024)
2026-04-19 18:11:34 +08:00
}
}
func (s *wxWorkNotifyService) normalizeDuplicateCheckInterval(value int) int {
if value <= 0 {
return 1800
}
if value > 14400 {
return 14400
}
return value
}
func (s *wxWorkNotifyService) truncateRunes(value string, max int) string {
2026-04-19 18:11:34 +08:00
if max <= 0 {
return ""
}
runes := []rune(strings.TrimSpace(value))
if len(runes) <= max {
return string(runes)
}
return string(runes[:max])
}