spark-server/internal/module/moderation/logic/scan.go
2026-09-29 16:37:36 +08:00

58 lines
1.5 KiB
Go

package logic
import (
"context"
modentity "spark-server/internal/module/moderation/entity"
)
// Scan implements message TextFilter. No hit returns (nil, nil).
func (s *Service) Scan(ctx context.Context, text string) (*modentity.ScanResult, error) {
if !s.Ready() {
return nil, nil
}
_ = ctx
details, masked, ok := s.repo.MatcherFind(text)
if len(details) == 0 {
return nil, nil
}
if !ok {
return &modentity.ScanResult{Action: modentity.ActionReject, Hits: toHits(details)}, nil
}
var actions []modentity.Action
var muteSec int
hits := make([]modentity.HitMatch, 0, len(details))
for i := range details {
d := details[i]
act := d.Action.Effective()
actions = append(actions, act)
if act == modentity.ActionMute {
if w := s.repo.LookupWord(d.WordID); w != nil && w.MuteSeconds > muteSec {
muteSec = w.MuteSeconds
}
}
hits = append(hits, modentity.HitMatch{
WordID: d.WordID, Category: d.Category, Action: d.Action,
Excerpt: d.Excerpt, ByteFrom: d.From, ByteTo: d.To,
})
}
best := modentity.MaxAction(actions...)
res := &modentity.ScanResult{Action: best, Hits: hits, MuteSeconds: muteSec}
if best == modentity.ActionReplace {
res.ReplacedBody = masked
}
return res, nil
}
func toHits(details []MatchDetail) []modentity.HitMatch {
out := make([]modentity.HitMatch, 0, len(details))
for i := range details {
d := details[i]
out = append(out, modentity.HitMatch{
WordID: d.WordID, Category: d.Category, Action: d.Action,
Excerpt: d.Excerpt, ByteFrom: d.From, ByteTo: d.To,
})
}
return out
}