97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"errors"
|
|||
|
|
|
|||
|
|
"lijiaoqiao/supply-api/internal/audit/model"
|
|||
|
|
"lijiaoqiao/supply-api/internal/audit/repository"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// DatabaseAuditService 数据库-backed审计服务
|
|||
|
|
type DatabaseAuditService struct {
|
|||
|
|
repo repository.AuditRepository
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewDatabaseAuditService 创建数据库-backed审计服务
|
|||
|
|
func NewDatabaseAuditService(repo repository.AuditRepository) *DatabaseAuditService {
|
|||
|
|
return &DatabaseAuditService{repo: repo}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Ensure interface
|
|||
|
|
var _ AuditStoreInterface = (*DatabaseAuditService)(nil)
|
|||
|
|
|
|||
|
|
// Emit 发送审计事件
|
|||
|
|
func (s *DatabaseAuditService) Emit(ctx context.Context, event *model.AuditEvent) error {
|
|||
|
|
// 验证事件
|
|||
|
|
if event == nil {
|
|||
|
|
return ErrInvalidInput
|
|||
|
|
}
|
|||
|
|
if event.EventName == "" {
|
|||
|
|
return ErrMissingEventName
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查幂等键
|
|||
|
|
if event.IdempotencyKey != "" {
|
|||
|
|
existing, err := s.repo.GetByIdempotencyKey(ctx, event.IdempotencyKey)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if existing != nil {
|
|||
|
|
// 幂等键已存在,检查payload是否一致
|
|||
|
|
if isSamePayload(existing, event) {
|
|||
|
|
return repository.ErrDuplicateIdempotencyKey
|
|||
|
|
}
|
|||
|
|
return ErrIdempotencyConflict
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 发送事件
|
|||
|
|
if err := s.repo.Emit(ctx, event); err != nil {
|
|||
|
|
if errors.Is(err, repository.ErrDuplicateIdempotencyKey) {
|
|||
|
|
return repository.ErrDuplicateIdempotencyKey
|
|||
|
|
}
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Query 查询审计事件
|
|||
|
|
func (s *DatabaseAuditService) Query(ctx context.Context, filter *EventFilter) ([]*model.AuditEvent, int64, error) {
|
|||
|
|
if filter == nil {
|
|||
|
|
filter = &EventFilter{}
|
|||
|
|
}
|
|||
|
|
// 转换 filter 类型
|
|||
|
|
repoFilter := &repository.EventFilter{
|
|||
|
|
TenantID: filter.TenantID,
|
|||
|
|
Category: filter.Category,
|
|||
|
|
EventName: filter.EventName,
|
|||
|
|
Limit: filter.Limit,
|
|||
|
|
Offset: filter.Offset,
|
|||
|
|
}
|
|||
|
|
if !filter.StartTime.IsZero() {
|
|||
|
|
repoFilter.StartTime = &filter.StartTime
|
|||
|
|
}
|
|||
|
|
if !filter.EndTime.IsZero() {
|
|||
|
|
repoFilter.EndTime = &filter.EndTime
|
|||
|
|
}
|
|||
|
|
return s.repo.Query(ctx, repoFilter)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetByIdempotencyKey 根据幂等键获取事件
|
|||
|
|
func (s *DatabaseAuditService) GetByIdempotencyKey(ctx context.Context, key string) (*model.AuditEvent, error) {
|
|||
|
|
return s.repo.GetByIdempotencyKey(ctx, key)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewDatabaseAuditServiceWithPool 从数据库连接池创建审计服务
|
|||
|
|
func NewDatabaseAuditServiceWithPool(pool interface {
|
|||
|
|
Query(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
|
|||
|
|
Exec(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
|
|||
|
|
}) *DatabaseAuditService {
|
|||
|
|
// 注意:这里需要一个适配器来将通用的pool接口转换为pgxpool.Pool
|
|||
|
|
// 在实际使用中,应该直接使用 NewDatabaseAuditService(repo)
|
|||
|
|
// 这个函数仅用于类型兼容性
|
|||
|
|
return nil
|
|||
|
|
}
|