using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using System.Net; using asap.core; using Microsoft.AspNetCore.SignalR.Client; using Newtonsoft.Json; using UniRx; using GameCore; using game; public interface IRTService { public void WaitForAPISvrLogin(); public Task Connect(); public Task Disconnect(); public bool IsConnected { get; } public IDisposable OnEvent(Action handler); public Task Publish(string methodName, string arg1); public Task Publish(string methodName, string arg1, string arg2); //public void Reset(); public void Release(); } public class SignalRService : IRTService { private HubConnection _hubConnection; private ICustomServerMgr _serverMgr; private HashSet _bindedEvent; private IEventAggregator _eventAgg; private string _url; private Dictionary> _cachedEvents; public SignalRService(ICustomServerMgr serverMgr, IConfig config) { this._serverMgr = serverMgr; var baseUrl = config.Get(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>(); _bindedEvent = new HashSet(); } public void WaitForAPISvrLogin() { GContext.OnEvent().Subscribe(OnApiSvrLoginSuccess); } private async void OnApiSvrLoginSuccess(EvtAPISvrLoginSuccess evt) { try{ Reset(); await Connect(); } catch (Exception ex) { Debug.LogException(ex); } } public void Release() { 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; } } private void Reset() { 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("ForceQuit", ForceQuit); if (_bindedEvent != null) { _bindedEvent.Clear(); } else { _bindedEvent = new HashSet(); } } private Task OnHubConnected(string connectionId) { if(_cachedEvents.Count > 0) { foreach(var kv in _cachedEvents) { _hubConnection.On(kv.Key, kv.Value); } _cachedEvents.Clear(); } _hubConnection.Reconnected -= OnHubConnected; return Task.CompletedTask; } public bool IsConnected => _hubConnection != null && _hubConnection.State == HubConnectionState.Connected; public async Task Connect() { if(_hubConnection == null) { Debug.LogWarning("[RTService] hubConnection is null"); return; } //UnityEngine.Assertions.Assert.IsNotNull(_hubConnection, "[RTService] hubConnection is null"); if (_hubConnection.State == HubConnectionState.Disconnected) { await _hubConnection.StartAsync(); Debug.Log($"[RTService] Connected to SignalR server {_hubConnection.State == HubConnectionState.Connected}"); } } 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}"); } } public IDisposable OnEvent(Action handler) { var methodName = typeof(T).Name; if(!_bindedEvent.Contains(typeof(T))) { _bindedEvent.Add(typeof(T)); if(IsConnected) { _hubConnection.On(methodName, data => { var result =JsonConvert.DeserializeObject(data); _eventAgg.Publish(result); }); } else { _cachedEvents[methodName] = data => { var result =JsonConvert.DeserializeObject(data); _eventAgg.Publish(result); }; } } return _eventAgg.GetEvent().Subscribe(handler); } public async Task Publish(string methodName, string arg1) { try { return await _hubConnection.InvokeAsync(methodName, arg1); } catch(Exception e) { Debug.LogException(e); return null; } } public async Task Publish(string methodName, string arg1, string arg2) { try { return await _hubConnection.InvokeAsync(methodName, arg1, arg2); } catch(Exception e) { Debug.LogException(e); return null; } } private async void ForceQuit(string titleKey, string infoKey, string btnKey) { await Awaiters.NextFrame; GameObject go = await UIManager.Instance.ShowUI(UITypes.NoticeConfirmPopupPanel); var noticeConfirmPopupPanel = go.GetComponent(); 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); } private async void Restart() { await LoadingScreen.Show(); await GContext.container.Resolve().SwitchStageAsync("QuitStage"); } public async void Test() { Debug.Log("[RTService] Test invoking"); var returnValue = await _hubConnection.InvokeAsync("Test","arg1", "arg2"); Debug.Log($"[RTService] Test invoked Value {returnValue}"); } }