123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- package job
- import (
- "context"
- "encoding/json"
- "fmt"
- "github.com/go-nunu/nunu-layout-advanced/internal/service"
- "github.com/go-nunu/nunu-layout-advanced/internal/service/api/waf"
- "github.com/rabbitmq/amqp091-go"
- "go.uber.org/zap"
- "strconv"
- "strings"
- "sync"
- )
- // 使用公共的 TaskHandler 定义
- // WhitelistJob 定义了处理白名单相关任务的接口
- type WhitelistJob interface {
- // DomainConsumer 启动消费者,处理域名白名单任务
- DomainConsumer(ctx context.Context)
- // IpConsumer 启动消费者,处理 IP 白名单任务
- IpConsumer(ctx context.Context)
- }
- // NewWhitelistJob 创建一个新的 WhitelistJob
- func NewWhitelistJob(job *Job,
- aoDunService service.AoDunService,
- wafForMatter waf.WafFormatterService,
- ) WhitelistJob {
- return &whitelistJob{
- Job: job,
- aoDunService: aoDunService,
- wafForMatter: wafForMatter,
- }
- }
- type whitelistJob struct {
- *Job
- aoDunService service.AoDunService
- wafForMatter waf.WafFormatterService
- }
- // DomainConsumer 启动域名白名单消费者
- func (j *whitelistJob) DomainConsumer(ctx context.Context) {
- j.consume(ctx, "domain_whitelist", "domain_whitelist_consumer", j.handleDomainMessage)
- }
- // IpConsumer 启动IP白名单消费者
- func (j *whitelistJob) IpConsumer(ctx context.Context) {
- j.consume(ctx, "ip_white", "ip_white_consumer", j.handleIpMessage)
- }
- // consume 调用公共的 Consume 方法
- func (j *whitelistJob) consume(ctx context.Context, taskName, consumerName string, handler TaskHandler) {
- j.Job.Consume(ctx, taskName, consumerName, handler)
- }
- // handleDomainMessage 是域名白名单任务的具体处理器
- func (j *whitelistJob) handleDomainMessage(ctx context.Context, logger *zap.Logger, d amqp091.Delivery) error {
- type domainTaskPayload struct {
- Domain string `json:"domain"`
- Ip string `json:"ip"`
- Action string `json:"action"` // "add" or "del"
- }
- var payload domainTaskPayload
- if err := json.Unmarshal(d.Body, &payload); err != nil {
- logger.Error("解析域名白名单消息失败", zap.Error(err), zap.ByteString("body", d.Body))
- return nil // 返回 nil 以避免消息重入队列,因为这是一个格式错误
- }
- logger.Info("收到域名白名单任务",
- zap.String("action", payload.Action),
- zap.String("domain", payload.Domain),
- zap.String("ip", payload.Ip),
- zap.String("routing_key", d.RoutingKey),
- )
- var processingErr error
- switch payload.Action {
- case "add", "del":
- processingErr = j.aoDunService.DomainWhiteList(ctx, payload.Domain, payload.Ip, payload.Action)
- default:
- processingErr = fmt.Errorf("unknown action: %s", payload.Action)
- logger.Warn("在域名白名单任务中收到未知操作", zap.String("action", payload.Action), zap.String("domain", payload.Domain))
- }
- if processingErr != nil {
- logger.Error("处理域名白名单任务失败", zap.Error(processingErr), zap.String("domain", payload.Domain))
- } else {
- logger.Info("已成功处理域名白名单任务", zap.String("action", payload.Action), zap.String("domain", payload.Domain))
- }
- return processingErr
- }
- // handleIpMessage 是 IP 白名单任务的具体处理器
- func (j *whitelistJob) handleIpMessage(ctx context.Context, logger *zap.Logger, d amqp091.Delivery) error {
- type ipTaskPayload struct {
- Ips []string `json:"ips"`
- Action string `json:"action"`
- Color string `json:"color"`
- ReturnSourceIp string `json:"return_source_ip"`
- }
- var payload ipTaskPayload
- if err := json.Unmarshal(d.Body, &payload); err != nil {
- logger.Error("解析IP白名单消息失败", zap.Error(err), zap.ByteString("body", d.Body), zap.String("routing_key", d.RoutingKey))
- return nil // 消息格式错误,不应重试
- }
- logger.Info("收到IP白名单任务",
- zap.String("action", payload.Action),
- zap.Any("ips", payload.Ips),
- zap.String("color", payload.Color),
- zap.String("routing_key", d.RoutingKey),
- )
- var processingErr error
- switch payload.Action {
- case "add":
- ips, err := j.wafForMatter.AppendWafIp(ctx, payload.Ips, payload.ReturnSourceIp)
- if err != nil {
- // 如果附加IP失败,记录错误并终止
- processingErr = fmt.Errorf("为WAF准备IP列表失败: %w", err)
- } else {
- var wg sync.WaitGroup
- errChan := make(chan error, 2)
- wg.Add(2)
- go func() {
- defer wg.Done()
- if err := j.aoDunService.AddWhiteStaticList(ctx, false, ips, payload.Color); err != nil {
- errChan <- err
- }
- }()
- go func() {
- defer wg.Done()
- if err := j.aoDunService.AddWhiteStaticList(ctx, true, ips,payload.Color); err != nil {
- errChan <- err
- }
- }()
- wg.Wait()
- close(errChan)
- var errs []string
- for err := range errChan {
- errs = append(errs, err.Error())
- }
- if len(errs) > 0 {
- processingErr = fmt.Errorf("添加IP到白名单时发生错误: %s", strings.Join(errs, "; "))
- }
- }
- case "del":
- var wg sync.WaitGroup
- errChan := make(chan error, len(payload.Ips)*2)
- deleteFromWall := func(isSmall bool, ip string) {
- defer wg.Done()
- id, err := j.aoDunService.GetWhiteStaticList(ctx, isSmall, ip, payload.ReturnSourceIp,payload.Color)
- if err != nil {
- errChan <- fmt.Errorf("获取IP '%s' (isSmall: %t) ID失败: %w , color: %s", ip, isSmall, err, payload.Color)
- return
- }
- if err := j.aoDunService.DelWhiteStaticList(ctx, isSmall, strconv.Itoa(id), payload.Color); err != nil {
- errChan <- fmt.Errorf("删除IP '%s' (isSmall: %t, id: %d) 失败: %w , color: %s", ip, isSmall, id, err , payload.Color)
- }
- }
- for _, ip := range payload.Ips {
- wg.Add(2)
- go deleteFromWall(false, ip)
- go deleteFromWall(true, ip)
- }
- wg.Wait()
- close(errChan)
- var errs []string
- for err := range errChan {
- logger.Error("删除IP白名单过程中发生错误", zap.Error(err), zap.String("color", payload.Color))
- errs = append(errs, err.Error())
- }
- if len(errs) > 0 {
- processingErr = fmt.Errorf("删除IP任务中发生错误: %s", strings.Join(errs, "; ") + ", color: " + payload.Color)
- }
- default:
- processingErr = fmt.Errorf("unknown action: %s", payload.Action)
- logger.Warn("在IP白名单任务中收到未知操作", zap.String("action", payload.Action), zap.Any("ips", payload.Ips), zap.String("color", payload.Color))
- }
- if processingErr != nil {
- logger.Error("处理IP白名单任务失败", zap.Error(processingErr), zap.Any("ips", payload.Ips), zap.String("color", payload.Color))
- } else {
- logger.Info("已成功处理IP白名单任务", zap.String("action", payload.Action), zap.Any("ips", payload.Ips), zap.String("color", payload.Color))
- }
- return processingErr
- }
|