using System;
using System.Collections.Generic;
using System.Threading.Tasks;
///
/// Brisk SDK 的静态总入口。
/// 初始化完成后,开发者可以通过 Brisk.Auth、Brisk.Leaderboard 等模块直接访问能力。
///
public static class Brisk
{
private static BriskContext s_context;
static Brisk()
{
Auth = new BriskAuthModule();
Player = new BriskPlayerModule();
Config = new BriskConfigModule();
Announcements = new BriskAnnouncementsModule();
Leaderboard = new BriskLeaderboardModule();
Archive = new BriskArchiveModule();
Space = new BriskSpaceModule();
}
///
/// SDK 初始化完成后触发。
///
public static event Action OnInitialized;
///
/// 登录成功并保存会话后触发。
///
public static event Action OnLoggedIn;
///
/// 主动登出并清理本地会话后触发。
///
public static event Action OnLoggedOut;
///
/// 发生维护、封禁、强更等严重阻断错误时触发。
///
public static event Action OnBlockingError;
///
/// 登录态失效并清空本地会话时触发。
///
public static event Action OnAuthExpired;
///
/// 认证模块入口。
///
public static BriskAuthModule Auth { get; }
///
/// 玩家模块入口。
///
public static BriskPlayerModule Player { get; }
///
/// 动态配置模块入口。
///
public static BriskConfigModule Config { get; }
///
/// 公告模块入口。
///
public static BriskAnnouncementsModule Announcements { get; }
///
/// 排行榜模块入口。
///
public static BriskLeaderboardModule Leaderboard { get; }
///
/// 云存档模块入口。
///
public static BriskArchiveModule Archive { get; }
///
/// 玩家空间模块入口。
///
public static BriskSpaceModule Space { get; }
///
/// 当前 SDK 是否已完成初始化。
///
public static bool IsInitialized => s_context != null;
///
/// 当前是否存在可用登录态。
///
public static bool IsLoggedIn => s_context != null && s_context.Session.HasAccessToken;
///
/// 当前访问令牌。
///
public static string AccessToken => s_context != null ? s_context.Session.AccessToken : null;
///
/// 当前玩家 ID。
///
public static string PlayerId => s_context != null ? s_context.Session.PlayerId : null;
///
/// 当前登录身份摘要。
///
public static BriskIdentity Identity => s_context != null ? s_context.Session.Identity : null;
///
/// 当前初始化选项。
///
public static BriskOptions Options => s_context != null ? s_context.Options : null;
///
/// 初始化阶段获取到的 bootstrap 结果。
///
public static BriskBootstrapResult Bootstrap => s_context != null ? s_context.Bootstrap : null;
///
/// 初始化 SDK,并执行 bootstrap 与本地会话恢复。
///
/// 初始化选项。
public static async Task InitializeAsync(BriskOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.Validate();
var context = new BriskContext(options);
s_context = context;
try
{
await BootstrapAsync(context);
await RestoreSessionAsync(context);
OnInitialized?.Invoke();
}
catch
{
if (context.Bootstrap == null)
{
s_context = null;
}
throw;
}
}
///
/// 关闭 SDK 并清空当前上下文。
///
public static void Shutdown()
{
s_context = null;
}
///
/// 设置严重错误的展示器。
///
/// 自定义错误展示器;传入 null 时恢复默认展示器。
public static void SetErrorPresenter(IBriskErrorPresenter presenter)
{
GetRequiredContext().ErrorPresenter = presenter ?? BriskDefaultErrorPresenter.Instance;
}
///
/// 设置阻断错误确认后的退出回调。
///
/// 项目方自定义退出逻辑。
public static void SetExitHandler(Action exitHandler)
{
GetRequiredContext().ExitHandler = exitHandler;
}
internal static BriskContext GetRequiredContext()
{
if (s_context == null)
{
throw new BriskNotInitializedException();
}
return s_context;
}
internal static void NotifyLoggedIn()
{
OnLoggedIn?.Invoke();
}
internal static void NotifyLoggedOut()
{
OnLoggedOut?.Invoke();
}
internal static void NotifyBlockingError(BriskBlockingException exception)
{
s_context?.ErrorPresenter?.ShowBlockingError(exception);
OnBlockingError?.Invoke(exception);
}
internal static void NotifyAuthExpired(BriskAuthExpiredException exception)
{
s_context?.ErrorPresenter?.ShowAuthExpired(exception);
OnAuthExpired?.Invoke(exception);
}
private static async Task BootstrapAsync(BriskContext context)
{
var query = new Dictionary
{
{ "game_key", context.Options.GameKey },
{ "client_version", context.Options.ClientVersion },
{ "device_id", context.Options.DeviceId }
};
var bootstrapData = await context.HttpClient.GetDataAsync("/client/bootstrap", query, false);
var bootstrap = BriskModelMapper.ToBootstrapResult(bootstrapData);
context.Bootstrap = bootstrap;
if (bootstrap.MaintenanceMode)
{
var message = string.IsNullOrWhiteSpace(bootstrap.MaintenanceMessage)
? "Server is under maintenance."
: bootstrap.MaintenanceMessage;
var exception = new BriskMaintenanceException(message);
NotifyBlockingError(exception);
throw exception;
}
if (BriskVersionComparer.IsLessThan(context.Options.ClientVersion, bootstrap.MinClientVersion))
{
var exception = new BriskClientUpdateRequiredException("Client version is lower than the minimum supported version.");
NotifyBlockingError(exception);
throw exception;
}
}
private static async Task RestoreSessionAsync(BriskContext context)
{
var storedSession = await context.TokenStore.LoadAsync();
if (storedSession == null || string.IsNullOrWhiteSpace(storedSession.AccessToken))
{
return;
}
context.Session.Update(
storedSession.AccessToken,
storedSession.ExpiresAt,
storedSession.PlayerId,
storedSession.ProjectAccountId,
storedSession.LoginProvider,
storedSession.LoginUserId);
if (!context.Options.ValidateSessionOnInitialize)
{
return;
}
try
{
var meData = await context.HttpClient.GetDataAsync("/player/me", null, true);
var me = BriskModelMapper.ToPlayerMe(meData);
context.Session.Update(
storedSession.AccessToken,
storedSession.ExpiresAt,
me.PlayerId,
me.ProjectAccountId,
me.LoginProvider,
me.LoginUserId);
}
catch (BriskAuthExpiredException exception)
{
context.Session.Clear();
await context.TokenStore.ClearAsync();
NotifyAuthExpired(exception);
}
catch (BriskBlockingException exception)
{
NotifyBlockingError(exception);
throw;
}
}
}