feat(upserver): 接入认证与KV存档并完成限定钓鱼闭环
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using System.Net;
|
||||
using asap.core;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Newtonsoft.Json;
|
||||
using UniRx;
|
||||
@@ -22,184 +23,159 @@ public interface IRTService
|
||||
public Task<string> Publish(string methodName, string arg1, string arg2);
|
||||
//public void Reset();
|
||||
public void Release();
|
||||
public Task ReleaseAsync();
|
||||
}
|
||||
|
||||
public class SignalRService : IRTService
|
||||
{
|
||||
private HubConnection _hubConnection;
|
||||
private ICustomServerMgr _serverMgr;
|
||||
private HashSet<Type> _bindedEvent;
|
||||
private IEventAggregator _eventAgg;
|
||||
private string _url;
|
||||
private Dictionary<string, Action<string>> _cachedEvents;
|
||||
private readonly ICustomServerMgr _serverMgr;
|
||||
private readonly IEventAggregator _eventAgg = new EventAggregator();
|
||||
private readonly string _url;
|
||||
private readonly Dictionary<string, Action<string>> handlers = new Dictionary<string, Action<string>>();
|
||||
private readonly System.Threading.SemaphoreSlim lifecycle = new System.Threading.SemaphoreSlim(1, 1);
|
||||
private IDisposable loginSubscription;
|
||||
private bool released;
|
||||
private int connectionVersion;
|
||||
private System.Threading.CancellationTokenSource connecting;
|
||||
|
||||
public SignalRService(ICustomServerMgr serverMgr, IConfig config)
|
||||
{
|
||||
this._serverMgr = serverMgr;
|
||||
var baseUrl = config.Get<string>(GConstant.K_Event_API_URL, string.Empty);
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Assertions.Assert.IsTrue(!string.IsNullOrEmpty(baseUrl));
|
||||
#endif
|
||||
_url = baseUrl + "gamehub";
|
||||
_eventAgg = new EventAggregator();
|
||||
_cachedEvents = new Dictionary<string, Action<string>>();
|
||||
_bindedEvent = new HashSet<Type>();
|
||||
_serverMgr = serverMgr;
|
||||
_url = new Uri(serverMgr.ApiBaseUri, "gamehub").AbsoluteUri;
|
||||
_serverMgr.SessionChanged += OnSessionChanged;
|
||||
}
|
||||
|
||||
public void WaitForAPISvrLogin()
|
||||
{
|
||||
GContext.OnEvent<game.EvtAPISvrLoginSuccess>().Subscribe(OnApiSvrLoginSuccess);
|
||||
if (released || loginSubscription != null) return;
|
||||
loginSubscription = GContext.OnEvent<EvtAPISvrLoginSuccess>().Subscribe(OnApiSvrLoginSuccess);
|
||||
}
|
||||
|
||||
private async void OnApiSvrLoginSuccess(EvtAPISvrLoginSuccess evt)
|
||||
{
|
||||
try{
|
||||
Reset();
|
||||
await Connect();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
try { await Connect(); }
|
||||
catch (Exception ex) { Debug.LogException(ex); }
|
||||
}
|
||||
|
||||
public void Release()
|
||||
private async void OnSessionChanged()
|
||||
{
|
||||
if (_hubConnection != null)
|
||||
{
|
||||
_hubConnection.StopAsync();
|
||||
_hubConnection.DisposeAsync();
|
||||
_hubConnection = null;
|
||||
}
|
||||
|
||||
if (_bindedEvent != null)
|
||||
{
|
||||
_bindedEvent.Clear();
|
||||
_bindedEvent = null;
|
||||
}
|
||||
|
||||
if (_eventAgg != null)
|
||||
{
|
||||
_eventAgg = null;
|
||||
}
|
||||
|
||||
if(_cachedEvents != null)
|
||||
{
|
||||
_cachedEvents.Clear();
|
||||
_cachedEvents = null;
|
||||
}
|
||||
connectionVersion++;
|
||||
connecting?.Cancel();
|
||||
try { await Disconnect(); }
|
||||
catch (Exception ex) { Debug.LogException(ex); }
|
||||
}
|
||||
|
||||
|
||||
private void Reset()
|
||||
private async Task CloseConnection()
|
||||
{
|
||||
if (_hubConnection != null)
|
||||
{
|
||||
_hubConnection.StopAsync();
|
||||
_hubConnection.DisposeAsync();
|
||||
_hubConnection = null;
|
||||
}
|
||||
|
||||
var cookie = _serverMgr.Cookie;
|
||||
_hubConnection = new HubConnectionBuilder()
|
||||
.WithUrl(_url, option => option.Cookies = cookie)
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
|
||||
_hubConnection.Reconnected += OnHubConnected;
|
||||
|
||||
_hubConnection.On<string,string, string>("ForceQuit", ForceQuit);
|
||||
|
||||
if (_bindedEvent != null)
|
||||
{
|
||||
_bindedEvent.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_bindedEvent = new HashSet<Type>();
|
||||
}
|
||||
var previous = _hubConnection;
|
||||
_hubConnection = null;
|
||||
if (previous == null) return;
|
||||
try { await previous.StopAsync(); }
|
||||
finally { await previous.DisposeAsync(); }
|
||||
}
|
||||
|
||||
private Task OnHubConnected(string connectionId)
|
||||
public async void Release()
|
||||
{
|
||||
if(_cachedEvents.Count > 0)
|
||||
{
|
||||
foreach(var kv in _cachedEvents)
|
||||
{
|
||||
_hubConnection.On<string>(kv.Key, kv.Value);
|
||||
}
|
||||
_cachedEvents.Clear();
|
||||
}
|
||||
_hubConnection.Reconnected -= OnHubConnected;
|
||||
return Task.CompletedTask;
|
||||
try { await ReleaseAsync(); }
|
||||
catch (Exception ex) { Debug.LogException(ex); }
|
||||
}
|
||||
|
||||
public bool IsConnected => _hubConnection != null && _hubConnection.State == HubConnectionState.Connected;
|
||||
public async Task ReleaseAsync()
|
||||
{
|
||||
released = true;
|
||||
connectionVersion++;
|
||||
connecting?.Cancel();
|
||||
loginSubscription?.Dispose();
|
||||
loginSubscription = null;
|
||||
_serverMgr.SessionChanged -= OnSessionChanged;
|
||||
await lifecycle.WaitAsync();
|
||||
try { await CloseConnection(); handlers.Clear(); }
|
||||
finally { lifecycle.Release(); }
|
||||
}
|
||||
|
||||
private bool IsCurrent(HubConnection hub, int version, int session) =>
|
||||
!released && version == connectionVersion && session == _serverMgr.SessionVersion && ReferenceEquals(hub, _hubConnection);
|
||||
|
||||
public bool IsConnected => !released && _hubConnection != null && _hubConnection.State == HubConnectionState.Connected;
|
||||
|
||||
public async Task Connect()
|
||||
{
|
||||
if(_hubConnection == null)
|
||||
var session = _serverMgr.SessionVersion;
|
||||
var version = connectionVersion;
|
||||
var cookies = _serverMgr.Cookie;
|
||||
await lifecycle.WaitAsync();
|
||||
try
|
||||
{
|
||||
Debug.LogWarning("[RTService] hubConnection is null");
|
||||
return;
|
||||
if (released || version != connectionVersion || session != _serverMgr.SessionVersion) return;
|
||||
if (_hubConnection != null && _hubConnection.State != HubConnectionState.Disconnected) return;
|
||||
await CloseConnection();
|
||||
if (released || version != connectionVersion || session != _serverMgr.SessionVersion) return;
|
||||
var hub = new HubConnectionBuilder()
|
||||
.WithUrl(_url, option =>
|
||||
{
|
||||
option.Cookies = cookies;
|
||||
option.SkipNegotiation = true;
|
||||
option.Transports = HttpTransportType.WebSockets;
|
||||
})
|
||||
.WithAutomaticReconnect()
|
||||
.Build();
|
||||
_hubConnection = hub;
|
||||
hub.On<string, string, string>("ForceQuit", (title, info, button) =>
|
||||
{
|
||||
if (IsCurrent(hub, version, session)) ForceQuit(title, info, button, version, session);
|
||||
});
|
||||
foreach (var handler in handlers)
|
||||
Bind(hub, version, session, handler.Key, handler.Value);
|
||||
connecting?.Dispose();
|
||||
connecting = new System.Threading.CancellationTokenSource();
|
||||
try { await hub.StartAsync(connecting.Token); }
|
||||
catch { await CloseConnection(); throw; }
|
||||
if (!IsCurrent(hub, version, session)) { await CloseConnection(); return; }
|
||||
Debug.Log("[RTService] Connected to SignalR server True");
|
||||
}
|
||||
finally { lifecycle.Release(); }
|
||||
}
|
||||
|
||||
//UnityEngine.Assertions.Assert.IsNotNull(_hubConnection, "[RTService] hubConnection is null");
|
||||
if (_hubConnection.State == HubConnectionState.Disconnected)
|
||||
private void Bind(HubConnection hub, int version, int session, string name, Action<string> handler)
|
||||
{
|
||||
hub.On<string>(name, data =>
|
||||
{
|
||||
await _hubConnection.StartAsync();
|
||||
Debug.Log($"[RTService] Connected to SignalR server {_hubConnection.State == HubConnectionState.Connected}");
|
||||
}
|
||||
if (IsCurrent(hub, version, session)) handler(data);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task Disconnect()
|
||||
{
|
||||
if(_hubConnection == null)
|
||||
{
|
||||
Debug.LogWarning("[RTService] hubConnection is null");
|
||||
return;
|
||||
}
|
||||
|
||||
//UnityEngine.Assertions.Assert.IsNotNull(_hubConnection, "[RTService] hubConnection is null");
|
||||
if (_hubConnection.State == HubConnectionState.Connected)
|
||||
{
|
||||
await _hubConnection.StopAsync();
|
||||
Debug.Log($"[RTService] Disconnected to SignalR server {_hubConnection.State == HubConnectionState.Disconnected}");
|
||||
}
|
||||
await lifecycle.WaitAsync();
|
||||
try { await CloseConnection(); }
|
||||
finally { lifecycle.Release(); }
|
||||
}
|
||||
|
||||
public IDisposable OnEvent<T>(Action<T> handler)
|
||||
{
|
||||
var methodName = typeof(T).Name;
|
||||
|
||||
if(!_bindedEvent.Contains(typeof(T)))
|
||||
if (released) throw new ObjectDisposedException(nameof(SignalRService));
|
||||
var name = typeof(T).Name;
|
||||
if (!handlers.ContainsKey(name))
|
||||
{
|
||||
_bindedEvent.Add(typeof(T));
|
||||
if(IsConnected)
|
||||
{
|
||||
_hubConnection.On<string>(methodName, data => {
|
||||
var result =JsonConvert.DeserializeObject<T>(data);
|
||||
_eventAgg.Publish(result);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedEvents[methodName] = data => {
|
||||
|
||||
var result =JsonConvert.DeserializeObject<T>(data);
|
||||
_eventAgg.Publish(result);
|
||||
};
|
||||
}
|
||||
Action<string> dispatch = data => _eventAgg.Publish(JsonConvert.DeserializeObject<T>(data));
|
||||
handlers.Add(name, dispatch);
|
||||
if (_hubConnection != null)
|
||||
Bind(_hubConnection, connectionVersion, _serverMgr.SessionVersion, name, dispatch);
|
||||
}
|
||||
|
||||
return _eventAgg.GetEvent<T>().Subscribe(handler);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> Publish(string methodName, string arg1)
|
||||
{
|
||||
var hub = _hubConnection;
|
||||
var version = connectionVersion;
|
||||
var session = _serverMgr.SessionVersion;
|
||||
if (hub == null || !IsCurrent(hub, version, session)) return null;
|
||||
try
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<string>(methodName, arg1);
|
||||
var result = await hub.InvokeAsync<string>(methodName, arg1);
|
||||
return IsCurrent(hub, version, session) ? result : null;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -210,9 +186,14 @@ public class SignalRService : IRTService
|
||||
|
||||
public async Task<string> Publish(string methodName, string arg1, string arg2)
|
||||
{
|
||||
var hub = _hubConnection;
|
||||
var version = connectionVersion;
|
||||
var session = _serverMgr.SessionVersion;
|
||||
if (hub == null || !IsCurrent(hub, version, session)) return null;
|
||||
try
|
||||
{
|
||||
return await _hubConnection.InvokeAsync<string>(methodName, arg1, arg2);
|
||||
var result = await hub.InvokeAsync<string>(methodName, arg1, arg2);
|
||||
return IsCurrent(hub, version, session) ? result : null;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -221,15 +202,17 @@ public class SignalRService : IRTService
|
||||
}
|
||||
}
|
||||
|
||||
private async void ForceQuit(string titleKey, string infoKey, string btnKey)
|
||||
private async void ForceQuit(string titleKey, string infoKey, string btnKey, int version, int session)
|
||||
{
|
||||
await Awaiters.NextFrame;
|
||||
if (released || version != connectionVersion || session != _serverMgr.SessionVersion) return;
|
||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.NoticeConfirmPopupPanel);
|
||||
if (released || version != connectionVersion || session != _serverMgr.SessionVersion) return;
|
||||
var noticeConfirmPopupPanel = go.GetComponent<NoticeConfirmPopupPanel>();
|
||||
string title = LocalizationMgr.GetText(titleKey ?? "UI_NoticePopupPanel_3");
|
||||
string info = LocalizationMgr.GetText(infoKey ?? "UI_NoticePopupPanel_4");
|
||||
string label = LocalizationMgr.GetText(btnKey ?? "UI_COMMON_confirm");
|
||||
noticeConfirmPopupPanel.Init(1, title, info, onClickLeft: Restart, onClose: Restart, btn_left_text: label);
|
||||
noticeConfirmPopupPanel.Init(1, title, info, onClickLeft: () => { if (!released && version == connectionVersion && session == _serverMgr.SessionVersion) Restart(); }, onClose: () => { if (!released && version == connectionVersion && session == _serverMgr.SessionVersion) Restart(); }, btn_left_text: label);
|
||||
}
|
||||
|
||||
private async void Restart()
|
||||
|
||||
Reference in New Issue
Block a user