148 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using LMS.Common.Extensions;
using LMS.DAO;
using LMS.Repository.DB;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace LMS.Tools.MJPackage
{
public class TaskService(ITokenService tokenService, ILogger<TaskService> logger, ApplicationDbContext dbContext, ITaskConcurrencyManager taskConcurrencyManager) : ITaskService
{
private readonly ITokenService _tokenService = tokenService;
private readonly ILogger<TaskService> _logger = logger;
private readonly ApplicationDbContext _dbContext = dbContext;
private readonly ITaskConcurrencyManager _taskConcurrencyManager = taskConcurrencyManager;
public async Task<Dictionary<string, object>?> FetchTaskAsync(MJApiTasks mJApiTasks)
{
try
{
// 获取UseToken先尝试 Token再尝试 TokenId
var tokenConfig = await _tokenService.GetTokenAsync(mJApiTasks.Token);
string useToken = string.Empty;
if (tokenConfig == null)
{
// Token 没找到 尝试用 TokenId 查找
MJApiTokens? mJApiTokens = await _tokenService.GetMJapiTokenByIdAsync(mJApiTasks.TokenId);
if (mJApiTokens == null)
{
return null;
}
useToken = mJApiTokens.UseToken;
}
else
{
useToken = tokenConfig.UseToken;
}
if (string.IsNullOrWhiteSpace(useToken))
{
_logger.LogInformation($"Token is empty for task ID: {mJApiTasks.TaskId}");
return null;
}
// 尝试备用API
var backupResult = await TryBackupApiAsync(mJApiTasks.ThirdPartyTaskId, useToken);
if (string.IsNullOrWhiteSpace(backupResult))
{
// 没有找到数据
_logger.LogInformation($"备用API没有返回数据TaskId: {mJApiTasks.TaskId}");
return null;
}
var properties = new Dictionary<string, object>();
try
{
// 不为空 开始解析数据
properties = JsonConvert.DeserializeObject<Dictionary<string, object>>(backupResult);
}
catch (JsonException ex)
{
_logger.LogError($"解析备用API返回数据失败: {ex.Message}");
return null;
}
if (properties == null)
{
_logger.LogInformation($"备用API返回数据为空TaskId: {mJApiTasks.TaskId}");
return null;
}
return properties;
}
catch (Exception ex)
{
// 记录异常日志
_logger.LogError($"Error fetching task: {ex.Message}");
return null;
}
}
private async Task<string?> TryBackupApiAsync(string id, string useToken)
{
string mjAPIBasicUrl = await _tokenService.GetMJAPIBasicUrl();
string backupUrl = $"{mjAPIBasicUrl}/mj/task/{id}/fetch";
const int maxRetries = 3;
const int baseDelayMs = 1000;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "sk-" + useToken);
client.Timeout = TimeSpan.FromSeconds(30);
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
var response = await client.GetAsync(backupUrl);
var content = await response.Content.ReadAsStringAsync();
// 判断请求是不是报错
if (!response.IsSuccessStatusCode)
{
_logger.LogWarning("备用API调用返回错误状态码TaskId: {TaskId}, Attempt: {Attempt}, StatusCode: {StatusCode}",
id, attempt, response.StatusCode);
return null;
}
return content;
}
catch (Exception ex) when (IsRetriableException(ex))
{
if (attempt < maxRetries)
{
var delay = baseDelayMs * (int)Math.Pow(2, attempt - 1);
_logger.LogWarning(ex, "备用API调用失败TaskId: {TaskId}, Attempt: {Attempt}, 将在{Delay}ms后重试",
id, attempt, delay);
await Task.Delay(delay);
}
else
{
_logger.LogError(ex, "备用API调用最终失败TaskId: {TaskId}, MaxAttempts: {MaxAttempts}",
id, maxRetries);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "备用API调用发生不可重试异常TaskId: {TaskId}, Attempt: {Attempt}",
id, attempt);
break;
}
}
return null;
}
private static bool IsRetriableException(Exception ex)
{
return ex is HttpRequestException ||
ex is TaskCanceledException ||
ex is SocketException;
}
}
}