646 lines
21 KiB
C#
646 lines
21 KiB
C#
using asap.core;
|
||
using com.fpnn;
|
||
using com.fpnn.rtm;
|
||
using GameCore;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using UnityEngine;
|
||
using UniRx;
|
||
|
||
namespace game
|
||
{
|
||
public class ChatQuestProcessor : RTMQuestProcessor
|
||
{
|
||
public override void SessionClosed(int ClosedByErrorCode)
|
||
{
|
||
Debug.Log("SessionClosed errorCode = " + ClosedByErrorCode);
|
||
}
|
||
|
||
public override bool ReloginWillStart(int lastErrorCode, int retriedCount)
|
||
{
|
||
Debug.Log("ReloginWillStart lastErrorCode = " + lastErrorCode + ", retriedCount = " + retriedCount);
|
||
return true;
|
||
}
|
||
|
||
public override void Kickout()
|
||
{
|
||
Debug.Log("Kickout");
|
||
}
|
||
|
||
public override void KickoutRoom(long roomId)
|
||
{
|
||
Debug.Log("KickoutRoom roomId = " + roomId);
|
||
}
|
||
}
|
||
|
||
[Serializable]
|
||
public class ChatMessage : IComparable<ChatMessage>
|
||
{
|
||
public ChatMessage(long messageId, long fromUid, string message, long mtime, long cursorId = 0)
|
||
{
|
||
this.messageId = messageId;
|
||
this.fromUid = fromUid;
|
||
this.message = message;
|
||
this.mtime = mtime;
|
||
this.cursorId = cursorId;
|
||
}
|
||
public static ChatMessage ConvertoFromRTMMessage(RTMMessage message)
|
||
{
|
||
ChatMessage chatDemoMessage = new ChatMessage(message.messageId, message.fromUid, message.stringMessage, message.modifiedTime);
|
||
return chatDemoMessage;
|
||
}
|
||
|
||
public static ChatMessage ConvertoFromHistoryMessage(HistoryMessage message)
|
||
{
|
||
ChatMessage chatDemoMessage = new ChatMessage(message.messageId, message.fromUid, message.stringMessage, message.modifiedTime, message.cursorId);
|
||
return chatDemoMessage;
|
||
}
|
||
|
||
public int CompareTo(ChatMessage message)
|
||
{
|
||
if (mtime > message.mtime)
|
||
return 1;
|
||
else if (mtime < message.mtime)
|
||
return -1;
|
||
else
|
||
{
|
||
if (messageId >= message.messageId)
|
||
return 1;
|
||
else
|
||
return -1;
|
||
}
|
||
}
|
||
public long messageId;
|
||
public long fromUid;
|
||
public string message;
|
||
public long mtime;
|
||
public long cursorId;
|
||
}
|
||
|
||
public class ChatMessageCompare : IEqualityComparer<ChatMessage>
|
||
{
|
||
public bool Equals(ChatMessage msg1, ChatMessage msg2)
|
||
{
|
||
if (msg1.mtime == msg2.mtime && msg1.messageId == msg2.messageId)
|
||
{
|
||
if (msg1.cursorId == msg2.cursorId)
|
||
return true;
|
||
else if ((msg1.cursorId == 0 && msg2.cursorId != 0) || (msg1.cursorId != 0 && msg2.cursorId == 0))
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
else
|
||
return false;
|
||
}
|
||
|
||
public int GetHashCode(ChatMessage msg)
|
||
{
|
||
if (msg == null)
|
||
return 0;
|
||
else
|
||
return string.Format("{0}_{1}_{2}", msg.mtime, msg.messageId, msg.message).GetHashCode();
|
||
}
|
||
}
|
||
|
||
[Serializable]
|
||
public class ChatConversation
|
||
{
|
||
//public Int32 unreadCount;
|
||
public Int64 lastMessageTime;
|
||
//public ChatMessage lastMessage;
|
||
|
||
//public void AddMessage(ChatMessage message)
|
||
//{
|
||
// if (lastMessage == null)
|
||
// {
|
||
// lastMessage = message;
|
||
// return;
|
||
// }
|
||
// if (message.mtime > lastMessage.mtime)
|
||
// {
|
||
// lastMessage = message;
|
||
// return;
|
||
// }
|
||
// else if (message.mtime == lastMessage.mtime && lastMessage.messageId > message.messageId)
|
||
// {
|
||
// lastMessage = message;
|
||
// return;
|
||
// }
|
||
//}
|
||
}
|
||
|
||
|
||
public class ChatChatData
|
||
{
|
||
public Int64 lastId;
|
||
public List<ChatMessage> messageList;
|
||
}
|
||
|
||
public class ChatChangeEvent
|
||
{
|
||
public bool nextContent;
|
||
public bool push;
|
||
}
|
||
|
||
public enum ChatType
|
||
{
|
||
Text = 1,//文本消息
|
||
System = 2,//系统内提示
|
||
System2 = 3,//解锁地图
|
||
Help = 4,//请求照片
|
||
Emoji = 5,//发送表情
|
||
HelpEnergy = 6//请求体力帮助
|
||
}
|
||
|
||
public class ChatService : IChatService
|
||
{
|
||
private IUserService userService { get; set; }
|
||
private IConfig config { get; set; }
|
||
private int sendInterval = 2;
|
||
long groupConversationId = 0;
|
||
RTMClient client;
|
||
ChatConversation chatConversation;
|
||
ChatChatData chat;
|
||
|
||
public ChatService(IUserService userService, IConfig config, cfg.Tables tables)
|
||
{
|
||
this.userService = userService;
|
||
this.config = config;
|
||
this.sendInterval = tables.TbGlobalConfig.ClubChatLimitTime;
|
||
ClientEngine.Init();
|
||
RTMControlCenter.Init();
|
||
|
||
}
|
||
|
||
private IDisposable disposable;
|
||
public void WaitingForLogin()
|
||
{
|
||
disposable = RootCtx.OnEvent<EvtAPISvrLoginSuccess>().Subscribe(OnApiSvrLoginSuccess);
|
||
}
|
||
|
||
private async void OnApiSvrLoginSuccess(EvtAPISvrLoginSuccess evt)
|
||
{
|
||
disposable.Dispose();
|
||
int retryCount = 0;
|
||
while(! await LoginRTM())
|
||
{
|
||
retryCount++;
|
||
await Task.Delay(Math.Min(5000 + retryCount * 1000, 10000));
|
||
}
|
||
}
|
||
|
||
private async Task<bool> LoginRTM(int timeout = 5)
|
||
{
|
||
|
||
var userIdLong = userService.InternalId;
|
||
var pid = long.Parse(config.Get(GConstant.K_RTMP_ID, "80000560"));
|
||
var rtmServerEndpoint = config.Get(GConstant.K_RTM_Server_Endpoint, "rtm-nx-front.ilivedata.com:13321");
|
||
var hmacSecret = config.Get(GConstant.K_RTM_Hmac_Secret, "7a1ba6bb85a4473d96fa4bf45b01f1dd");
|
||
ChatQuestProcessor processor = new ChatQuestProcessor();
|
||
InitProcessor(processor);
|
||
client = RTMClient.getInstance(rtmServerEndpoint, pid, userIdLong, processor);
|
||
|
||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||
|
||
string token = GetToken(pid, hmacSecret, userIdLong, out long ts);
|
||
|
||
client.Login((long pid, long uid, bool successful, int errorCode) =>
|
||
{
|
||
if (successful)
|
||
{
|
||
taskCompletionSource.SetResult(true);
|
||
//RTMControlCenter.callbackQueue.PostAction(() =>
|
||
//{
|
||
// GetConversationList();
|
||
//});
|
||
}
|
||
else
|
||
{
|
||
taskCompletionSource.SetResult(false);
|
||
Debug.Log("Login failed, errorCode = " + errorCode);
|
||
#if AGG
|
||
using (var e = GEvent.GameEvent("ilivedata"))
|
||
{
|
||
e.AddContent("connection_failure", errorCode)
|
||
.AddContent("pid", pid)
|
||
.AddContent("uid", uid)
|
||
.AddContent("userIdLong", userIdLong);
|
||
}
|
||
#endif
|
||
}
|
||
}, token, ts, timeout);
|
||
|
||
return await(taskCompletionSource.Task);
|
||
}
|
||
|
||
string GetToken(long pid, string hmacSecret, long uid, out long ts)
|
||
{
|
||
ts = ClientEngine.GetCurrentSeconds();
|
||
string text = pid.ToString() + ":" + uid.ToString() + ":" + ts.ToString();
|
||
|
||
using (var hmacsha256 = new HMACSHA256(Convert.FromBase64String(hmacSecret)))
|
||
{
|
||
var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(text));
|
||
return Convert.ToBase64String(hash);
|
||
}
|
||
}
|
||
|
||
public async Task<HashSet<long>> GetOnlineUsers(List<long> playerIDs)
|
||
{
|
||
HashSet<long> longs = new HashSet<long>();
|
||
|
||
if(client?.Status != RTMClient.ClientStatus.Connected)
|
||
return longs;
|
||
|
||
var taskCompletionSource = new TaskCompletionSource<HashSet<long>>();
|
||
longs = new HashSet<long>(playerIDs);
|
||
client.GetOnlineUsers((HashSet<long> uids, int errorCode) =>
|
||
{
|
||
if (errorCode == 0)
|
||
{
|
||
taskCompletionSource.SetResult(uids);
|
||
}
|
||
else
|
||
{
|
||
taskCompletionSource.SetResult(null);
|
||
}
|
||
}, longs);
|
||
return await taskCompletionSource.Task;
|
||
}
|
||
|
||
public void GetConversationList(long groupConversationId)
|
||
{
|
||
this.groupConversationId = groupConversationId;
|
||
|
||
if(client?.Status != RTMClient.ClientStatus.Connected)
|
||
return;
|
||
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
GetConversationList();
|
||
});
|
||
}
|
||
|
||
void InitProcessor(ChatQuestProcessor processor)
|
||
{
|
||
processor.PushGroupChatCallback = OnPushGroupChat;
|
||
processor.PushGroupMessageCallback = OnPushGroupMessage;
|
||
//processor.PushMessageCallback = OnPushGroupMessage;
|
||
//processor.PushChatCallback = OnPushGroupChat;
|
||
processor.ReloginCompletedCallback = OnRelogin;
|
||
}
|
||
|
||
void OnPushGroupChat(RTMMessage message)
|
||
{
|
||
if (message.toId == groupConversationId)
|
||
{
|
||
AddMessage(groupConversationId, true);
|
||
}
|
||
//else if (message.toId == userIdLong)
|
||
//{
|
||
// //个人聊天列表
|
||
|
||
//}
|
||
}
|
||
|
||
void OnPushGroupMessage(RTMMessage message)
|
||
{
|
||
if (message.toId == groupConversationId)
|
||
{
|
||
//主界面推送消息
|
||
|
||
}
|
||
//else if (message.toId == userIdLong)
|
||
//{
|
||
// //个人聊天列表
|
||
|
||
//}
|
||
}
|
||
|
||
void OnRelogin(bool successful, bool retryAgain, int errorCode, int retriedCount)
|
||
{
|
||
//Debug.Log("OnRelogin successful = " + successful + " retryAgain = " + retryAgain + ", errorCode = " + errorCode + ", retriedCount = " + retriedCount);
|
||
if (successful && chatConversation != null)
|
||
{
|
||
client?.GetGroupUnreadConversationList((List<Conversation> groupConversationList, int errorCode) =>
|
||
{
|
||
if (errorCode == 0)
|
||
{
|
||
InitConversationList(groupConversationList);
|
||
}
|
||
}, startTime: chatConversation.lastMessageTime);
|
||
}
|
||
}
|
||
|
||
void GetConversationList()
|
||
{
|
||
long uid = client.Uid;
|
||
client?.GetGroupConversationList((List<Conversation> groupConversationList, int errorCode) =>
|
||
{
|
||
if (errorCode == 0)
|
||
{
|
||
InitConversationList(groupConversationList);
|
||
}
|
||
});
|
||
}
|
||
|
||
void InitConversationList(List<Conversation> list)
|
||
{
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
foreach (Conversation conversation in list)
|
||
{
|
||
if (conversation.id == groupConversationId)
|
||
{
|
||
if (chatConversation == null)
|
||
{
|
||
chatConversation = new ChatConversation();
|
||
}
|
||
//chatConversation.unreadCount += conversation.unreadCount;
|
||
//if (conversation.lastMessage != null && conversation.lastMessage.messageId != 0)
|
||
// chatConversation.AddMessage(ChatMessage.ConvertoFromHistoryMessage(conversation.lastMessage));
|
||
UpdateConversationList(false);
|
||
return;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
void UpdateConversationList(bool push)
|
||
{
|
||
if (chatConversation == null)
|
||
return;
|
||
//client?.GetGroupMessage((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||
//{
|
||
// if (errorCode == 0)
|
||
// {
|
||
// InitChat(lastCursorId, messages);
|
||
// }
|
||
//}, groupConversationId, true, 10);
|
||
//两个接口一样 GetGroupMessage多一个指定类型
|
||
client?.GetGroupChat((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||
{
|
||
if (errorCode == 0)
|
||
{
|
||
InitChat(lastCursorId, messages, push, false);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("GetGroupChat errorCode = " + errorCode);
|
||
}
|
||
}, groupConversationId, true, 10);
|
||
}
|
||
|
||
void InitChat(long lastId, List<HistoryMessage> messages, bool push, bool nextContent)
|
||
{
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
if (chat == null)
|
||
{
|
||
chat = new ChatChatData();
|
||
chat.messageList = new List<ChatMessage>();
|
||
}
|
||
if (messages != null)
|
||
{
|
||
if ((chat.lastId == 0 || lastId < chat.lastId) && lastId != 0)
|
||
chat.lastId = lastId;
|
||
|
||
foreach (HistoryMessage message in messages)
|
||
{
|
||
chat.messageList.Add(ChatMessage.ConvertoFromHistoryMessage(message));
|
||
}
|
||
chat.messageList = chat.messageList.Distinct(new ChatMessageCompare()).ToList();
|
||
chat.messageList.Sort();
|
||
GContext.Publish(new ChatChangeEvent() { nextContent = nextContent, push = push });
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
async void AddMessage(long conversationId, bool push)
|
||
{
|
||
await Task.Delay(100);//服务器聊天记录存储延时
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
if (conversationId == groupConversationId)
|
||
{
|
||
if (chatConversation == null)
|
||
{
|
||
chatConversation = new ChatConversation();
|
||
//chatConversation.unreadCount = 1;
|
||
//chatConversation.lastMessage = message;
|
||
}
|
||
//else
|
||
//{
|
||
// chatConversation.AddMessage(message);
|
||
//}
|
||
UpdateConversationList(push);
|
||
//if (chat == null)
|
||
// return;
|
||
//chat.messageList.Add(message);
|
||
//chat.messageList = chat.messageList.Distinct(new ChatMessageCompare()).ToList();
|
||
//chat.messageList.Sort();
|
||
//GContext.Publish(new ChatChangeEvent());
|
||
}
|
||
});
|
||
}
|
||
|
||
async Task<long> CanSend(string message)
|
||
{
|
||
if (groupConversationId == 0)
|
||
return 0;
|
||
var taskCompletionSource = new TaskCompletionSource<long>();
|
||
message = string.Format("{0}#{1}", userService.UserId, message);
|
||
client?.SendGroupChat((long messageId, long mtime, int errorCode) =>
|
||
{
|
||
if (errorCode != 0)
|
||
{
|
||
taskCompletionSource.SetResult(0);
|
||
Debug.Log("SendGroupChat errorCode = " + errorCode);
|
||
}
|
||
else
|
||
{
|
||
taskCompletionSource.SetResult(messageId);
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
AddMessage(groupConversationId, false);
|
||
chatConversation.lastMessageTime = mtime;
|
||
});
|
||
}
|
||
}, groupConversationId, message);
|
||
long messageId = await taskCompletionSource.Task;
|
||
return messageId;
|
||
}
|
||
|
||
async Task<long> Send(string message)
|
||
{
|
||
if (groupConversationId == 0)
|
||
return 0;
|
||
|
||
if (!CanSend())
|
||
{
|
||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_42"));
|
||
return 0;
|
||
}
|
||
|
||
var taskCompletionSource = new TaskCompletionSource<long>();
|
||
message = string.Format("{0}#{1}", userService.UserId, message);
|
||
client?.SendGroupChat((long messageId, long mtime, int errorCode) =>
|
||
{
|
||
if (errorCode != 0)
|
||
{
|
||
taskCompletionSource.SetResult(0);
|
||
Debug.Log("SendGroupChat errorCode = " + errorCode);
|
||
}
|
||
else
|
||
{
|
||
taskCompletionSource.SetResult(messageId);
|
||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||
{
|
||
AddMessage(groupConversationId, false);
|
||
chatConversation.lastMessageTime = mtime;
|
||
});
|
||
}
|
||
}, groupConversationId, message);
|
||
long messageId = await taskCompletionSource.Task;
|
||
return messageId;
|
||
}
|
||
|
||
Task sendTask = null;
|
||
private bool CanSend()
|
||
{
|
||
if(sendTask == null || sendTask.IsCompleted)
|
||
{
|
||
sendTask = Task.Delay(TimeSpan.FromSeconds(sendInterval));
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
public void NextPage()
|
||
{
|
||
if (groupConversationId == 0)
|
||
return;
|
||
if (chat == null)
|
||
return;
|
||
if (chat.messageList.Count >= GContext.container.Resolve<cfg.Tables>().TbGlobalConfig.ClubChatMaxCount)
|
||
{
|
||
return;
|
||
}
|
||
client?.GetGroupChat((int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode) =>
|
||
{
|
||
if (errorCode == 0)
|
||
{
|
||
InitChat(lastCursorId, messages, false, true);
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("GetGroupChat errorCode = " + errorCode);
|
||
}
|
||
}, groupConversationId, true, 10, lastId: chat.lastId);
|
||
}
|
||
|
||
public void OnQuit()
|
||
{
|
||
chat = null;
|
||
chatConversation = null;
|
||
groupConversationId = 0;
|
||
}
|
||
|
||
public void InitChatData()
|
||
{
|
||
chat = null;
|
||
}
|
||
|
||
public ChatChatData GetGroupChat()
|
||
{
|
||
return chat;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解析消息类型
|
||
/// </summary>
|
||
/// <param name="chat"></param>
|
||
/// <returns>1.文本消息 2.系统消息(没有点赞)3.系统消息 4.求助帖 5.图片</returns>
|
||
public string[] ParseChat(string chat)
|
||
{
|
||
return chat.Split('#');
|
||
}
|
||
|
||
public async Task<long> SendHelpEnergyMessage(int itemId)
|
||
{
|
||
string chat = $"{(int)ChatType.HelpEnergy}#{itemId}";
|
||
return await CanSend(chat);
|
||
}
|
||
|
||
public void SendEmoji(string chat)
|
||
{
|
||
chat = $"{(int)ChatType.Emoji}#{chat}";
|
||
_ = Send(chat);
|
||
}
|
||
|
||
public async Task<long> SendGetPhotoMessage(string chat)
|
||
{
|
||
chat = $"{(int)ChatType.Help}#{chat}";
|
||
return await CanSend(chat);
|
||
}
|
||
|
||
//谁干了什么
|
||
public void SendSystemMessage2(string chat)
|
||
{
|
||
chat = $"{(int)ChatType.System2}#{chat}";
|
||
_ = CanSend(chat);
|
||
}
|
||
|
||
//俱乐部系统提示
|
||
public void SendSystemMessage(string chat)
|
||
{
|
||
chat = $"{(int)ChatType.System}#{chat}";
|
||
_ = CanSend(chat);
|
||
}
|
||
|
||
public async void SendTxTMessage(string chat)
|
||
{
|
||
//审核
|
||
bool value = await TextAudit(chat);
|
||
if (value)
|
||
{
|
||
chat = $"{(int)ChatType.Text}#{chat}";
|
||
_ = Send(chat);
|
||
}
|
||
else
|
||
{
|
||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_33"));
|
||
}
|
||
}
|
||
|
||
public async Task<bool> TextAudit(string text)
|
||
{
|
||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||
client.TextCheck((TextCheckResult result, int errorCode) =>
|
||
{
|
||
if (errorCode != com.fpnn.ErrorCode.FPNN_EC_OK)
|
||
{
|
||
taskCompletionSource.SetResult(true);
|
||
}
|
||
else
|
||
{
|
||
//Debug.Log(" -- result " + result.result);
|
||
|
||
//if (result.tags != null)
|
||
// Debug.Log(" -- tags.Count " + result.tags.Count);
|
||
//if (result.wlist != null)
|
||
// Debug.Log(" -- wlist.Count " + result.wlist.Count);
|
||
taskCompletionSource.SetResult(result.result == 0);
|
||
}
|
||
}, text);
|
||
return await taskCompletionSource.Task;
|
||
}
|
||
}
|
||
}
|