191 lines
7.2 KiB
C#
191 lines
7.2 KiB
C#
|
||
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 originResult = await TryOriginApiAsync(mJApiTasks.ThirdPartyTaskId);
|
||
var properties = new Dictionary<string, object>();
|
||
if (string.IsNullOrWhiteSpace(originResult))
|
||
{
|
||
originResult = await TryBackupApiAsync(mJApiTasks.ThirdPartyTaskId, useToken);
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(originResult))
|
||
{
|
||
// 没有找到数据
|
||
_logger.LogInformation($"备用API没有返回数据,TaskId: {mJApiTasks.TaskId}");
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 不为空 开始解析数据
|
||
properties = JsonConvert.DeserializeObject<Dictionary<string, object>>(originResult);
|
||
}
|
||
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?> TryOriginApiAsync(string id)
|
||
{
|
||
string originUrl = $"https://mjapi.bzu.cn/mj/task/{id}/fetch";
|
||
|
||
// 判断 原始token 不存在 直接 返回空
|
||
string orginToken = await _tokenService.GetOriginToken();
|
||
if (string.IsNullOrWhiteSpace(orginToken))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
using var client = new HttpClient();
|
||
client.DefaultRequestHeaders.Add("Authorization", orginToken);
|
||
client.Timeout = TimeSpan.FromSeconds(30);
|
||
|
||
var response = await client.GetAsync(originUrl);
|
||
var content = await response.Content.ReadAsStringAsync();
|
||
// 判断是不是返回空
|
||
if ((int)response.StatusCode == 204 || string.IsNullOrWhiteSpace(content))
|
||
{
|
||
return string.Empty;
|
||
}
|
||
if (!response.IsSuccessStatusCode)
|
||
{
|
||
_logger.LogWarning($"源API调用返回错误状态码,TaskId: {id}, StatusCode: {response.StatusCode}");
|
||
return null;
|
||
}
|
||
return content;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogWarning(ex, "原始API调用失败,TaskId: {TaskId},准备尝试备用API", id);
|
||
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;
|
||
}
|
||
|
||
}
|
||
}
|