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 _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 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 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(jsonstr) ?? null; } else { _logger.LogWarning("获取用户信息数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString()); return null; } } catch (Exception ex) { _logger.LogError(ex, "获取Banner失败"); throw; // 重新抛出,让重试机制处理 } }, nameof(GetUserInfo)); } #endregion /// /// 账密登录:POST {BaseUrl}/prod-api/work_main/login。 /// 参数 account/code/password/type 均非必填(string)。 /// 成功(code=1):msg 为 JWT Token;失败(code!=1):msg 为错误信息。 /// 登录失败不做重试(密码错误重试无意义)。 /// 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}"); } } /// /// 发送注册验证码:GET {BaseUrl}/prod-api/work_sms/sms/send_code?phone=xxx。 /// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。 /// public Task<(bool Success, string Message)> SendRegisterCodeAsync(string phone) { return SmsRequestAsync(WebApiAddress.SendCode, new Dictionary { ["phone"] = phone }); } /// /// 发送登录验证码:GET {BaseUrl}/prod-api/work_sms/sms/send_login?phone=xxx。 /// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。 /// public Task<(bool Success, string Message)> SendLoginCodeAsync(string phone) { return SmsRequestAsync(WebApiAddress.SendLoginCode, new Dictionary { ["phone"] = phone }); } /// /// 验证验证码:GET {BaseUrl}/prod-api/work_sms/sms/check_code?code=xxx&phone=xxx[&type=]。 /// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。 /// public Task<(bool Success, string Message)> CheckVerifyCodeAsync(string phone, string code, string type = "") { var query = new Dictionary { ["phone"] = phone, ["code"] = code }; if (!string.IsNullOrEmpty(type)) { query["type"] = type; } return SmsRequestAsync(WebApiAddress.CheckCode, query); } /// /// 发送邮箱验证码:GET {BaseUrl}/prod-api/work_sms/email/send_code?address=xxx[&type=]。 /// type 为语言(默认中文,en:英文,可选),成功(code=1)返回 (true, 空)。 /// public Task<(bool Success, string Message)> SendEmailCodeAsync(string address, string type = "") { var query = new Dictionary { ["address"] = address }; if (!string.IsNullOrEmpty(type)) { query["type"] = type; } return SmsRequestAsync(WebApiAddress.EmailSendCode, query); } /// /// 验证邮箱验证码:GET {BaseUrl}/prod-api/work_sms/email/check_code?address=xxx&code=xxx。 /// 成功(code=1)返回 (true, 空);失败(code!=1)返回 (false, 错误信息)。 /// public Task<(bool Success, string Message)> CheckEmailCodeAsync(string address, string code) { return SmsRequestAsync(WebApiAddress.EmailCheckCode, new Dictionary { ["address"] = address, ["code"] = code }); } /// 短信服务接口公共实现(GET + query 参数,成功状态码为 1)。 private async Task<(bool Success, string Message)> SmsRequestAsync(string endpoint, Dictionary 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}"); } } /// /// 手机号注册:POST {BaseUrl}/prod-api/work_main/user/phone_register。 /// code(验证码)、phone、psw(密码)必填;其余可选。 /// 注意:注册接口成功状态码为 1,响应 data 为 boolean。 /// 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); } /// /// 邮箱注册:POST {BaseUrl}/prod-api/work_main/user/user/email_register。 /// code(验证码)、email、psw(密码)必填;其余可选。 /// 注意:注册接口成功状态码为 1,响应 data 为 boolean。 /// 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); } /// 手机号/邮箱注册公共实现(两接口参数结构一致,仅路径不同)。 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?> 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>(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> GetBannerCache() { var result = await _cacheService.GetOrCreateAsync>( key: CacheKey_Banner, dataFetchFunc: () => GetBanner(""), expiry: _cacheExpiry ); return result ?? new List(); } #endregion #region 用户信息和积分相关 public async Task 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(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 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(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 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(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 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(jsonstr) ?? null; } else { _logger.LogWarning("获取用户积分数据失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString()); return null; } } catch (Exception ex) { _logger.LogError(ex, "获取用户积分数据失败: {Token}", token); throw; // 重新抛出,让重试机制处理 } }, nameof(GetUserIntegralHistroy)); } /// /// 用户烧录信息添加 /// /// /// /// /// public Task BurnAddInfo(string token, BurnItem burnItem) { throw new NotImplementedException(); } /// /// 添加积分 /// /// /// /// /// public Task AddIntegral(string token, BurnKeyItem burnKeyItem) { throw new NotImplementedException(); } #endregion #region K3tool 云数据包相关 /// /// 获取K3tool 云数据包信息 /// /// /// /// /// public async Task 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(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 胎压 /// /// 获取所有胎压类型 /// /// /// /// /// public async Task?> 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>(jsonstr) ?? null; } else { _logger.LogWarning("获取胎压类型失败,状态码: {Status}, 响应: {Response}", status, jobj.ToString()); return null; } } catch (Exception ex) { _logger.LogError(ex, "获取胎压类型失败: {Token}", token); throw; // 重新抛出,让重试机制处理 } }, nameof(GetTpmsType)); } #endregion } }