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.
221 lines
10 KiB
221 lines
10 KiB
using System.Threading.Tasks;
|
|
using System.Threading;
|
|
using AIK.Common.Interface;
|
|
using AIK.Common.SysCommon;
|
|
using AIK.Models.ApiModels;
|
|
using AIK.Models.ApiModels.Membership;
|
|
using AIK.Service.IService;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Serialization;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Net;
|
|
|
|
namespace AIK.Service.Service
|
|
{
|
|
public class MembershipService : IMembershipService
|
|
{
|
|
private static readonly JsonSerializerSettings JsonSettings = new()
|
|
{
|
|
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
|
NullValueHandling = NullValueHandling.Ignore
|
|
};
|
|
|
|
private readonly IHttpClientService _httpClientService;
|
|
private readonly IConfigurationService _configurationService;
|
|
private readonly ISettingsService _settingsService;
|
|
private readonly IRetryPolicyService _retryPolicyService;
|
|
private readonly ILogger<MembershipService> _logger;
|
|
|
|
public MembershipService(
|
|
IHttpClientService httpClientService,
|
|
IConfigurationService configurationService,
|
|
ISettingsService settingsService,
|
|
IRetryPolicyService retryPolicyService,
|
|
ILogger<MembershipService> logger)
|
|
{
|
|
_httpClientService = httpClientService;
|
|
_configurationService = configurationService;
|
|
_settingsService = settingsService;
|
|
_retryPolicyService = retryPolicyService;
|
|
_logger = logger;
|
|
}
|
|
|
|
public Task<List<MembershipModule>> GetModuleListAsync(string model = "key", CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
var url = BuildUrl(WebApiAddress.MembershipModuleList, new()
|
|
{
|
|
["model"] = string.IsNullOrWhiteSpace(model) ? "key" : model,
|
|
["language"] = GetLanguage()
|
|
});
|
|
|
|
var response = await _httpClientService.GetStringWithTimeoutAsync(url, TimeSpan.FromSeconds(15), cancellationToken);
|
|
var apiResponse = DeserializeResponse<List<MembershipModule>>(response, nameof(GetModuleListAsync));
|
|
return IsSuccess(apiResponse) ? apiResponse.Data ?? new List<MembershipModule>() : new List<MembershipModule>();
|
|
}, nameof(GetModuleListAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<ApiPageResult<MembershipRecord>> FindOpenedFunctionsAsync(string token, MembershipFindRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
request.Language ??= GetLanguage();
|
|
var url = BuildUrl(WebApiAddress.MembershipFind);
|
|
var json = JsonConvert.SerializeObject(request, JsonSettings);
|
|
var response = await _httpClientService.PostJsonWithTimeoutAndTokenAsync(url, json, token, TimeSpan.FromSeconds(15), cancellationToken);
|
|
return DeserializePageResponse<MembershipRecord>(response, nameof(FindOpenedFunctionsAsync));
|
|
}, nameof(FindOpenedFunctionsAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<ApiResponse<int>> OpenFunctionAsync(string token, OpenMembershipRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
request.Language ??= GetLanguage();
|
|
return await PostWithTokenAsync<int>(WebApiAddress.MembershipOpen, token, request, nameof(OpenFunctionAsync), cancellationToken);
|
|
}, nameof(OpenFunctionAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<ApiResponse> BindDeviceAsync(string token, BindMembershipDeviceRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
request.Language ??= GetLanguage();
|
|
var response = await PostWithTokenAsync<object>(WebApiAddress.MembershipBind, token, request, nameof(BindDeviceAsync), cancellationToken);
|
|
return ToUntypedResponse(response);
|
|
}, nameof(BindDeviceAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<bool> CheckPermissionAsync(string token, CheckMembershipPermissionRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
request.Language ??= GetLanguage();
|
|
var response = await PostWithTokenAsync<bool>(WebApiAddress.MembershipCheck, token, request, nameof(CheckPermissionAsync), cancellationToken);
|
|
return IsSuccess(response) && response.Data;
|
|
}, nameof(CheckPermissionAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<ApiResponse> ActivateDeviceAsync(string token, ActivateDeviceRequest request, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
request.Language ??= GetLanguage();
|
|
var response = await PostWithTokenAsync<object>(WebApiAddress.MembershipActivate, token, request, nameof(ActivateDeviceAsync), cancellationToken);
|
|
return ToUntypedResponse(response);
|
|
}, nameof(ActivateDeviceAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<BurnCountInfo?> GetBurnCountInfoAsync(string token, CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
var url = BuildUrl(WebApiAddress.MembershipFindCount);
|
|
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(url, token, TimeSpan.FromSeconds(15), cancellationToken);
|
|
var apiResponse = DeserializeResponse<BurnCountInfo>(response, nameof(GetBurnCountInfoAsync));
|
|
return IsSuccess(apiResponse) ? apiResponse.Data : null;
|
|
}, nameof(GetBurnCountInfoAsync), cancellationToken);
|
|
}
|
|
|
|
public Task<ApiResponse> AddBurnCountAsync(string token, string type = "ysjs", CancellationToken cancellationToken = default)
|
|
{
|
|
return _retryPolicyService.ExecuteWithRetryAsync(async () =>
|
|
{
|
|
var url = BuildUrl(WebApiAddress.MembershipAddCount, new()
|
|
{
|
|
["type"] = string.IsNullOrWhiteSpace(type) ? "ysjs" : type
|
|
});
|
|
|
|
var response = await _httpClientService.GetStringWithTimeoutAndTokenAsync(url, token, TimeSpan.FromSeconds(15), cancellationToken);
|
|
return ToUntypedResponse(DeserializeResponse<object>(response, nameof(AddBurnCountAsync)));
|
|
}, nameof(AddBurnCountAsync), cancellationToken);
|
|
}
|
|
|
|
private async Task<ApiResponse<T>> PostWithTokenAsync<T>(string path, string token, object request, string operationName, CancellationToken cancellationToken)
|
|
{
|
|
var url = BuildUrl(path);
|
|
var json = JsonConvert.SerializeObject(request, JsonSettings);
|
|
var response = await _httpClientService.PostJsonWithTimeoutAndTokenAsync(url, json, token, TimeSpan.FromSeconds(15), cancellationToken);
|
|
return DeserializeResponse<T>(response, operationName);
|
|
}
|
|
|
|
private string BuildUrl(string path, Dictionary<string, string?>? query = null)
|
|
{
|
|
var url = $"{_configurationService.ApiSettings.BaseUrl}{path}";
|
|
if (query == null || query.Count == 0)
|
|
{
|
|
return url;
|
|
}
|
|
|
|
var queryString = string.Join("&", query
|
|
.Where(item => !string.IsNullOrWhiteSpace(item.Value))
|
|
.Select(item => $"{WebUtility.UrlEncode(item.Key)}={WebUtility.UrlEncode(item.Value)}"));
|
|
return string.IsNullOrEmpty(queryString) ? url : $"{url}?{queryString}";
|
|
}
|
|
|
|
private string GetLanguage()
|
|
{
|
|
return string.IsNullOrWhiteSpace(_settingsService.Load().Language) ? "zh" : _settingsService.Load().Language;
|
|
}
|
|
|
|
private ApiResponse<T> DeserializeResponse<T>(string response, string operationName)
|
|
{
|
|
var apiResponse = JsonConvert.DeserializeObject<ApiResponse<T>>(response) ?? new ApiResponse<T>();
|
|
if (!IsSuccess(apiResponse))
|
|
{
|
|
_logger.LogWarning("{OperationName} failed. Code: {Code}, Message: {Message}, Response: {Response}", operationName, apiResponse.Code, apiResponse.Msg, response);
|
|
}
|
|
|
|
return apiResponse;
|
|
}
|
|
|
|
private ApiPageResult<T> DeserializePageResponse<T>(string response, string operationName)
|
|
{
|
|
var pageResponse = JsonConvert.DeserializeObject<ApiPageResponse<T>>(response) ?? new ApiPageResponse<T>();
|
|
if (pageResponse.Code != 1)
|
|
{
|
|
_logger.LogWarning("{OperationName} failed. Code: {Code}, Message: {Message}, Response: {Response}", operationName, pageResponse.Code, pageResponse.Msg, response);
|
|
return new ApiPageResult<T>();
|
|
}
|
|
|
|
return new ApiPageResult<T>
|
|
{
|
|
Records = pageResponse.Records ?? new List<T>(),
|
|
Total = pageResponse.Total,
|
|
Current = pageResponse.Current,
|
|
Size = pageResponse.Size,
|
|
Pages = pageResponse.Pages
|
|
};
|
|
}
|
|
|
|
private static bool IsSuccess<T>(ApiResponse<T> response)
|
|
{
|
|
return response.Code == 1;
|
|
}
|
|
|
|
private static ApiResponse ToUntypedResponse<T>(ApiResponse<T> response)
|
|
{
|
|
return new ApiResponse
|
|
{
|
|
Code = response.Code,
|
|
Msg = response.Msg,
|
|
I18nMsg = response.I18nMsg,
|
|
Data = response.Data,
|
|
Dict = response.Dict
|
|
};
|
|
}
|
|
|
|
private sealed class ApiPageResponse<T> : ApiPageResult<T>
|
|
{
|
|
public int Code { get; set; }
|
|
public string? Msg { get; set; }
|
|
public string? I18nMsg { get; set; }
|
|
public Dictionary<string, object>? Dict { get; set; }
|
|
}
|
|
}
|
|
}
|
|
|