兼容win7版应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

621 lines
26 KiB

using System.Threading.Tasks;
using System.Threading;
using AIK.Common.Interface;
using AIK.Common.SysCommon;
using AIK.Common.SysCommon.UserCommon;
using AIK.Models;
using AIK.Models.ApiModels;
using AIK.Models.ApiModels.Banner;
using AIK.Models.ApiModels.Burn;
using AIK.Models.ApiModels.CloudData;
using AIK.Models.ApiModels.Integral;
using AIK.Models.ApiModels.Record;
using AIK.Models.ApiModels.TpmsModels;
using AIK.Models.ApiModels.Version;
using AIK.Models.BannerModels;
using AIK.Models.HttpPolicy;
using AIK.Service.IService;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
namespace AIK.Service.Service
{
public class AikDataService : IAikDataService
{
private readonly IDataCacheService _cacheService;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfigurationService _configurationService;
private readonly ILogger<AikDataService> _logger;
private readonly IRetryPolicyService _retryPolicyService;
private readonly RetryPolicyConfig _retryConfig;
private readonly IHttpClientService _httpClientService;
private readonly ISettingsService _settingsService;
private const string CacheKey_Banner = "banner_data";
private readonly TimeSpan _cacheExpiry = TimeSpan.FromHours(3);//默认3个小时有效期
// 通过构造函数注入
public AikDataService(IDataCacheService cacheService, IHttpClientFactory httpClientFactory, ILogger<AikDataService> logger, IConfigurationService configurationService, IRetryPolicyService retryPolicyService, IHttpClientService httpClientService, ISettingsService settingsService)
{
_cacheService = cacheService;
_httpClientFactory = httpClientFactory;
_configurationService = configurationService;
_logger = logger;
_retryPolicyService = retryPolicyService;
_httpClientService = httpClientService;
_retryConfig = new RetryPolicyConfig
{
MaxRetryCount = 3,
RetryDelay = TimeSpan.FromSeconds(1),
DefaultTimeout = TimeSpan.FromSeconds(15)
};
_cacheExpiry = TimeSpan.FromHours(_configurationService.CacheSettings.DataCacheExpiryHours);
_settingsService = settingsService;
}
#region App版本相关
public async Task<AppVersionInfo?> GetAppVersionInfo(string type)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.AppNew}?type={type}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAsync(
url,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj["data"]?.ToString();
return JsonConvert.DeserializeObject<AppVersionInfo>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取Banner失败");
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetUserInfo));
}
#endregion
/// <summary>
/// 账密登录:POST {BaseUrl}/prod-api/work_main/login。
/// 参数 account/code/password/type 均非必填(string)。
/// 成功(code=1):msg 为 JWT Token;失败(code!=1):msg 为错误信息。
/// 登录失败不做重试(密码错误重试无意义)。
/// </summary>
public async Task<(bool Success, string Message)> LoginByAccountAsync(string account, string code, string password, string type)
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.AccountLogin}";
var requestData = new
{
account = account,
code = code,
password = password,
type = type
};
string sendData = JsonConvert.SerializeObject(requestData);
var response = await _httpClientService.PostJsonWithTimeoutAsync(
url,
sendData,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
string status = jobj["code"]?.ToString() ?? string.Empty;
string msg = jobj["msg"]?.ToString() ?? string.Empty;
if (status == "1")
{
return (true, msg); // msg 为 JWT Token
}
_logger.LogWarning("账密登录失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return (false, string.IsNullOrEmpty(msg) ? "登录失败" : msg);
}
catch (Exception ex)
{
_logger.LogError(ex, "账密登录请求异常");
return (false, $"网络请求失败: {ex.Message}");
}
}
/// <summary>
/// 发送注册验证码:GET {BaseUrl}/prod-api/work_sms/sms/send_code?phone=xxx。
/// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。
/// </summary>
public Task<(bool Success, string Message)> SendRegisterCodeAsync(string phone)
{
return SmsRequestAsync(WebApiAddress.SendCode, new Dictionary<string, string> { ["phone"] = phone });
}
/// <summary>
/// 发送登录验证码:GET {BaseUrl}/prod-api/work_sms/sms/send_login?phone=xxx。
/// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。
/// </summary>
public Task<(bool Success, string Message)> SendLoginCodeAsync(string phone)
{
return SmsRequestAsync(WebApiAddress.SendLoginCode, new Dictionary<string, string> { ["phone"] = phone });
}
/// <summary>
/// 验证验证码:GET {BaseUrl}/prod-api/work_sms/sms/check_code?code=xxx&amp;phone=xxx[&amp;type=]。
/// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。
/// </summary>
public Task<(bool Success, string Message)> CheckVerifyCodeAsync(string phone, string code, string type = "")
{
var query = new Dictionary<string, string>
{
["phone"] = phone,
["code"] = code
};
if (!string.IsNullOrEmpty(type))
{
query["type"] = type;
}
return SmsRequestAsync(WebApiAddress.CheckCode, query);
}
/// <summary>
/// 发送邮箱验证码:GET {BaseUrl}/prod-api/work_sms/email/send_code?address=xxx[&amp;type=]。
/// type 为语言(默认中文,en:英文,可选),成功(code=1)返回 (true, 空)。
/// </summary>
public Task<(bool Success, string Message)> SendEmailCodeAsync(string address, string type = "")
{
var query = new Dictionary<string, string> { ["address"] = address };
if (!string.IsNullOrEmpty(type))
{
query["type"] = type;
}
return SmsRequestAsync(WebApiAddress.EmailSendCode, query);
}
/// <summary>
/// 验证邮箱验证码:GET {BaseUrl}/prod-api/work_sms/email/check_code?address=xxx&amp;code=xxx。
/// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。
/// </summary>
public Task<(bool Success, string Message)> CheckEmailCodeAsync(string address, string code)
{
return SmsRequestAsync(WebApiAddress.EmailCheckCode, new Dictionary<string, string>
{
["address"] = address,
["code"] = code
});
}
/// <summary>短信服务接口公共实现(GET + query 参数,成功状态码为 1)。</summary>
private async Task<(bool Success, string Message)> SmsRequestAsync(string endpoint, Dictionary<string, string> query)
{
try
{
var sb = new StringBuilder();
foreach (var kv in query)
{
if (sb.Length > 0)
{
sb.Append('&');
}
sb.Append(Uri.EscapeDataString(kv.Key)).Append('=').Append(Uri.EscapeDataString(kv.Value));
}
string url = $"{_configurationService.ApiSettings.BaseUrl}{endpoint}";
if (sb.Length > 0)
{
url += "?" + sb;
}
var response = await _httpClientService.GetStringWithTimeoutAsync(url, TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
string status = jobj["code"]?.ToString() ?? string.Empty;
string msg = jobj["msg"]?.ToString() ?? string.Empty;
if (status == "1")
{
return (true, string.Empty);
}
_logger.LogWarning("短信接口失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return (false, string.IsNullOrEmpty(msg) ? "请求失败" : msg);
}
catch (Exception ex)
{
_logger.LogError(ex, "短信接口请求异常");
return (false, $"网络请求失败: {ex.Message}");
}
}
/// <summary>
/// 手机号注册:POST {BaseUrl}/prod-api/work_main/user/phone_register。
/// code(验证码)、phone、psw(密码)必填;其余可选。
/// 注意:注册接口成功状态码为 1,响应 data 为 boolean。
/// </summary>
public Task<(bool Success, string Message)> RegisterByPhoneAsync(string code, string phone, string psw, string nickName = "", string sex = "", string local = "", string image = "")
{
return RegisterCoreAsync(WebApiAddress.PhoneRegister, code, phone, string.Empty, psw, nickName, sex, local, image);
}
/// <summary>
/// 邮箱注册:POST {BaseUrl}/prod-api/work_main/user/user/email_register。
/// code(验证码)、email、psw(密码)必填;其余可选。
/// 注意:注册接口成功状态码为 1,响应 data 为 boolean。
/// </summary>
public Task<(bool Success, string Message)> RegisterByEmailAsync(string code, string email, string psw, string nickName = "", string sex = "", string local = "", string image = "")
{
return RegisterCoreAsync(WebApiAddress.EmailRegister, code, string.Empty, email, psw, nickName, sex, local, image);
}
/// <summary>手机号/邮箱注册公共实现(两接口参数结构一致,仅路径不同)。</summary>
private async Task<(bool Success, string Message)> RegisterCoreAsync(
string endpoint, string code, string phone, string email, string psw,
string nickName, string sex, string local, string image)
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{endpoint}";
var requestData = new
{
code = code,
phone = phone,
email = email,
psw = psw,
nickName = nickName,
sex = sex,
local = local,
image = image
};
string sendData = JsonConvert.SerializeObject(requestData);
var response = await _httpClientService.PostJsonWithTimeoutAsync(
url,
sendData,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
string status = jobj["code"]?.ToString() ?? string.Empty;
string msg = jobj["msg"]?.ToString() ?? string.Empty;
if (status == "1")
{
return (true, string.Empty);
}
_logger.LogWarning("注册失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return (false, string.IsNullOrEmpty(msg) ? "注册失败" : msg);
}
catch (Exception ex)
{
_logger.LogError(ex, "注册请求异常");
return (false, $"网络请求失败: {ex.Message}");
}
}
#region Banner相关
public async Task<List<BannerModel>?> GetBanner(string languagecode = "")
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.BannerAll}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAsync(
url,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj["data"]?.ToString();
return JsonConvert.DeserializeObject<List<BannerModel>>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取Banner失败");
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetUserInfo));
}
public async Task<List<BannerModel>> GetBannerCache()
{
var result = await _cacheService.GetOrCreateAsync<List<BannerModel>>(
key: CacheKey_Banner,
dataFetchFunc: () => GetBanner(""),
expiry: _cacheExpiry
);
return result ?? new List<BannerModel>();
}
#endregion
#region 用户信息和积分相关
public async Task<UserModel?> GetUserInfo(string token)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.CommonProfile}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(
url,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj["data"]["user"]?.ToString();
return JsonConvert.DeserializeObject<UserModel>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用户信息数据失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetUserInfo));
}
public async Task<IntegralModel?> GetUserIntegral(string token)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.Integral}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(
url,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj["data"]?.ToString();
return JsonConvert.DeserializeObject<IntegralModel>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用户信息数据失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetUserIntegral));
}
public async Task<ApiResponseRecord> GetKeyLogList(string token, int currentindex = 1, int pagesize = 20)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.LogList}";
var requestData = new
{
pageNum = currentindex,
pageSize = pagesize,
language = _settingsService.Load().Language
};
string sendData = JsonConvert.SerializeObject(requestData);
// 使用带超时的HTTP请求
var response = await _httpClientService.PostJsonWithTimeoutAndTokenAsync(
url,
sendData,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj?.ToString();
return JsonConvert.DeserializeObject<ApiResponseRecord>(jsonstr) ?? new ApiResponseRecord();
}
else
{
_logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return new ApiResponseRecord();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用户信息数据失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetKeyLogList));
}
public async Task<ApiResponseIntegralRecord?> GetUserIntegralHistroy(string token)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.IntegralHistroy}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(
url,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj?.ToString();
return JsonConvert.DeserializeObject<ApiResponseIntegralRecord>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取用户积分数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取用户积分数据失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetUserIntegralHistroy));
}
/// <summary>
/// 用户烧录信息添加
/// </summary>
/// <param name="token"></param>
/// <param name="burnItem"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task<ApiResponse> BurnAddInfo(string token, BurnItem burnItem)
{
throw new NotImplementedException();
}
/// <summary>
/// 添加积分
/// </summary>
/// <param name="token"></param>
/// <param name="burnKeyItem"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task<ApiResponse> AddIntegral(string token, BurnKeyItem burnKeyItem)
{
throw new NotImplementedException();
}
#endregion
#region K3tool 云数据包相关
/// <summary>
/// 获取K3tool 云数据包信息
/// </summary>
/// <param name="token"></param>
/// <param name="ossType"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<ApiResponseOssData?> GetOssDataCache(string token, string ossType = "K3tool_bin")
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
//测试 等待调整
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.OssDataCache}/{WebApiAddress.K3ToolBin}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(
url,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj?.ToString();
return JsonConvert.DeserializeObject<ApiResponseOssData>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取云数据数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取云数据数据失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetOssDataCache));
}
#endregion
#region 胎压
/// <summary>
/// 获取所有胎压类型
/// </summary>
/// <param name="token"></param>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<List<TpmsType>?> GetTpmsType(string token, int? id)
{
return await _retryPolicyService.ExecuteWithRetryAsync(async () =>
{
try
{
string url = $"{_configurationService.ApiSettings.BaseUrl}{WebApiAddress.TpmsType}?parentId={id}&language={_settingsService.Load().Language}";
// 使用带超时的HTTP请求
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(
url,
token,
TimeSpan.FromSeconds(15));
var jobj = JObject.Parse(response);
var status = jobj["code"]?.ToString();
if (status == "1")
{
var jsonstr = jobj["data"]?.ToString();
return JsonConvert.DeserializeObject<List<TpmsType>>(jsonstr) ?? null;
}
else
{
_logger.LogWarning("获取胎压类型失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString());
return null;
}
}
catch (Exception ex)
{
_logger.LogError(ex, "获取胎压类型失败: {Token}", token);
throw; // 重新抛出,让重试机制处理
}
}, nameof(GetTpmsType));
}
#endregion
}
}