using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using TapSDK.UI;
using TapSDK.Compliance.Internal;
using TapSDK.Compliance.Model;
using TapSDK.Core;
using TapSDK.Core.Internal.Utils;
using TapSDK.Login;
using UnityEngine;
using Network = TapSDK.Compliance.Internal.Network;
using Random = System.Random;
using System.Text;
using TapSDK.Core.Internal.Log;
namespace TapSDK.Compliance
{
public abstract class BaseComplianceWorker {
protected TapTapComplianceOption config => TapTapComplianceManager.ComplianceConfig;
#region Abstract
static readonly string USER_ANTI_FILENAME = "user_anti_config";
// 本地基准时间戳
private long BaseLocalTime = 0;
//获取本地时间戳时,应用运行的时间
private long BaseLocalStartUpTime = 0;
///
/// 激活手动认证
///
protected abstract Task VerifyManuallyAsync();
///
/// 检查未成年人可玩性
///
///
protected abstract PlayableResult CheckOfflineMinorPlayable();
///
/// 直接通过 Tap 账号获取实名制信息
///
///
protected abstract Task InternalStartup(string userId);
#endregion
#region Virutal
///
/// 检查可玩性后,已知成年人时的处理
///
///
///
protected virtual void OnCheckedPlayableWithAdult(PlayableResult playable)
{
TryStartPoll();
}
///
/// 检查可玩性后,已知未成年人时的处理
///
///
///
protected virtual async Task OnCheckedPlayableWithMinorAsync(PlayableResult playable)
{
if (playable.RemainTime > 0)
{
TapTapComplianceManager.ShowAntiAddictionTip();
}
var tcs = new TaskCompletionSource();
Action onOk;
if (playable.RemainTime > 0) {
onOk = () => {
tcs.TrySetResult(StartUpResult.LOGIN_SUCCESS);
TryStartPoll();
};
}
else {
tcs.TrySetResult(StartUpResult.PERIOD_RESTRICT);
onOk = () => {
Application.Quit();
};
}
Action onSwitchAccount = null;
if (config.showSwitchAccount && playable.RemainTime <= 0) {
onSwitchAccount = () => {
Logout(false);
TapTapCompliance.OnInvokeExternalCallback(StartUpResult.SWITCH_ACCOUNT, null);
};
}
TapComplianceUI.OpenHealthReminderPanel(playable, onOk, onSwitchAccount);
return await tcs.Task;
}
///
/// 检查可玩性,如果出现异常就会用本地的计算方式
///
///
protected virtual async Task CheckPlayableAsyncWithFallback()
{
try
{
var playableResult = await CheckPlayableAsync();
return playableResult;
}
catch (ComplianceException e)
{
if (e.IsTokenExpired()
|| e.Code < 500 || !TapTapComplianceManager.CurrentUserAntiResult.policy.active.Equals(ComplianceConst.POLICY_ACTIVE_TIME_RANGE))
{
throw;
}
return CheckOfflinePlayable();
}
catch (Exception e)
{
TapLog.Error(e);
// 单机判断是否可玩
return CheckOfflinePlayable();
}
}
///
/// 获取用户配置,失败时,会尝试获取本地配置,如果都无效,抛出异常
///
///
protected virtual async Task CheckUserConfigAsyncWithFallback()
{
string filename = Tool.EncryptString(Verification.Current.UserId);
Persistence persistence = new Persistence(Path.Combine(
USER_ANTI_FILENAME,
filename));
UserComplianceConfigResult result = await persistence.Load();
try
{
UserComplianceConfigResult serverResult = await Network.CheckUserConfig();
if(serverResult != null){
await persistence.Save(serverResult);
TapTapComplianceManager.CurrentSession = GenerateSession();
}
return serverResult;
}
catch (ComplianceException e)
{
if (e.IsTokenExpired() || e.Code < 500)
{
throw;
}else{
if(result != null){
ResetBaseLocalTime();
TapTapComplianceManager.CurrentSession = GenerateSession();
return result;
}else{
throw;
}
}
}
catch (Exception e)
{
TapLog.Error(e.Message ?? "");
if(result == null){
throw;
}else{
ResetBaseLocalTime();
TapTapComplianceManager.CurrentSession = GenerateSession();
return result;
}
}
}
private void ResetBaseLocalTime(){
if(BaseLocalTime > 0){
return;
}
BaseLocalTime = DateTimeOffset.Now.ToUnixTimeSeconds();
BaseLocalStartUpTime = (long)Time.realtimeSinceStartup;
TapLog.Log(" current local time " + DateTimeOffset.Now);
}
///
/// 获取基于本地时间的当前时间戳,用于离线心跳计算
///
///
protected long GetCurrentLocalTime(){
long currentStartUpTime = (long) Time.realtimeSinceStartup;
return BaseLocalTime + currentStartUpTime - BaseLocalStartUpTime;
}
private string GenerateSession()
{
const string baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = new Random();
var builder = new StringBuilder();
int l = baseStr.Length;
for (var i = 0; i < 32; i++)
{
var number = random.Next(l);
builder.Append(baseStr[number]);
}
return builder.ToString();
}
///
/// 检查可玩性
///
/// 当内部发生错误的时候,是否抛出异常.默认不抛出异常,就会按照本地规则计算playable
///
protected virtual async Task CheckPlayableAsync()
{
try
{
var playableResult = await Network.CheckPlayable();
return playableResult;
}
catch (Exception e)
{
TapLog.Error(e.Message ?? "");
throw;
}
}
///
/// 本地判断可玩性
///
///
protected virtual PlayableResult CheckOfflinePlayable()
{
TapLog.Log("CheckOfflinePlayable");
// 成年人
if (Verification.IsAdult)
{
// 可玩
return new PlayableResult
{
RemainTime = 9999
};
}
return CheckOfflineMinorPlayable();
}
///
/// 是否需要开启轮询检查可玩性
///
///
protected virtual bool IsNeedStartPoll()
{
return !Verification.IsAdult || Config.NeedUploadUserAction;
}
///
/// 轮询时,检查可玩性判断
///
///
public virtual async Task CheckPlayableOnPollingAsync()
{
try
{
var playable = await CheckPlayableAsyncWithFallback();
if (playable.RemainTime <= 0)
{
OnUnplayablePostPoll(playable);
}
return playable;
}
catch (Exception e)
{
if (e is ComplianceException aae && aae.IsTokenExpired())
{
Logout();
TapTapCompliance.OnInvokeExternalCallback(StartUpResult.EXITED, null);
return new PlayableResult { RemainTime = 0 };
}
else
{
CompliancePoll.Logout();
TapTapCompliance.OnInvokeExternalCallback(StartUpResult.INVALID_CLIENT_OR_NETWORK_ERROR, null);
return new PlayableResult { RemainTime = 0 };
}
}
}
///
/// 轮询时,发现不可玩处理
///
///
protected virtual void OnUnplayablePostPoll(PlayableResult playable)
{
Action onExitGame = Application.Quit;
Action onSwitch = null;
if (config.showSwitchAccount && playable.RemainTime <= 0)
{
onSwitch = () => {
Logout(false);
TapTapCompliance.OnInvokeExternalCallback(StartUpResult.SWITCH_ACCOUNT, null);
};
}
TapTapCompliance.OnInvokeExternalCallback(StartUpResult.PERIOD_RESTRICT, null);
TapComplianceUI.OpenHealthReminderPanel(playable, onExitGame, onSwitch);
}
///
/// 通过检查,发现不可支付时的处理
///
///
protected virtual void OnCheckedUnpayable(PayableResult payable)
{
//当服务端返回提示文案无效时,不显示
if(payable.Title != null && payable.Title.Length > 0 &&
payable.Content != null && payable.Content.Length > 0){
TapComplianceUI.OpenHealthPaymentPanel(payable);
}
}
///
/// 登出处理
///
public virtual void Logout(bool needClearCache = true)
{
if(needClearCache){
string filename = Tool.EncryptString(Verification.Current.UserId);
Persistence persistence = new Persistence(Path.Combine(
USER_ANTI_FILENAME,
filename));
persistence.Delete();
}
Verification.Logout(needClearCache);
CompliancePoll.Logout();
TapTapComplianceManager.UserId = null;
}
#endregion
#region Internal
public async Task StartUp(string userId) {
await FetchVerificationAsync(userId);
if (Verification.Current == null || Verification.IsVerifyFailed)
{
TapLog.Log("try get token internal by UI");
var result = await InternalStartup(userId);
// 目前只会返回 9002 和 0-认证成功
// 9002 是 StartUpResult.REAL_NAME_STOP
if (result != 0)
{
return result;
}
}
else if (Verification.IsVerifing)
{
return await ShowVerifingTip();
}
else
{
UIManager.Instance.CloseLoading();
}
return await OnVerificationFetched();
}
///
/// 显示实名中提示
///
internal async Task ShowVerifingTip()
{
var task = new TaskCompletionSource();
var tip = Config.GetInputIdentifyBlockingTip();
Action onOk = () =>
{
TapLog.Log("[TapTap: ChinaCompliance] 认证中,实名取消!");
task.TrySetResult(StartUpResult.REAL_NAME_STOP);
};
TapComplianceUI.OpenHealthPaymentPanel(tip.Title, tip.Content, tip.PositiveButtonText, onOk);
return await task.Task;
}
///
/// 获得实名信息
///
public async Task FetchVerificationAsync(string userId)
{
// 拉取服务端实名信息
try
{
await Verification.Fetch(userId);
UIManager.Instance.CloseLoading();
}
catch (Exception e)
{
TapLog.Error(e.Message ?? "");
UIManager.Instance.CloseLoading();
//所有错误跳过,执行实名
}
}
///
/// 获得实名信息后的处理
///
///
public async Task OnVerificationFetched() {
return await ValidateUserConfigAsync();
}
private async Task ValidateUserConfigAsync(){
do {
try{
UserComplianceConfigResult result = await CheckUserConfigAsyncWithFallback();
TapTapComplianceManager.CurrentUserAntiResult = result;
await Verification.setAgeState(result.userState.ageLimit, result.userState.isAdult);
// 适龄限制判断
if (!result.ageCheckResult.allow) {
return StartUpResult.AGE_LIMIT;
}
// 检查时长
else{
return await ValidatePlayableAsync();
}
}
catch (Exception e){
if (e is ComplianceException aae && aae.IsTokenExpired())
{
//用户登出
Logout();
return StartUpResult.EXITED;
}
else
{
return StartUpResult.INVALID_CLIENT_OR_NETWORK_ERROR;
}
}
}while (true);
}
///
/// 检查可玩性
///
///
private async Task ValidatePlayableAsync()
{
int tryCount = 0;
do {
try{
tryCount++;
PlayableResult playable = await CheckPlayableAsyncWithFallback();
TapTapComplianceManager.CurrentPlayableResult = playable;
// 2.1 成年人-后处理
if (Verification.Current.CheckIsAdult) {
OnCheckedPlayableWithAdult(playable);
return StartUpResult.LOGIN_SUCCESS;
}
// 2.2 未成年人-后处理
else{
return await OnCheckedPlayableWithMinorAsync(playable);
}
}
catch (Exception e){
TapLog.Log("ValidatePlayableAsync ERROR = " + e.Message + " stack = " + e.StackTrace);
if (e is ComplianceException aae && aae.IsTokenExpired())
{
//用户登出
Logout();
return StartUpResult.EXITED;
}else{
return StartUpResult.INVALID_CLIENT_OR_NETWORK_ERROR;
}
}
}while (true);
}
///
/// 尝试开启轮询检查
///
protected void TryStartPoll()
{
TapLog.Log("TryStartPoll ");
if (IsNeedStartPoll())
{
TapLog.Log("TryStartPoll interval = " + TapTapComplianceManager.CurrentUserAntiResult.policy.heartbeatInterval);
CompliancePoll.StartUp(TapTapComplianceManager.CurrentUserAntiResult.policy.heartbeatInterval);
}
}
///
/// 检查是否可以支付
///
///
///
public async virtual Task CheckPayableAsync(long amount)
{
PayableResult payable = await Network.CheckPayable(amount);
if (!payable.Status)
{
OnCheckedUnpayable(payable);
}
return payable;
}
///
/// 提交充值结果
///
///
///
public virtual Task SubmitPayResult(long amount)
{
return Network.SubmitPayment(amount);
}
///
/// 获取配置
///
public async Task FetchConfigAsync(string userId)
{
return await Config.Fetch(userId);
}
protected void ShowVerifiedToast() {
Texture avatar = TapSDK.UI.UIManager.TapTapToastIcon;
string str = "您已在 TapTap 实名!";
TapSDK.UI.UIManager.Instance.OpenToast(false, str, 3, icon: avatar);
}
#endregion
}
}