Files
back_cantanBuilding/Assets/Scripts/Services/RTService.cs
2026-05-26 16:15:54 +08:00

249 lines
7.1 KiB
C#

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<T>(Action<T> handler);
public Task<string> Publish(string methodName, string arg1);
public Task<string> 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<Type> _bindedEvent;
private IEventAggregator _eventAgg;
private string _url;
private Dictionary<string, Action<string>> _cachedEvents;
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>();
}
public void WaitForAPISvrLogin()
{
GContext.OnEvent<game.EvtAPISvrLoginSuccess>().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<string,string, string>("ForceQuit", ForceQuit);
if (_bindedEvent != null)
{
_bindedEvent.Clear();
}
else
{
_bindedEvent = new HashSet<Type>();
}
}
private Task OnHubConnected(string connectionId)
{
if(_cachedEvents.Count > 0)
{
foreach(var kv in _cachedEvents)
{
_hubConnection.On<string>(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<T>(Action<T> handler)
{
var methodName = typeof(T).Name;
if(!_bindedEvent.Contains(typeof(T)))
{
_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);
};
}
}
return _eventAgg.GetEvent<T>().Subscribe(handler);
}
public async Task<string> Publish(string methodName, string arg1)
{
try
{
return await _hubConnection.InvokeAsync<string>(methodName, arg1);
}
catch(Exception e)
{
Debug.LogException(e);
return null;
}
}
public async Task<string> Publish(string methodName, string arg1, string arg2)
{
try
{
return await _hubConnection.InvokeAsync<string>(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<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);
}
private async void Restart()
{
await LoadingScreen.Show();
await GContext.container.Resolve<IStageService>().SwitchStageAsync("QuitStage");
}
public async void Test()
{
Debug.Log("[RTService] Test invoking");
var returnValue = await _hubConnection.InvokeAsync<string>("Test","arg1", "arg2");
Debug.Log($"[RTService] Test invoked Value {returnValue}");
}
}