Add video download failure reporting feature
- Introduced a new API endpoint `POST /api/v1/video/remove_watermark/report_failure` for reporting download failures. - Added a new database table `video_download_failures` to store details about failed downloads, including domain, URL, error message, and reporting metadata. - Updated the video handler to process failure reports and save them to the database. - Enhanced documentation to include details about the new reporting feature and its usage.
This commit is contained in:
@@ -3,6 +3,9 @@ package handler
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -25,6 +28,14 @@ type removeWatermarkRequest struct {
|
||||
Content string `json:"content" binding:"required"`
|
||||
}
|
||||
|
||||
type reportDownloadFailureRequest struct {
|
||||
Domain string `json:"domain"`
|
||||
FailedURL string `json:"failedUrl" binding:"required"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
UserAgent string `json:"userAgent"`
|
||||
}
|
||||
|
||||
func (h *VideoHandler) RemoveWatermark(c *gin.Context) {
|
||||
var req removeWatermarkRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -84,3 +95,52 @@ func (h *VideoHandler) UnlockQuota(c *gin.Context) {
|
||||
"unlocked": true,
|
||||
}))
|
||||
}
|
||||
|
||||
func (h *VideoHandler) ReportDownloadFailure(c *gin.Context) {
|
||||
var req reportDownloadFailureRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误"))
|
||||
return
|
||||
}
|
||||
|
||||
failedURL := strings.TrimSpace(req.FailedURL)
|
||||
if failedURL == "" {
|
||||
c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "failedUrl 不能为空"))
|
||||
return
|
||||
}
|
||||
|
||||
reportedAt := time.Now()
|
||||
if req.Timestamp > 0 {
|
||||
reportedAt = time.UnixMilli(req.Timestamp)
|
||||
}
|
||||
|
||||
domain := strings.TrimSpace(req.Domain)
|
||||
if domain == "" {
|
||||
if parsed, err := url.Parse(failedURL); err == nil {
|
||||
domain = parsed.Host
|
||||
}
|
||||
}
|
||||
|
||||
userAgent := strings.TrimSpace(req.UserAgent)
|
||||
if userAgent == "" {
|
||||
userAgent = c.Request.UserAgent()
|
||||
}
|
||||
|
||||
report := service.DownloadFailureReport{
|
||||
Domain: domain,
|
||||
FailedURL: failedURL,
|
||||
ErrorMessage: req.ErrorMessage,
|
||||
ReportedAt: reportedAt,
|
||||
UserAgent: userAgent,
|
||||
ClientIP: c.ClientIP(),
|
||||
}
|
||||
|
||||
if err := h.videoService.ReportDownloadFailure(c.Request.Context(), report); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "上报失败,请稍后重试"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, model.Success(gin.H{
|
||||
"reported": true,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -50,3 +50,25 @@ func (VideoParseUnlock) TableName() string {
|
||||
func (VideoParseUnlock) TableComment() string {
|
||||
return "短视频去水印-每日广告解锁"
|
||||
}
|
||||
|
||||
type VideoDownloadFailure struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `gorm:"comment:创建时间" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"comment:更新时间" json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index;comment:删除时间" json:"-"`
|
||||
|
||||
Domain string `gorm:"size:255;index;comment:来源域名" json:"domain"`
|
||||
FailedURL string `gorm:"size:1000;comment:下载失败的URL" json:"failed_url"`
|
||||
ErrorMessage string `gorm:"type:text;comment:失败原因" json:"error_message"`
|
||||
ReportedAt time.Time `gorm:"index;comment:失败发生时间" json:"reported_at"`
|
||||
UserAgent string `gorm:"size:255;comment:上报端UA" json:"user_agent"`
|
||||
ClientIP string `gorm:"size:64;comment:上报IP" json:"client_ip"`
|
||||
}
|
||||
|
||||
func (VideoDownloadFailure) TableName() string {
|
||||
return "video_download_failures"
|
||||
}
|
||||
|
||||
func (VideoDownloadFailure) TableComment() string {
|
||||
return "短视频去水印-下载失败上报"
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
rmmodel "wx_service/internal/remove_watermark/model"
|
||||
)
|
||||
|
||||
const removeWatermarkEndpoint = "https://api.23bt.cn/api/d1w/index"
|
||||
const removeWatermarkEndpoint = "https://api.23bt.cn/api/dsp/index"
|
||||
|
||||
var (
|
||||
// 从用户输入的文本里“抓取 URL”的简单正则(找到第一个 http/https 链接)
|
||||
@@ -56,6 +56,15 @@ func (e *ThirdPartyError) Error() string {
|
||||
return fmt.Sprintf("third-party api error: status=%d message=%s", e.StatusCode, e.Message)
|
||||
}
|
||||
|
||||
type DownloadFailureReport struct {
|
||||
Domain string
|
||||
FailedURL string
|
||||
ErrorMessage string
|
||||
ReportedAt time.Time
|
||||
UserAgent string
|
||||
ClientIP string
|
||||
}
|
||||
|
||||
func NewVideoService(db *gorm.DB, cfg config.ShortVideoConfig) (*VideoService, error) {
|
||||
timeout := cfg.RequestTimeout
|
||||
if timeout <= 0 {
|
||||
@@ -253,3 +262,33 @@ func truncateString(input string, max int) string {
|
||||
}
|
||||
return input[:max]
|
||||
}
|
||||
|
||||
func (s *VideoService) ReportDownloadFailure(ctx context.Context, report DownloadFailureReport) error {
|
||||
if report.ReportedAt.IsZero() {
|
||||
report.ReportedAt = time.Now()
|
||||
}
|
||||
|
||||
if report.Domain == "" && report.FailedURL != "" {
|
||||
if parsed, err := url.Parse(report.FailedURL); err == nil {
|
||||
report.Domain = parsed.Host
|
||||
}
|
||||
}
|
||||
|
||||
entry := rmmodel.VideoDownloadFailure{
|
||||
Domain: report.Domain,
|
||||
FailedURL: report.FailedURL,
|
||||
ErrorMessage: truncateString(report.ErrorMessage, 2000),
|
||||
ReportedAt: report.ReportedAt,
|
||||
UserAgent: truncateString(report.UserAgent, 255),
|
||||
ClientIP: truncateString(report.ClientIP, 64),
|
||||
}
|
||||
|
||||
if entry.FailedURL == "" {
|
||||
return errors.New("failed_url is required")
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Create(&entry).Error; err != nil {
|
||||
return fmt.Errorf("save download failure report: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user