163 lines
4.0 KiB
Go
163 lines
4.0 KiB
Go
package util
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gjson"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
func PullTaskResult(ctx context.Context, body map[string]any, queryConfig map[string]any, headMsg map[string]any) (map[string]any, error) {
|
|
taskID, err := extractTaskID(body, queryConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
g.Log().Infof(ctx, "[PullTaskResult] taskID=%s", taskID)
|
|
|
|
queryUrl := buildQueryURL(queryConfig, taskID)
|
|
method := gconv.String(queryConfig["method"])
|
|
if method == "" {
|
|
method = "GET"
|
|
}
|
|
interval := gconv.Int(queryConfig["interval_seconds"])
|
|
if interval <= 0 {
|
|
interval = 2
|
|
}
|
|
|
|
statusPath := gconv.String(queryConfig["status_path"])
|
|
if statusPath == "" {
|
|
statusPath = "status"
|
|
}
|
|
statusValues, _ := queryConfig["status_values"].(map[string]any)
|
|
|
|
// 失败信息路径
|
|
errorPath := gconv.String(queryConfig["error_path"])
|
|
if errorPath == "" {
|
|
errorPath = "error.message"
|
|
}
|
|
|
|
reqBodyMap := map[string]any{"task_id": taskID}
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
default:
|
|
}
|
|
|
|
result, err := doQueryRequest(ctx, method, queryUrl, reqBodyMap, headMsg)
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "[PullTaskResult] 请求失败 taskID=%s err=%v", taskID, err)
|
|
time.Sleep(time.Duration(interval) * time.Second)
|
|
continue
|
|
}
|
|
|
|
if result == nil {
|
|
time.Sleep(time.Duration(interval) * time.Second)
|
|
continue
|
|
}
|
|
|
|
statusStr := gconv.String(gjson.New(result).Get(statusPath).Val())
|
|
g.Log().Infof(ctx, "[PullTaskResult] 状态 taskID=%s status=%s", taskID, statusStr)
|
|
|
|
if matchStatus(statusStr, statusValues["succeeded"]) {
|
|
g.Log().Infof(ctx, "[PullTaskResult] 任务成功 taskID=%s", taskID)
|
|
return result, nil
|
|
}
|
|
|
|
if matchStatus(statusStr, statusValues["failed"]) {
|
|
errMsg := gconv.String(gjson.New(result).Get(errorPath).Val())
|
|
if errMsg == "" {
|
|
errMsg = "任务失败"
|
|
}
|
|
g.Log().Errorf(ctx, "[PullTaskResult] 任务失败 taskID=%s err=%s", taskID, errMsg)
|
|
return result, fmt.Errorf("任务失败: %s", errMsg)
|
|
}
|
|
|
|
time.Sleep(time.Duration(interval) * time.Second)
|
|
}
|
|
}
|
|
|
|
func extractTaskID(body, queryConfig map[string]any) (string, error) {
|
|
taskIDPath := gconv.String(queryConfig["task_id"])
|
|
taskID := gconv.String(gjson.New(body).Get(taskIDPath).Val())
|
|
if taskID == "" {
|
|
return "", fmt.Errorf("无法从路径 %s 提取 taskID", taskIDPath)
|
|
}
|
|
return taskID, nil
|
|
}
|
|
|
|
func buildQueryURL(queryConfig map[string]any, taskID string) string {
|
|
queryUrl := gconv.String(queryConfig["url"])
|
|
return replaceURLParams(queryUrl, map[string]any{"id": taskID})
|
|
}
|
|
|
|
func doQueryRequest(ctx context.Context, method, queryUrl string, reqBodyMap map[string]any, headMsg map[string]any) (map[string]any, error) {
|
|
var reqBody io.Reader
|
|
if method == "POST" {
|
|
bs, _ := json.Marshal(reqBodyMap)
|
|
reqBody = bytes.NewReader(bs)
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, method, queryUrl, reqBody)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("创建请求失败: %w", err)
|
|
}
|
|
|
|
for hk, hv := range ParseHeadMsgHeaders(headMsg) {
|
|
req.Header.Set(hk, hv)
|
|
}
|
|
|
|
client := &http.Client{Timeout: 30 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
raw, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return nil, nil
|
|
}
|
|
|
|
var result map[string]any
|
|
_ = json.Unmarshal(raw, &result)
|
|
return result, nil
|
|
}
|
|
|
|
func matchStatus(actual string, expected any) bool {
|
|
expectedStr := gconv.String(expected)
|
|
if actual == expectedStr {
|
|
return true
|
|
}
|
|
if arr, ok := expected.([]any); ok {
|
|
for _, item := range arr {
|
|
if actual == gconv.String(item) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func replaceURLParams(rawURL string, params map[string]any) string {
|
|
re := regexp.MustCompile(`\{([^}]+)}`)
|
|
return re.ReplaceAllStringFunc(rawURL, func(s string) string {
|
|
key := strings.Trim(s, "{}")
|
|
if val, ok := params[key]; ok {
|
|
return gconv.String(val)
|
|
}
|
|
return s
|
|
})
|
|
}
|