备份CatanBuilding瘦身独立工程
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
internal class DuplicatedMessageFilter
|
||||
{
|
||||
private enum MessageCategories
|
||||
{
|
||||
P2PMessageType,
|
||||
GroupMessageType,
|
||||
RoomMessageType,
|
||||
BroadcastMessageType,
|
||||
}
|
||||
|
||||
private struct MessageIdUnit
|
||||
{
|
||||
public MessageCategories messageType;
|
||||
public long bizId;
|
||||
public long uid;
|
||||
public long mid;
|
||||
}
|
||||
|
||||
private const int expireSeconds = 20 * 60;
|
||||
private Dictionary<MessageIdUnit, long> midCache;
|
||||
private object interLocker;
|
||||
|
||||
public DuplicatedMessageFilter()
|
||||
{
|
||||
midCache = new Dictionary<MessageIdUnit, long>();
|
||||
interLocker = new object();
|
||||
}
|
||||
|
||||
public bool CheckP2PMessage(long uid, long mid, long to)
|
||||
{
|
||||
MessageIdUnit unit;
|
||||
unit.messageType = MessageCategories.P2PMessageType;
|
||||
unit.bizId = to;
|
||||
unit.uid = uid;
|
||||
unit.mid = mid;
|
||||
|
||||
return CheckMessageIdUnit(unit);
|
||||
}
|
||||
|
||||
public bool CheckGroupMessage(long groupId, long uid, long mid)
|
||||
{
|
||||
MessageIdUnit unit;
|
||||
unit.messageType = MessageCategories.GroupMessageType;
|
||||
unit.bizId = groupId;
|
||||
unit.uid = uid;
|
||||
unit.mid = mid;
|
||||
|
||||
return CheckMessageIdUnit(unit);
|
||||
}
|
||||
|
||||
public bool CheckRoomMessage(long roomId, long uid, long mid)
|
||||
{
|
||||
MessageIdUnit unit;
|
||||
unit.messageType = MessageCategories.RoomMessageType;
|
||||
unit.bizId = roomId;
|
||||
unit.uid = uid;
|
||||
unit.mid = mid;
|
||||
|
||||
return CheckMessageIdUnit(unit);
|
||||
}
|
||||
|
||||
public bool CheckBroadcastMessage(long uid, long mid)
|
||||
{
|
||||
MessageIdUnit unit;
|
||||
unit.messageType = MessageCategories.BroadcastMessageType;
|
||||
unit.bizId = 0;
|
||||
unit.uid = uid;
|
||||
unit.mid = mid;
|
||||
|
||||
return CheckMessageIdUnit(unit);
|
||||
}
|
||||
|
||||
private bool CheckMessageIdUnit(MessageIdUnit unit)
|
||||
{
|
||||
long now = ClientEngine.GetCurrentSeconds();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (midCache.ContainsKey(unit))
|
||||
{
|
||||
midCache[unit] = now;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
midCache.Add(unit, now);
|
||||
ClearExpired(now);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearExpired(long now)
|
||||
{
|
||||
now -= expireSeconds;
|
||||
List<MessageIdUnit> expired = new List<MessageIdUnit>();
|
||||
|
||||
foreach (KeyValuePair<MessageIdUnit, long> kvp in midCache)
|
||||
{
|
||||
if (kvp.Value <= now)
|
||||
expired.Add(kvp.Key);
|
||||
}
|
||||
|
||||
foreach (MessageIdUnit unit in expired)
|
||||
midCache.Remove(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d587adca036a740d1a115f4e4f01f2f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public static class ErrorCode
|
||||
{
|
||||
public const int RTM_EC_INVALID_PID_OR_UID = 200001;
|
||||
public const int RTM_EC_INVALID_PID_OR_SIGN = 200002;
|
||||
public const int RTM_EC_INVALID_FILE_OR_SIGN_OR_TOKEN = 200003;
|
||||
public const int RTM_EC_ATTRS_WITHOUT_SIGN_OR_EXT = 200004;
|
||||
public const int RTM_EC_INVALID_MTYPE = 200005;
|
||||
public const int RTM_EC_SAME_SIGN = 200006;
|
||||
public const int RTM_EC_INVALID_FILE_MTYPE = 200007;
|
||||
public const int RTM_EC_INVALID_SERFVER_TIME = 200008;
|
||||
|
||||
public const int RTM_EC_FREQUENCY_LIMITED = 200010;
|
||||
public const int RTM_EC_REFRESH_SCREEN_LIMITED = 200011;
|
||||
public const int RTM_EC_KICKOUT_SELF = 200012;
|
||||
|
||||
public const int RTM_EC_FORBIDDEN_METHOD = 200020;
|
||||
public const int RTM_EC_PERMISSION_DENIED = 200021;
|
||||
public const int RTM_EC_UNAUTHORIZED = 200022;
|
||||
public const int RTM_EC_DUPLCATED_AUTH = 200023;
|
||||
public const int RTM_EC_AUTH_DENIED = 200024;
|
||||
public const int RTM_EC_ADMIN_LOGIN = 200025;
|
||||
public const int RTM_EC_ADMIN_ONLY = 200026;
|
||||
public const int RTM_EC_INVALID_AUTH_TOEKN = 200027;
|
||||
|
||||
public const int RTM_EC_LARGE_MESSAGE_OR_ATTRS = 200030;
|
||||
public const int RTM_EC_LARGE_FILE_OR_ATTRS = 200031;
|
||||
public const int RTM_EC_TOO_MANY_ITEMS_IN_PARAMETERS = 200032;
|
||||
public const int RTM_EC_EMPTY_PARAMETER = 200033;
|
||||
public const int RTM_EC_INVALID_PARAMETER = 200034;
|
||||
public const int RTM_EC_LARGE_DATA = 200035;
|
||||
|
||||
public const int RTM_EC_NOT_IN_ROOM = 200040;
|
||||
public const int RTM_EC_NOT_GROUP_MEMBER = 200041;
|
||||
public const int RTM_EC_MAX_GROUP_MEMBER_COUNT = 200042;
|
||||
public const int RTM_EC_NOT_FRIEND = 200043;
|
||||
public const int RTM_EC_BANNED_IN_GROUP = 200044;
|
||||
public const int RTM_EC_BANNED_IN_ROOM = 200045;
|
||||
public const int RTM_EC_EMPTY_GROUP = 200046;
|
||||
public const int RTM_EC_MAX_ROOM_COUNT = 200047;
|
||||
public const int RTM_EC_MAX_FRIEND_COUNT = 200048;
|
||||
public const int RTM_EC_BLOCKED_USER = 200049;
|
||||
|
||||
public const int RTM_EC_UNSUPPORTED_LANGUAGE = 200050;
|
||||
public const int RTM_EC_EMPTY_TRANSLATION = 200051;
|
||||
public const int RTM_EC_SEND_TO_SELF = 200052;
|
||||
public const int RTM_EC_DUPLCATED_MID = 200053;
|
||||
public const int RTM_EC_SENSITIVE_WORDS = 200054;
|
||||
public const int RTM_EC_NOT_ONLINE = 200055;
|
||||
public const int RTM_EC_TRANSLATION_ERROR = 200056;
|
||||
public const int RTM_EC_PROFANITY_STOP = 200057;
|
||||
public const int RTM_EC_NO_CONFIG_IN_CONSOLE = 200060;
|
||||
public const int RTM_EC_UNSUPPORTED_TRASNCRIBE_TYPE = 200061;
|
||||
public const int RTM_EC_BLOCK_USER = 200062;
|
||||
|
||||
public const int RTM_EC_MESSAGE_NOT_FOUND = 200070;
|
||||
|
||||
public const int RTM_EC_UNKNOWN_ERROR = 200999;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ba4bcf6a86f2433abd07d015223bda7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class MidGenerator
|
||||
{
|
||||
static private ushort order = 0;
|
||||
static private object interLocker = new object();
|
||||
|
||||
static public long Gen()
|
||||
{
|
||||
long baseId = ClientEngine.GetCurrentMilliseconds() << 16;
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
return baseId + ++order;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e74c15297ec2642c086cd61b71bc402a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.msgpack;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class InvalidAudioDataException : Exception
|
||||
{
|
||||
public InvalidAudioDataException(string message) : base(message) { }
|
||||
public InvalidAudioDataException(String message, Exception ex) : base(message, ex) { }
|
||||
}
|
||||
|
||||
public class RTMAudioData
|
||||
{
|
||||
|
||||
public static string DefaultCodec = "amr-wb";
|
||||
private string codecType;
|
||||
private string lang;
|
||||
private readonly byte[] audio; // Current is AMR-WB
|
||||
private float[] pcmData; // Original PCM data
|
||||
private long duration; // Duration in ms
|
||||
private int frequency;
|
||||
private int lengthSamples;
|
||||
|
||||
public RTMAudioData(byte[] audio, float[] pcmData, string codecType, string lang, long duration, int lengthSamples, int frequency)
|
||||
{
|
||||
this.audio = audio;
|
||||
this.pcmData = pcmData;
|
||||
this.codecType = codecType;
|
||||
this.lang = lang;
|
||||
this.duration = duration;
|
||||
this.lengthSamples = lengthSamples;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
public RTMAudioData(byte[] audio, FileInfo fileInfo)
|
||||
{
|
||||
codecType = DefaultCodec;
|
||||
lang = fileInfo.language;
|
||||
duration = fileInfo.duration;
|
||||
this.audio = audio;
|
||||
frequency = AudioRecorder.RECORD_SAMPLE_RATE;
|
||||
ParseAudioData();
|
||||
}
|
||||
|
||||
public RTMAudioData(byte[] audio, string language, long duration)
|
||||
{
|
||||
codecType = DefaultCodec;
|
||||
lang = language;
|
||||
this.duration = duration;
|
||||
this.audio = audio;
|
||||
frequency = AudioRecorder.RECORD_SAMPLE_RATE;
|
||||
ParseAudioData();
|
||||
}
|
||||
|
||||
private void ParseAudioData()
|
||||
{
|
||||
byte[] wavBuffer = AudioConvert.ConvertToWav(audio);
|
||||
|
||||
if (wavBuffer == null || wavBuffer.Length < 23)
|
||||
{
|
||||
throw new InvalidAudioDataException("Invalid audio data, convert failed.");
|
||||
}
|
||||
|
||||
int channelCount = wavBuffer[22];
|
||||
|
||||
int pos = 12;
|
||||
|
||||
while(! (wavBuffer.Length > pos+3 && wavBuffer[pos] == 100 && wavBuffer[pos+1] == 97 && wavBuffer[pos+2] == 116 && wavBuffer[pos+3] == 97)) {
|
||||
pos += 4;
|
||||
int chunkSize = wavBuffer[pos] + wavBuffer[pos + 1] * 256 + wavBuffer[pos + 2] * 65536 + wavBuffer[pos + 3] * 16777216;
|
||||
pos += 4 + chunkSize;
|
||||
}
|
||||
pos += 8;
|
||||
|
||||
lengthSamples = (wavBuffer.Length - pos) /2 ;
|
||||
|
||||
pcmData = new float[lengthSamples];
|
||||
|
||||
int idx = 0;
|
||||
while (pos < wavBuffer.Length) {
|
||||
pcmData[idx] = BytesToFloat(wavBuffer[pos], wavBuffer[pos + 1]);
|
||||
pos += 2;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
private static float BytesToFloat(byte firstByte, byte secondByte) {
|
||||
short s = (short)((secondByte << 8) | firstByte);
|
||||
return s / 32768.0F;
|
||||
}
|
||||
|
||||
public byte[] Audio
|
||||
{
|
||||
get
|
||||
{
|
||||
return audio;
|
||||
}
|
||||
}
|
||||
|
||||
public float[] PcmData
|
||||
{
|
||||
get
|
||||
{
|
||||
return pcmData;
|
||||
}
|
||||
}
|
||||
|
||||
public long Duration
|
||||
{
|
||||
get
|
||||
{
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
public string Language
|
||||
{
|
||||
get
|
||||
{
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
public string CodecType
|
||||
{
|
||||
get
|
||||
{
|
||||
return codecType;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthSamples
|
||||
{
|
||||
get
|
||||
{
|
||||
return lengthSamples;
|
||||
}
|
||||
}
|
||||
|
||||
public int Frequency
|
||||
{
|
||||
get
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9dbf0784ae094a7d8f9a65e62f1d409
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class RTMCallbackQueue : MonoBehaviour
|
||||
{
|
||||
private static Queue<Action> actionQueue = new Queue<Action>();
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (actionQueue)
|
||||
{
|
||||
actionQueue.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void PostAction(Action action)
|
||||
{
|
||||
lock (actionQueue)
|
||||
{
|
||||
actionQueue.Enqueue(action);
|
||||
}
|
||||
}
|
||||
|
||||
private Action GetAction()
|
||||
{
|
||||
lock (actionQueue)
|
||||
{
|
||||
Action action = actionQueue.Dequeue();
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
while (actionQueue.Count > 0)
|
||||
{
|
||||
Action action = GetAction();
|
||||
action();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 482ae1cf95d6746d8bc2284c1f4c61b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51ea35e78aa9447579e1f633b4b7f74e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,522 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
private List<Conversation> BuildP2PConversationList(List<long> conversations, List<int> unreads, List<object> messages)
|
||||
{
|
||||
List<Conversation> conversationList = new List<Conversation>();
|
||||
int i = 0;
|
||||
foreach (List<object> items in messages)
|
||||
{
|
||||
HistoryMessage message = new HistoryMessage();
|
||||
message.cursorId = (long)Convert.ChangeType(items[0], TypeCode.Int64);
|
||||
if (message.cursorId != 0)
|
||||
{
|
||||
long direction = (long)Convert.ChangeType(items[1], TypeCode.Int64);
|
||||
if (direction == 1)
|
||||
{
|
||||
message.fromUid = Uid;
|
||||
message.toId = conversations[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
message.fromUid = conversations[i];
|
||||
message.toId = Uid;
|
||||
}
|
||||
message.messageType = (byte)Convert.ChangeType(items[2], TypeCode.Byte);
|
||||
message.messageId = (long)Convert.ChangeType(items[3], TypeCode.Int64);
|
||||
|
||||
if (!CheckBinaryType(items[5]))
|
||||
message.stringMessage = (string)Convert.ChangeType(items[5], TypeCode.String);
|
||||
else
|
||||
message.binaryMessage = (byte[])items[5];
|
||||
|
||||
message.attrs = (string)Convert.ChangeType(items[6], TypeCode.String);
|
||||
message.modifiedTime = (long)Convert.ChangeType(items[7], TypeCode.Int64);
|
||||
|
||||
if (message.messageType >= 40 && message.messageType <= 50)
|
||||
RTMClient.BuildFileInfo(message, errorRecorder);
|
||||
}
|
||||
|
||||
Conversation conversation = new Conversation();
|
||||
conversation.id = conversations[i];
|
||||
conversation.conversationType = ConversationType.P2P;
|
||||
conversation.unreadCount = unreads[i];
|
||||
conversation.lastMessage = message;
|
||||
conversationList.Add(conversation);
|
||||
i += 1;
|
||||
}
|
||||
return conversationList;
|
||||
}
|
||||
|
||||
public bool GetP2PConversationList(Action<List<Conversation>, int> callback, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getp2pconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
List<Conversation> conversationList = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildP2PConversationList(conversations, unreads, messages);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(conversationList, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetP2PConversationList(out List<Conversation> conversationList, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
conversationList = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getp2pconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildP2PConversationList(conversations, unreads, messages);
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetP2PUnreadConversationList(Action<List<Conversation>, int> callback, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getp2punreadconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
List<Conversation> conversationList = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildP2PConversationList(conversations, unreads, messages);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(conversationList, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetP2PUnreadConversationList(out List<Conversation> conversationList, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
conversationList = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getp2punreadconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildP2PConversationList(conversations, unreads, messages);
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Conversation> BuildGroupConversationList(List<long> conversations, List<int> unreads, List<object> messages)
|
||||
{
|
||||
List<Conversation> conversationList = new List<Conversation>();
|
||||
int i = 0;
|
||||
foreach (List<object> items in messages)
|
||||
{
|
||||
HistoryMessage message = new HistoryMessage();
|
||||
message.cursorId = (long)Convert.ChangeType(items[0], TypeCode.Int64);
|
||||
if (message.cursorId != 0)
|
||||
{
|
||||
message.fromUid = (long)Convert.ChangeType(items[1], TypeCode.Int64);
|
||||
message.toId = conversations[i];
|
||||
message.messageType = (byte)Convert.ChangeType(items[2], TypeCode.Byte);
|
||||
message.messageId = (long)Convert.ChangeType(items[3], TypeCode.Int64);
|
||||
|
||||
if (!CheckBinaryType(items[5]))
|
||||
message.stringMessage = (string)Convert.ChangeType(items[5], TypeCode.String);
|
||||
else
|
||||
message.binaryMessage = (byte[])items[5];
|
||||
|
||||
message.attrs = (string)Convert.ChangeType(items[6], TypeCode.String);
|
||||
message.modifiedTime = (long)Convert.ChangeType(items[7], TypeCode.Int64);
|
||||
|
||||
if (message.messageType >= 40 && message.messageType <= 50)
|
||||
RTMClient.BuildFileInfo(message, errorRecorder);
|
||||
}
|
||||
|
||||
Conversation conversation = new Conversation();
|
||||
conversation.id = conversations[i];
|
||||
conversation.conversationType = ConversationType.GROUP;
|
||||
conversation.unreadCount = unreads[i];
|
||||
conversation.lastMessage = message;
|
||||
conversationList.Add(conversation);
|
||||
i += 1;
|
||||
}
|
||||
return conversationList;
|
||||
}
|
||||
|
||||
public bool GetGroupConversationList(Action<List<Conversation>, int> callback, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
List<Conversation> conversationList = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildGroupConversationList(conversations, unreads, messages);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(conversationList, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupConversationList(out List<Conversation> conversationList, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
conversationList = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildGroupConversationList(conversations, unreads, messages);
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetGroupUnreadConversationList(Action<List<Conversation>, int> callback, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupunreadconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
List<Conversation> conversationList = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildGroupConversationList(conversations, unreads, messages);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(conversationList, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupUnreadConversationList(out List<Conversation> conversationList, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
conversationList = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupunreadconversationlist");
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
List<long> conversations = WantLongList(answer, "conversations");
|
||||
List<int> unreads = GetIntList(answer, "unreads");
|
||||
List<object> messages = (List<object>)answer.Want("msgs");
|
||||
conversationList = BuildGroupConversationList(conversations, unreads, messages);
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetUnreadConversationList(Action<List<Conversation>, List<Conversation>, int> callback, bool clear = true, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getunreadconversationlist");
|
||||
quest.Param("clear", clear);
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
List<Conversation> groupConversationList = null;
|
||||
List<Conversation> p2pConversationList = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<long> groupConversations = WantLongList(answer, "groupConversations");
|
||||
List<int> groupUnreads = GetIntList(answer, "groupUnreads");
|
||||
List<object> groupMsgs = (List<object>)answer.Want("groupMsgs");
|
||||
List<long> p2pConversations = WantLongList(answer, "p2pConversations");
|
||||
List<int> p2pUnreads = GetIntList(answer, "p2pUnreads");
|
||||
List<object> p2pMsgs = (List<object>)answer.Want("p2pMsgs");
|
||||
|
||||
groupConversationList = BuildGroupConversationList(groupConversations, groupUnreads, groupMsgs);
|
||||
p2pConversationList = BuildP2PConversationList(p2pConversations, p2pUnreads, p2pMsgs);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(groupConversationList, p2pConversationList, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetUnreadConversationList(out List<Conversation> groupConversationList, out List<Conversation> p2pConversationList, bool clear = true, HashSet<byte> mTypes = null, long startTime = 0, int timeout = 0)
|
||||
{
|
||||
groupConversationList = null;
|
||||
p2pConversationList = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getunreadconversationlist");
|
||||
quest.Param("clear", clear);
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
if (startTime != 0)
|
||||
quest.Param("mtime", startTime);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
List<long> groupConversations = WantLongList(answer, "groupConversations");
|
||||
List<int> groupUnreads = GetIntList(answer, "groupUnreads");
|
||||
List<object> groupMsgs = (List<object>)answer.Want("groupMsgs");
|
||||
List<long> p2pConversations = WantLongList(answer, "p2pConversations");
|
||||
List<int> p2pUnreads = GetIntList(answer, "p2pUnreads");
|
||||
List<object> p2pMsgs = (List<object>)answer.Want("p2pMsgs");
|
||||
|
||||
groupConversationList = BuildGroupConversationList(groupConversations, groupUnreads, groupMsgs);
|
||||
p2pConversationList = BuildP2PConversationList(p2pConversations, p2pUnreads, p2pMsgs);
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd4b0e14ac34c400b8d5eb269cc2e8ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,851 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using com.fpnn.proto;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
public enum ClientStatus
|
||||
{
|
||||
Closed,
|
||||
Connecting,
|
||||
Connected
|
||||
}
|
||||
|
||||
//-------------[ Private class for Login ]--------------------------//
|
||||
|
||||
private class AutoReloginInfo
|
||||
{
|
||||
public bool disabled = true;
|
||||
public bool canRelogin = false;
|
||||
public int reloginCount = 0;
|
||||
public int lastErrorCode = 0;
|
||||
public long lastReloginMS = 0;
|
||||
|
||||
public string token;
|
||||
public long ts;
|
||||
public Dictionary<string, string> attr;
|
||||
public string lang;
|
||||
|
||||
public void Login()
|
||||
{
|
||||
if (disabled)
|
||||
{
|
||||
disabled = false;
|
||||
reloginCount = 0;
|
||||
lastErrorCode = 0;
|
||||
}
|
||||
else if (canRelogin)
|
||||
{
|
||||
reloginCount += 1;
|
||||
}
|
||||
|
||||
lastReloginMS = ClientEngine.GetCurrentMilliseconds();
|
||||
}
|
||||
|
||||
public void LoginSuccessful()
|
||||
{
|
||||
canRelogin = true;
|
||||
reloginCount = 0;
|
||||
lastErrorCode = 0;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
disabled = true;
|
||||
canRelogin = false;
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthStatusInfo
|
||||
{
|
||||
public HashSet<AuthDelegate> authDelegates;
|
||||
public string token;
|
||||
public long ts;
|
||||
public Dictionary<string, string> attr;
|
||||
public string lang;
|
||||
|
||||
public int remainedTimeout;
|
||||
public long lastActionMsecTimeStamp;
|
||||
}
|
||||
|
||||
//-------------[ Static Fields ]--------------------------//
|
||||
private static readonly HashSet<int> reloginStopCodes = new HashSet<int>
|
||||
{
|
||||
fpnn.ErrorCode.FPNN_EC_CORE_FORBIDDEN,
|
||||
|
||||
ErrorCode.RTM_EC_INVALID_PID_OR_UID,
|
||||
ErrorCode.RTM_EC_INVALID_PID_OR_SIGN,
|
||||
ErrorCode.RTM_EC_PERMISSION_DENIED,
|
||||
ErrorCode.RTM_EC_AUTH_DENIED,
|
||||
ErrorCode.RTM_EC_ADMIN_LOGIN,
|
||||
ErrorCode.RTM_EC_ADMIN_ONLY,
|
||||
ErrorCode.RTM_EC_INVALID_AUTH_TOEKN,
|
||||
ErrorCode.RTM_EC_BLOCKED_USER,
|
||||
};
|
||||
|
||||
//-------------[ Fields ]--------------------------//
|
||||
private object interLocker;
|
||||
private static object instanceLocker = new object();
|
||||
private readonly long projectId;
|
||||
private readonly long uid;
|
||||
|
||||
private ClientStatus status;
|
||||
private volatile bool requireClose;
|
||||
private ManualResetEvent syncConnectingEvent;
|
||||
|
||||
public volatile int ConnectTimeout;
|
||||
public volatile int QuestTimeout;
|
||||
|
||||
private IRTMMasterProcessor processor;
|
||||
private TCPClient rtmGate;
|
||||
private Int64 rtmGateConnectionId;
|
||||
|
||||
private AuthStatusInfo authStatsInfo;
|
||||
private AutoReloginInfo autoReloginInfo;
|
||||
private RegressiveStrategy regressiveStrategy;
|
||||
private common.ErrorRecorder errorRecorder;
|
||||
|
||||
public RTMClient(string endpoint, long projectId, long uid, RTMQuestProcessor serverPushProcessor, bool autoRelogin = true)
|
||||
{
|
||||
interLocker = new object();
|
||||
this.projectId = projectId;
|
||||
this.uid = uid;
|
||||
status = ClientStatus.Closed;
|
||||
requireClose = false;
|
||||
syncConnectingEvent = new ManualResetEvent(false);
|
||||
|
||||
ConnectTimeout = 0;
|
||||
QuestTimeout = 0;
|
||||
|
||||
RTMMasterProcessor processorCurrent = new RTMMasterProcessor();
|
||||
processorCurrent.SetProcessor(serverPushProcessor);
|
||||
processor = processorCurrent;
|
||||
|
||||
errorRecorder = RTMConfig.errorRecorder;
|
||||
if (errorRecorder != null)
|
||||
processor.SetErrorRecorder(errorRecorder);
|
||||
|
||||
|
||||
BuildRtmGateClient(endpoint);
|
||||
|
||||
if (autoRelogin)
|
||||
{
|
||||
autoReloginInfo = new AutoReloginInfo();
|
||||
regressiveStrategy = RTMConfig.globalRegressiveStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
private void reset(RTMQuestProcessor serverPushProcessor, bool autoRelogin)
|
||||
{
|
||||
//status = ClientStatus.Closed;
|
||||
//requireClose = false;
|
||||
//ConnectTimeout = 0;
|
||||
//QuestTimeout = 0;
|
||||
//rtmGateConnectionId = 0;
|
||||
|
||||
//RTMMasterProcessor processorCurrent = new RTMMasterProcessor();
|
||||
//processorCurrent.SetProcessor(serverPushProcessor);
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
(processor as RTMMasterProcessor).SetProcessor(serverPushProcessor);
|
||||
//processorCurrent.SetConnectionId(rtmGateConnectionId);
|
||||
//processor = processorCurrent;
|
||||
if (errorRecorder != null)
|
||||
processor.SetErrorRecorder(errorRecorder);
|
||||
|
||||
if (autoRelogin)
|
||||
{
|
||||
autoReloginInfo = new AutoReloginInfo();
|
||||
regressiveStrategy = RTMConfig.globalRegressiveStrategy;
|
||||
}
|
||||
else
|
||||
{
|
||||
autoReloginInfo = null;
|
||||
regressiveStrategy = null;
|
||||
}
|
||||
}
|
||||
|
||||
//authStatsInfo = null;
|
||||
//syncConnectingEvent.Reset();
|
||||
}
|
||||
|
||||
public static RTMClient getInstance(string endpoint, long projectId, long uid, RTMQuestProcessor serverPushProcessor, bool autoRelogin = true)
|
||||
{
|
||||
RTMClient client = null;
|
||||
lock (instanceLocker)
|
||||
{
|
||||
client = RTMControlCenter.FetchClient(projectId, uid);
|
||||
if (client != null)
|
||||
{
|
||||
client.reset(serverPushProcessor, autoRelogin);
|
||||
}
|
||||
else
|
||||
{
|
||||
client = new RTMClient(endpoint, projectId, uid, serverPushProcessor, autoRelogin);
|
||||
RTMControlCenter.AddClient(projectId, uid, client);
|
||||
}
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
//-------------[ Fack Fields ]--------------------------//
|
||||
|
||||
//-- Obsolete in v.2.2.0
|
||||
[Obsolete("Property Pid is deprecated, please use ProjectId instead.")]
|
||||
public long Pid
|
||||
{
|
||||
get
|
||||
{
|
||||
return projectId;
|
||||
}
|
||||
}
|
||||
|
||||
public long ProjectId
|
||||
{
|
||||
get
|
||||
{
|
||||
return projectId;
|
||||
}
|
||||
}
|
||||
|
||||
public long Uid
|
||||
{
|
||||
get
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
|
||||
public ClientStatus Status
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (interLocker)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public common.ErrorRecorder ErrorRecorder
|
||||
{
|
||||
set
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
errorRecorder = value;
|
||||
processor.SetErrorRecorder(errorRecorder);
|
||||
rtmGate.SetErrorRecorder(errorRecorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ConnectionIsAlive()
|
||||
{
|
||||
return processor.ConnectionIsAlive();
|
||||
}
|
||||
|
||||
public void SetRegressiveStrategy(RegressiveStrategy strategy)
|
||||
{
|
||||
regressiveStrategy = strategy;
|
||||
}
|
||||
|
||||
private TCPClient GetCoreClient()
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
if (status == ClientStatus.Connected)
|
||||
return rtmGate;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------[ Init Functions ]--------------------------//
|
||||
private string adjustEndpoint(string originalEndpoint)
|
||||
{
|
||||
int idx = originalEndpoint.LastIndexOf(':');
|
||||
if (idx < 1)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Invalid RTM client endpoint: " + originalEndpoint);
|
||||
|
||||
return originalEndpoint;
|
||||
}
|
||||
|
||||
string portString = originalEndpoint.Substring(idx + 1);
|
||||
int port = Convert.ToInt32(portString, 10);
|
||||
if (port == 13321)
|
||||
return originalEndpoint;
|
||||
|
||||
if (port == 13325)
|
||||
return originalEndpoint.Substring(0, idx) + ":" + 13321;
|
||||
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Invalid RTM client endpoint: " + originalEndpoint + " (invalid port)");
|
||||
|
||||
return originalEndpoint;
|
||||
}
|
||||
|
||||
private void BuildRtmGateClient(string originalEndpoint)
|
||||
{
|
||||
rtmGate = TCPClient.Create(adjustEndpoint(originalEndpoint), true);
|
||||
|
||||
if (errorRecorder != null)
|
||||
rtmGate.SetErrorRecorder(errorRecorder);
|
||||
|
||||
rtmGate.SetQuestProcessor(processor);
|
||||
rtmGate.SetConnectionConnectedDelegate((Int64 connectionId, string endpoint, bool connected) => {
|
||||
if (requireClose)
|
||||
{
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_CONNECTION_CLOSED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connected)
|
||||
{
|
||||
rtmGateConnectionId = connectionId;
|
||||
RTMControlCenter.RegisterSession(rtmGateConnectionId, this);
|
||||
Auth(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
}
|
||||
});
|
||||
|
||||
rtmGate.SetConnectionCloseDelegate((Int64 connectionId, string endpoint, bool causedByError) => {
|
||||
|
||||
bool trigger = false;
|
||||
bool isConnecting = false;
|
||||
bool startRelogin = false;
|
||||
lock (interLocker)
|
||||
{
|
||||
trigger = rtmGateConnectionId == connectionId;
|
||||
if (trigger)
|
||||
{
|
||||
if (status == ClientStatus.Connecting)
|
||||
isConnecting = true;
|
||||
else
|
||||
{
|
||||
status = ClientStatus.Closed;
|
||||
rtmGateConnectionId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (autoReloginInfo != null)
|
||||
{
|
||||
startRelogin = CheckRelogin();
|
||||
autoReloginInfo.lastErrorCode = (causedByError ? fpnn.ErrorCode.FPNN_EC_CORE_CONNECTION_CLOSED : fpnn.ErrorCode.FPNN_EC_OK);
|
||||
}
|
||||
}
|
||||
|
||||
if (trigger)
|
||||
{
|
||||
if (isConnecting)
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
else
|
||||
{
|
||||
if (startRelogin)
|
||||
StartRelogin();
|
||||
else
|
||||
processor.SessionClosed(causedByError ? fpnn.ErrorCode.FPNN_EC_CORE_UNKNOWN_ERROR : fpnn.ErrorCode.FPNN_EC_OK);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public bool CheckRelogin()
|
||||
{
|
||||
return autoReloginInfo.disabled == false && autoReloginInfo.canRelogin && RTMControlCenter.NetworkStatus != NetworkType.NetworkType_Unreachable;
|
||||
}
|
||||
|
||||
//-------------[ Auth(Login) processing functions ]--------------------------//
|
||||
private void AuthFinish(bool authStatus, int errorCode)
|
||||
{
|
||||
AuthStatusInfo currInfo;
|
||||
long currUid;
|
||||
bool isRelogin = false;
|
||||
Int64 reservedRtmGateConnectionId = 0;
|
||||
bool needClose = false;
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (status != ClientStatus.Connecting)
|
||||
return;
|
||||
|
||||
if (authStatus)
|
||||
{
|
||||
status = ClientStatus.Connected;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ClientStatus.Closed;
|
||||
reservedRtmGateConnectionId = rtmGateConnectionId;
|
||||
rtmGateConnectionId = 0;
|
||||
needClose = true;
|
||||
//-- Reserving rtmGate without closing for quick relogin.
|
||||
}
|
||||
|
||||
if (autoReloginInfo != null)
|
||||
{
|
||||
isRelogin = autoReloginInfo.canRelogin;
|
||||
|
||||
if (authStatsInfo != null)
|
||||
{
|
||||
autoReloginInfo.token = authStatsInfo.token;
|
||||
autoReloginInfo.ts = authStatsInfo.ts;
|
||||
autoReloginInfo.attr = authStatsInfo.attr;
|
||||
autoReloginInfo.lang = authStatsInfo.lang;
|
||||
}
|
||||
|
||||
if (authStatus && !autoReloginInfo.canRelogin)
|
||||
autoReloginInfo.LoginSuccessful();
|
||||
}
|
||||
|
||||
currInfo = authStatsInfo;
|
||||
authStatsInfo = null;
|
||||
currUid = uid;
|
||||
|
||||
if (needClose)
|
||||
rtmGate.Close();
|
||||
|
||||
syncConnectingEvent.Set();
|
||||
}
|
||||
|
||||
if (reservedRtmGateConnectionId != 0)
|
||||
RTMControlCenter.UnregisterSession(reservedRtmGateConnectionId);
|
||||
|
||||
if (currInfo != null)
|
||||
foreach (AuthDelegate callback in currInfo.authDelegates)
|
||||
callback(projectId, currUid, authStatus, errorCode);
|
||||
|
||||
if (authStatus)
|
||||
processor.BeginCheckPingInterval();
|
||||
}
|
||||
|
||||
private bool AdjustAuthRemainedTimeout()
|
||||
{
|
||||
if (authStatsInfo == null)
|
||||
return false;
|
||||
long curr = ClientEngine.GetCurrentMilliseconds();
|
||||
int passSeconds = (int)(curr - authStatsInfo.lastActionMsecTimeStamp) / 1000;
|
||||
authStatsInfo.lastActionMsecTimeStamp = curr;
|
||||
authStatsInfo.remainedTimeout -= passSeconds;
|
||||
if (authStatsInfo.remainedTimeout <= 0)
|
||||
{
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Auth(bool checkRemainedTimeout)
|
||||
{
|
||||
if (checkRemainedTimeout && !AdjustAuthRemainedTimeout())
|
||||
return;
|
||||
|
||||
processor.SetConnectionId(rtmGateConnectionId);
|
||||
|
||||
Quest quest = new Quest("auth");
|
||||
quest.Param("pid", projectId);
|
||||
quest.Param("uid", uid);
|
||||
quest.Param("token", authStatsInfo.token);
|
||||
if (authStatsInfo.ts != 0)
|
||||
{
|
||||
quest.Param("ts", authStatsInfo.ts);
|
||||
quest.Param("authv", 2);
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
quest.Param("version", "Unity-" + RTMConfig.SDKVersion);
|
||||
#else
|
||||
quest.Param("version", "C#-" + RTMConfig.SDKVersion);
|
||||
#endif
|
||||
|
||||
if (authStatsInfo.lang.Length > 0)
|
||||
quest.Param("lang", authStatsInfo.lang);
|
||||
|
||||
if (authStatsInfo.attr != null && authStatsInfo.attr.Count > 0)
|
||||
quest.Param("attrs", authStatsInfo.attr);
|
||||
|
||||
int timeout = authStatsInfo.remainedTimeout;
|
||||
|
||||
bool status = rtmGate.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
if (requireClose)
|
||||
{
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_CONNECTION_CLOSED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
bool ok = answer.Get<bool>("ok", false);
|
||||
AuthFinish(ok, fpnn.ErrorCode.FPNN_EC_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthFinish(false, errorCode);
|
||||
}
|
||||
}, timeout);
|
||||
if (!status)
|
||||
AuthFinish(false, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
}
|
||||
|
||||
//-------------[ Login & System interfaces ]--------------------------//
|
||||
public bool Login(AuthDelegate callback, string token, int timeout = 0)
|
||||
{
|
||||
return Login(callback, token, null, 0, "", timeout);
|
||||
}
|
||||
|
||||
public bool Login(AuthDelegate callback, string token, long ts, int timeout = 0)
|
||||
{
|
||||
return Login(callback, token, null, ts, "", timeout);
|
||||
}
|
||||
|
||||
public bool Login(AuthDelegate callback, string token, Dictionary<string, string> attr, TranslateLanguage language = TranslateLanguage.None, int timeout = 0)
|
||||
{
|
||||
return Login(callback, token, attr, 0, GetTranslatedLanguage(language), timeout);
|
||||
}
|
||||
|
||||
public bool Login(AuthDelegate callback, string token, long ts, Dictionary<string, string> attr, TranslateLanguage language = TranslateLanguage.None, int timeout = 0)
|
||||
{
|
||||
return Login(callback, token, attr, ts, GetTranslatedLanguage(language), timeout);
|
||||
}
|
||||
|
||||
private bool Login(AuthDelegate callback, string token, Dictionary<string, string> attr, long ts = 0, string lang = "", int timeout = 0)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
if (status == ClientStatus.Connected)
|
||||
{
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(projectId, uid, true, fpnn.ErrorCode.FPNN_EC_OK);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (status == ClientStatus.Connecting)
|
||||
{
|
||||
authStatsInfo.authDelegates.Add(callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
status = ClientStatus.Connecting;
|
||||
syncConnectingEvent.Reset();
|
||||
|
||||
requireClose = false;
|
||||
|
||||
if (autoReloginInfo != null)
|
||||
autoReloginInfo.Login();
|
||||
authStatsInfo = new AuthStatusInfo
|
||||
{
|
||||
authDelegates = new HashSet<AuthDelegate>() { callback },
|
||||
remainedTimeout = timeout,
|
||||
};
|
||||
|
||||
authStatsInfo.token = token;
|
||||
authStatsInfo.ts = ts;
|
||||
authStatsInfo.attr = attr;
|
||||
authStatsInfo.lang = lang;
|
||||
authStatsInfo.lastActionMsecTimeStamp = ClientEngine.GetCurrentMilliseconds();
|
||||
if (authStatsInfo.remainedTimeout == 0)
|
||||
authStatsInfo.remainedTimeout = ((ConnectTimeout == 0) ? RTMConfig.globalConnectTimeoutSeconds : ConnectTimeout)
|
||||
+ ((QuestTimeout == 0) ? RTMConfig.globalQuestTimeoutSeconds : QuestTimeout);
|
||||
}
|
||||
|
||||
rtmGate.AsyncConnect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Login(out bool ok, string token, int timeout = 0)
|
||||
{
|
||||
return Login(out ok, token, null, 0, "", timeout);
|
||||
}
|
||||
|
||||
public int Login(out bool ok, string token, long ts, int timeout = 0)
|
||||
{
|
||||
return Login(out ok, token, null, ts, "", timeout);
|
||||
}
|
||||
|
||||
private class SyncLoginStatus
|
||||
{
|
||||
private ManualResetEvent syncWaiter;
|
||||
public bool ok;
|
||||
public int errorCode;
|
||||
|
||||
public SyncLoginStatus()
|
||||
{
|
||||
syncWaiter = new ManualResetEvent(false);
|
||||
syncWaiter.Reset();
|
||||
}
|
||||
|
||||
public void Set()
|
||||
{
|
||||
syncWaiter.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
syncWaiter.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
public int Login(out bool ok, string token, Dictionary<string, string> attr, TranslateLanguage language = TranslateLanguage.None, int timeout = 0)
|
||||
{
|
||||
return Login(out ok, token, attr, 0, GetTranslatedLanguage(language), timeout);
|
||||
}
|
||||
|
||||
public int Login(out bool ok, string token, long ts, Dictionary<string, string> attr, TranslateLanguage language = TranslateLanguage.None, int timeout = 0)
|
||||
{
|
||||
return Login(out ok, token, attr, ts, GetTranslatedLanguage(language), timeout);
|
||||
}
|
||||
|
||||
private int Login(out bool ok, string token, Dictionary<string, string> attr, long ts = 0, string lang = "", int timeout = 0)
|
||||
{
|
||||
SyncLoginStatus syncLoginStatus = new SyncLoginStatus();
|
||||
bool actionBegin = Login((long projectId, long uid, bool authStatus, int errorCode) => {
|
||||
syncLoginStatus.ok = authStatus;
|
||||
syncLoginStatus.errorCode = errorCode;
|
||||
syncLoginStatus.Set();
|
||||
}, token, attr, ts, lang, timeout);
|
||||
if (!actionBegin)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
if (status == ClientStatus.Connected)
|
||||
{
|
||||
ok = true;
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
if (status == ClientStatus.Closed)
|
||||
{
|
||||
ok = false;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncLoginStatus.Wait();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
ok = syncLoginStatus.ok;
|
||||
return syncLoginStatus.errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------[ Relogin interfaces ]--------------------------//
|
||||
private void StartNextRelogin()
|
||||
{
|
||||
int regressiveCount = autoReloginInfo.reloginCount;
|
||||
long interval = regressiveStrategy.maxIntervalSeconds * 1000;
|
||||
if (regressiveCount > regressiveStrategy.maxRegressvieCount)
|
||||
{
|
||||
processor.SessionClosed(autoReloginInfo.lastErrorCode);
|
||||
return;
|
||||
}
|
||||
if (regressiveCount < regressiveStrategy.linearRegressiveCount)
|
||||
{
|
||||
interval = interval * regressiveCount / regressiveStrategy.linearRegressiveCount;
|
||||
}
|
||||
RTMControlCenter.DelayRelogin(this, ClientEngine.GetCurrentMilliseconds() + interval);
|
||||
}
|
||||
|
||||
internal void StartRelogin()
|
||||
{
|
||||
bool launch = processor.ReloginWillStart(autoReloginInfo.lastErrorCode, autoReloginInfo.reloginCount);
|
||||
if (!launch)
|
||||
{
|
||||
processor.SessionClosed(autoReloginInfo.lastErrorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
bool startLogin = Login((long projectId, long uid, bool successful, int errorCode) =>
|
||||
{
|
||||
if (successful)
|
||||
{
|
||||
processor.ReloginCompleted(true, false, errorCode, autoReloginInfo.reloginCount);
|
||||
autoReloginInfo.LoginSuccessful();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool connected = false;
|
||||
lock (interLocker)
|
||||
{
|
||||
if (status == ClientStatus.Connected)
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (connected || errorCode == ErrorCode.RTM_EC_DUPLCATED_AUTH)
|
||||
{
|
||||
processor.ReloginCompleted(true, false, fpnn.ErrorCode.FPNN_EC_OK, autoReloginInfo.reloginCount);
|
||||
autoReloginInfo.LoginSuccessful();
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
processor.ReloginCompleted(false, false, ErrorCode.RTM_EC_INVALID_AUTH_TOEKN, autoReloginInfo.reloginCount);
|
||||
autoReloginInfo.Disable();
|
||||
processor.SessionClosed(ErrorCode.RTM_EC_INVALID_AUTH_TOEKN);
|
||||
return;
|
||||
}
|
||||
|
||||
bool stopRetry = reloginStopCodes.Contains(errorCode);
|
||||
|
||||
processor.ReloginCompleted(false, !stopRetry, errorCode, autoReloginInfo.reloginCount);
|
||||
if (stopRetry)
|
||||
{
|
||||
autoReloginInfo.Disable();
|
||||
processor.SessionClosed(errorCode);
|
||||
return;
|
||||
}
|
||||
else
|
||||
autoReloginInfo.lastErrorCode = errorCode;
|
||||
|
||||
StartNextRelogin();
|
||||
}
|
||||
},
|
||||
autoReloginInfo.token, autoReloginInfo.attr, autoReloginInfo.ts, autoReloginInfo.lang);
|
||||
|
||||
if (!startLogin && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse == false)
|
||||
{
|
||||
ClientStatus connStatus;
|
||||
lock (interLocker)
|
||||
{
|
||||
connStatus = status;
|
||||
}
|
||||
|
||||
if (connStatus == ClientStatus.Connected)
|
||||
{
|
||||
processor.ReloginCompleted(true, false, fpnn.ErrorCode.FPNN_EC_OK, autoReloginInfo.reloginCount);
|
||||
autoReloginInfo.LoginSuccessful();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorCode = fpnn.ErrorCode.FPNN_EC_CORE_CONNECTION_CLOSED;
|
||||
if (connStatus == ClientStatus.Connecting)
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_UNKNOWN_ERROR;
|
||||
|
||||
processor.ReloginCompleted(false, true, errorCode, autoReloginInfo.reloginCount);
|
||||
autoReloginInfo.lastErrorCode = errorCode;
|
||||
StartNextRelogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------[ Close interfaces ]--------------------------//
|
||||
internal void Close(bool disableRelogin, bool waitConnectingCannelled)
|
||||
{
|
||||
bool isConnecting = false;
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (disableRelogin && autoReloginInfo != null)
|
||||
autoReloginInfo.Disable();
|
||||
|
||||
if (status == ClientStatus.Closed)
|
||||
return;
|
||||
|
||||
requireClose = true;
|
||||
|
||||
if (status == ClientStatus.Connecting)
|
||||
{
|
||||
isConnecting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ClientStatus.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
rtmGate.Close();
|
||||
|
||||
if (isConnecting && waitConnectingCannelled)
|
||||
syncConnectingEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Close(bool waitConnectingCannelled = true)
|
||||
{
|
||||
Close(true, waitConnectingCannelled);
|
||||
}
|
||||
|
||||
public bool GetServerTime(Action<long, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getservertime");
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
long msec = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{ msec = answer.Get<long>("mts", 0); }
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(msec, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetServerTime(out long msec, int timeout = 0)
|
||||
{
|
||||
msec = 0;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getservertime");
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
msec = answer.Get<long>("mts", 0);
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ac63defd7aef4aa98ea19b883c03a01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using com.fpnn.proto;
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//===========================[ Data Get ]=========================//
|
||||
//-- Action<value, errorCode>
|
||||
public bool DataGet(Action<string, int> callback, string key, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("dataget");
|
||||
quest.Param("key", key);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string value = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{ value = answer.Get<string>("val", null); }
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(value, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DataGet(out string value, string key, int timeout = 0)
|
||||
{
|
||||
value = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("dataget");
|
||||
quest.Param("key", key);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
value = answer.Get<string>("val", null);
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Data Set ]=========================//
|
||||
public bool DataSet(DoneDelegate callback, string key, string value, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("dataset");
|
||||
quest.Param("key", key);
|
||||
quest.Param("val", value);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DataSet(string key, string value, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("dataset");
|
||||
quest.Param("key", key);
|
||||
quest.Param("val", value);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Data Delete ]=========================//
|
||||
public bool DataDelete(DoneDelegate callback, string key, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("datadel");
|
||||
quest.Param("key", key);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DataDelete(string key, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("datadel");
|
||||
quest.Param("key", key);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e67729abad0244684936ae1621abb727
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,145 @@
|
||||
using System.Collections.Generic;
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public delegate void AuthDelegate(long projectId, long uid, bool successful, int errorCode);
|
||||
public delegate void DoneDelegate(int errorCode);
|
||||
public delegate void MessageIdDelegate(long messageId, int errorCode);
|
||||
public delegate void SendMessageDelegate(long messageId, long mtime, int errorCode);
|
||||
|
||||
public class CheckResult
|
||||
{
|
||||
public int result;
|
||||
public List<int> tags;
|
||||
}
|
||||
|
||||
public class TextCheckResult : CheckResult
|
||||
{
|
||||
public string text;
|
||||
public List<string> wlist;
|
||||
public string language;
|
||||
}
|
||||
|
||||
public class FileInfo
|
||||
{
|
||||
//-- Common
|
||||
public string url; //-- File url
|
||||
public int size = 0; //-- File size
|
||||
|
||||
//-- For image type
|
||||
public string surl; //-- Thumb url, only for image type.
|
||||
|
||||
//-- For RTM audio
|
||||
public bool isRTMAudio = false;
|
||||
public string language;
|
||||
public int duration = 0;
|
||||
}
|
||||
|
||||
public class BaseMessage
|
||||
{
|
||||
public byte messageType;
|
||||
public string stringMessage = null;
|
||||
public byte[] binaryMessage = null;
|
||||
public string attrs;
|
||||
public long modifiedTime;
|
||||
public FileInfo fileInfo = null;
|
||||
|
||||
//-- Compatible with version 2.1.4 and before.
|
||||
[System.Obsolete("Field mtype is deprecated, please use messageType instead.")]
|
||||
public byte mtype
|
||||
{
|
||||
get { return messageType; }
|
||||
set { messageType = value; }
|
||||
}
|
||||
|
||||
[System.Obsolete("Field mtime is deprecated, please use modifiedTime instead.")]
|
||||
public long mtime
|
||||
{
|
||||
get { return modifiedTime; }
|
||||
set { modifiedTime = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class RetrievedMessage : BaseMessage
|
||||
{
|
||||
public long cursorId;
|
||||
|
||||
//-- Compatible with version 2.1.4 and before.
|
||||
[System.Obsolete("Field id is deprecated, please use cursorId instead.")]
|
||||
public long id
|
||||
{
|
||||
get { return cursorId; }
|
||||
set { cursorId = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class TranslatedInfo
|
||||
{
|
||||
public string sourceLanguage;
|
||||
public string targetLanguage;
|
||||
public string sourceText;
|
||||
public string targetText;
|
||||
}
|
||||
|
||||
public class RTMMessage : BaseMessage
|
||||
{
|
||||
public long fromUid;
|
||||
public long toId; //-- xid
|
||||
public long messageId;
|
||||
public TranslatedInfo translatedInfo = null;
|
||||
|
||||
//-- Compatible with version 2.1.4 and before.
|
||||
[System.Obsolete("Field mid is deprecated, please use messageId instead.")]
|
||||
public long mid
|
||||
{
|
||||
get { return messageId; }
|
||||
set { messageId = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class HistoryMessage : RTMMessage
|
||||
{
|
||||
public long cursorId;
|
||||
|
||||
//-- Compatible with version 2.1.4 and before.
|
||||
[System.Obsolete("Field id is deprecated, please use cursorId instead.")]
|
||||
public long id
|
||||
{
|
||||
get { return cursorId; }
|
||||
set { cursorId = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class HistoryMessageResult
|
||||
{
|
||||
public int count;
|
||||
public long lastCursorId;
|
||||
public long beginMsec;
|
||||
public long endMsec;
|
||||
public List<HistoryMessage> messages;
|
||||
|
||||
[System.Obsolete("Field lastId is deprecated, please use lastCursorId instead.")]
|
||||
public long lastId
|
||||
{
|
||||
get { return lastCursorId; }
|
||||
set { lastCursorId = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void HistoryMessageDelegate(int count, long lastCursorId, long beginMsec, long endMsec, List<HistoryMessage> messages, int errorCode);
|
||||
|
||||
public enum ConversationType
|
||||
{
|
||||
INVALID = 0,
|
||||
P2P = 1,
|
||||
GROUP = 2,
|
||||
ROOM = 3,
|
||||
}
|
||||
|
||||
public class Conversation
|
||||
{
|
||||
public long id;
|
||||
public ConversationType conversationType;
|
||||
public int unreadCount;
|
||||
public HistoryMessage lastMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ccf7ede33da94a6fb81508287c08c1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
private Dictionary<string, object> BuildAudioMessageAttrs(RTMAudioData audioData)
|
||||
{
|
||||
Dictionary<string, object> rtmAttrs = new Dictionary<string, object>();
|
||||
rtmAttrs.Add("type", "audiomsg");
|
||||
rtmAttrs.Add("codec", audioData.CodecType);
|
||||
rtmAttrs.Add("srate", audioData.Frequency);
|
||||
rtmAttrs.Add("lang", audioData.Language);
|
||||
rtmAttrs.Add("duration", audioData.Duration);
|
||||
return rtmAttrs;
|
||||
}
|
||||
|
||||
//===========================[ Send RTM-Audio File ]=========================//
|
||||
public bool SendFile(MessageIdDelegate callback, long peerUid, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.P2P, peerUid, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendFile(out long messageId, long peerUid, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.P2P, peerUid, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendFile(SendMessageDelegate callback, long peerUid, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.P2P, peerUid, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendFile(out long messageId, out long mtime, long peerUid, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.P2P, peerUid, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
//===========================[ Send RTM-Audio Group File ]=========================//
|
||||
public bool SendGroupFile(MessageIdDelegate callback, long groupId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Group, groupId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendGroupFile(out long messageId, long groupId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.Group, groupId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendGroupFile(SendMessageDelegate callback, long groupId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Group, groupId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendGroupFile(out long messageId, out long mtime, long groupId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.Group, groupId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
//===========================[ Send RTM-Audio Room File ]=========================//
|
||||
public bool SendRoomFile(MessageIdDelegate callback, long roomId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Room, roomId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendRoomFile(out long messageId, long roomId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.Room, roomId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendRoomFile(SendMessageDelegate callback, long roomId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Room, roomId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
|
||||
public int SendRoomFile(out long messageId, out long mtime, long roomId, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.Room, roomId, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), 0, timeout);
|
||||
}
|
||||
//===========================[ Upload RTM-Audio File ]=========================//
|
||||
public bool UploadFile(Action<string, uint, int> callback, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealUploadFile(callback, FileTokenType.Upload, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), timeout);
|
||||
}
|
||||
|
||||
public int UploadFile(out string url, out uint size, RTMAudioData audioData, string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealUploadFile(out url, out size, FileTokenType.Upload, (byte)MessageType.AudioFile, audioData.Audio, "", "", attrs, BuildAudioMessageAttrs(audioData), timeout);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9507cd07a08ed4e7b830c720e6ae6b86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,996 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using com.fpnn.proto;
|
||||
using com.fpnn.common;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
private enum FileTokenType
|
||||
{
|
||||
P2P,
|
||||
Group,
|
||||
Room,
|
||||
Upload,
|
||||
}
|
||||
|
||||
private class SendFileInfo
|
||||
{
|
||||
public FileTokenType actionType;
|
||||
|
||||
public long xid;
|
||||
public byte mtype;
|
||||
public byte[] fileContent;
|
||||
public string filename;
|
||||
public string fileExtension;
|
||||
public string userAttrs;
|
||||
public long messageId;
|
||||
|
||||
public string token;
|
||||
public string endpoint;
|
||||
public int remainTimeout;
|
||||
public long lastActionTimestamp;
|
||||
public MessageIdDelegate callback;
|
||||
public SendMessageDelegate callbackMtime;
|
||||
public Action<string, uint, int> uploadCallback;
|
||||
public Dictionary<string, object> rtmAttrs;
|
||||
}
|
||||
|
||||
//===========================[ File Token ]=========================//
|
||||
//-- Action<token, endpoint, errorCode>
|
||||
private bool FileToken(Action<string, string, int> callback, FileTokenType tokenType, long xid, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return false;
|
||||
|
||||
Quest quest = new Quest("filetoken");
|
||||
switch (tokenType)
|
||||
{
|
||||
case FileTokenType.P2P:
|
||||
quest.Param("cmd", "sendfile");
|
||||
quest.Param("to", xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Group:
|
||||
quest.Param("cmd", "sendgroupfile");
|
||||
quest.Param("gid", xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Room:
|
||||
quest.Param("cmd", "sendroomfile");
|
||||
quest.Param("rid", xid);
|
||||
break;
|
||||
case FileTokenType.Upload:
|
||||
quest.Param("cmd", "uploadfile");
|
||||
break;
|
||||
}
|
||||
|
||||
return client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string token = "";
|
||||
string endpoint = "";
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
token = answer.Want<string>("token");
|
||||
endpoint = answer.Want<string>("endpoint");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(token, endpoint, errorCode);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
private int FileToken(out string token, out string endpoint, FileTokenType tokenType, long xid, int timeout = 0)
|
||||
{
|
||||
token = "";
|
||||
endpoint = "";
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("filetoken");
|
||||
switch (tokenType)
|
||||
{
|
||||
case FileTokenType.P2P:
|
||||
quest.Param("cmd", "sendfile");
|
||||
quest.Param("to", xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Group:
|
||||
quest.Param("cmd", "sendgroupfile");
|
||||
quest.Param("gid", xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Room:
|
||||
quest.Param("cmd", "sendroomfile");
|
||||
quest.Param("rid", xid);
|
||||
break;
|
||||
case FileTokenType.Upload:
|
||||
quest.Param("cmd", "uploadfile");
|
||||
break;
|
||||
}
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
token = answer.Want<string>("token");
|
||||
endpoint = answer.Want<string>("endpoint");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ IPv4 Convert IPv6 Utilies ]=========================//
|
||||
private string ConvertIPv4ToIPv6(string ipv4)
|
||||
{
|
||||
string[] parts = ipv4.Split(new Char[] { '.' });
|
||||
if (parts.Length != 4)
|
||||
return string.Empty;
|
||||
|
||||
foreach (string part in parts)
|
||||
{
|
||||
int partInt = Int32.Parse(part);
|
||||
if (partInt > 255 || partInt < 0)
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string part7 = Convert.ToString(Int32.Parse(parts[0]) * 256 + Int32.Parse(parts[1]), 16);
|
||||
string part8 = Convert.ToString(Int32.Parse(parts[2]) * 256 + Int32.Parse(parts[3]), 16);
|
||||
return "64:ff9b::" + part7 + ":" + part8;
|
||||
}
|
||||
|
||||
private bool ConvertIPv4EndpointToIPv6IPPort(string ipv4endpoint, out string ipv6, out int port)
|
||||
{
|
||||
int idx = ipv4endpoint.LastIndexOf(':');
|
||||
if (idx == -1)
|
||||
{
|
||||
ipv6 = string.Empty;
|
||||
port = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string ipv4 = ipv4endpoint.Substring(0, idx);
|
||||
string portString = ipv4endpoint.Substring(idx + 1);
|
||||
port = Convert.ToInt32(portString, 10);
|
||||
|
||||
ipv6 = ConvertIPv4ToIPv6(ipv4);
|
||||
if (ipv6.Length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================[ File Utilies ]=========================//
|
||||
private void UpdateTimeout(ref int timeout, ref long lastActionTimestamp)
|
||||
{
|
||||
long currMsec = ClientEngine.GetCurrentMilliseconds();
|
||||
|
||||
timeout -= (int)((currMsec - lastActionTimestamp) / 1000);
|
||||
|
||||
lastActionTimestamp = currMsec;
|
||||
}
|
||||
|
||||
private string ExtraFileExtension(string filename)
|
||||
{
|
||||
int idx = filename.LastIndexOf('.');
|
||||
if (idx == -1)
|
||||
return null;
|
||||
|
||||
return filename.Substring(idx + 1);
|
||||
}
|
||||
|
||||
private string GetMD5(string str, bool upper)
|
||||
{
|
||||
byte[] inputBytes = Encoding.ASCII.GetBytes(str);
|
||||
return GetMD5(inputBytes, upper);
|
||||
}
|
||||
|
||||
private string GetMD5(byte[] bytes, bool upper)
|
||||
{
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] hash = md5.ComputeHash(bytes);
|
||||
string f = "x2";
|
||||
|
||||
if (upper)
|
||||
{
|
||||
f = "X2";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < hash.Length; i++)
|
||||
{
|
||||
sb.Append(hash[i].ToString(f));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string BuildFileAttrs(SendFileInfo info)
|
||||
{
|
||||
string fileMD5 = GetMD5(info.fileContent, false);
|
||||
string sign = GetMD5(fileMD5 + ":" + info.token, false);
|
||||
|
||||
if (info.rtmAttrs == null)
|
||||
info.rtmAttrs = new Dictionary<string, object>();
|
||||
|
||||
Dictionary<string, object> rtmAttrs = info.rtmAttrs;
|
||||
rtmAttrs.Add("sign", sign);
|
||||
|
||||
if (info.filename != null && info.filename.Length > 0)
|
||||
{
|
||||
rtmAttrs.Add("filename", info.filename);
|
||||
|
||||
if (info.fileExtension == null || info.fileExtension.Length == 0)
|
||||
info.fileExtension = ExtraFileExtension(info.filename);
|
||||
}
|
||||
if (info.fileExtension != null && info.fileExtension.Length > 0)
|
||||
rtmAttrs.Add("ext", info.fileExtension);
|
||||
|
||||
Dictionary<string, object> fileAttrs = new Dictionary<string, object>();
|
||||
fileAttrs.Add("rtm", rtmAttrs);
|
||||
|
||||
if (info.userAttrs == null || info.userAttrs.Length == 0)
|
||||
fileAttrs.Add("custom", "");
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> userDict = Json.ParseObject(info.userAttrs);
|
||||
if (userDict != null)
|
||||
fileAttrs.Add("custom", userDict);
|
||||
else
|
||||
fileAttrs.Add("custom", info.userAttrs);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
fileAttrs.Add("custom", info.userAttrs);
|
||||
}
|
||||
}
|
||||
|
||||
return Json.ToString(fileAttrs);
|
||||
}
|
||||
|
||||
private Quest BuildSendFileQuest(out long messageId, SendFileInfo info)
|
||||
{
|
||||
Quest quest = null;
|
||||
switch (info.actionType)
|
||||
{
|
||||
case FileTokenType.P2P:
|
||||
quest = new Quest("sendfile");
|
||||
quest.Param("to", info.xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Group:
|
||||
quest = new Quest("sendgroupfile");
|
||||
quest.Param("gid", info.xid);
|
||||
break;
|
||||
|
||||
case FileTokenType.Room:
|
||||
quest = new Quest("sendroomfile");
|
||||
quest.Param("rid", info.xid);
|
||||
break;
|
||||
case FileTokenType.Upload:
|
||||
quest = new Quest("uploadfile");
|
||||
quest.Param("uid", uid);
|
||||
break;
|
||||
}
|
||||
|
||||
quest.Param("pid", projectId);
|
||||
quest.Param("from", uid);
|
||||
quest.Param("token", info.token);
|
||||
quest.Param("mtype", info.mtype);
|
||||
messageId = info.messageId;
|
||||
if (info.messageId == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
quest.Param("mid", messageId);
|
||||
|
||||
quest.Param("file", info.fileContent);
|
||||
quest.Param("attrs", BuildFileAttrs(info));
|
||||
|
||||
return quest;
|
||||
}
|
||||
|
||||
private int SendFileWithClient(SendFileInfo info, TCPClient client)
|
||||
{
|
||||
UpdateTimeout(ref info.remainTimeout, ref info.lastActionTimestamp);
|
||||
if (info.remainTimeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
long messageId = 0;
|
||||
Quest quest = BuildSendFileQuest(out messageId, info);
|
||||
bool success = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (info.callbackMtime == null)
|
||||
info.callback(messageId, fpnn.ErrorCode.FPNN_EC_OK);
|
||||
else
|
||||
{
|
||||
long mtime = answer.Want<long>("mtime");
|
||||
info.callbackMtime(messageId, mtime, fpnn.ErrorCode.FPNN_EC_OK);
|
||||
}
|
||||
|
||||
RTMControlCenter.ActiveFileGateClient(info.endpoint, client);
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.callbackMtime == null)
|
||||
info.callback(0, errorCode);
|
||||
else
|
||||
info.callbackMtime(0, 0, errorCode);
|
||||
}, info.remainTimeout);
|
||||
|
||||
if (success)
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
else
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
private int UploadFileWithClient(SendFileInfo info, TCPClient client)
|
||||
{
|
||||
UpdateTimeout(ref info.remainTimeout, ref info.lastActionTimestamp);
|
||||
if (info.remainTimeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
long messageId = 0;
|
||||
Quest quest = BuildSendFileQuest(out messageId, info);
|
||||
bool success = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = answer.Want<string>("url");
|
||||
uint size = answer.Want<uint>("size");
|
||||
info.uploadCallback(url, size, fpnn.ErrorCode.FPNN_EC_OK);
|
||||
|
||||
RTMControlCenter.ActiveFileGateClient(info.endpoint, client);
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
info.uploadCallback(null, 0, errorCode);
|
||||
}, info.remainTimeout);
|
||||
|
||||
if (success)
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
else
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
private int SendFileWithoutClient(SendFileInfo info, bool originalEndpoint)
|
||||
{
|
||||
string fileGateEndpoint;
|
||||
if (originalEndpoint)
|
||||
fileGateEndpoint = info.endpoint;
|
||||
else
|
||||
{
|
||||
if (ConvertIPv4EndpointToIPv6IPPort(info.endpoint, out string ipv6, out int port))
|
||||
{
|
||||
fileGateEndpoint = ipv6 + ":" + port;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
|
||||
TCPClient client = TCPClient.Create(fileGateEndpoint, true);
|
||||
if (errorRecorder != null)
|
||||
client.SetErrorRecorder(errorRecorder);
|
||||
|
||||
client.SetConnectionConnectedDelegate((Int64 connectionId, string endpoint, bool connected) => {
|
||||
int errorCode = fpnn.ErrorCode.FPNN_EC_OK;
|
||||
|
||||
if (connected)
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(info.endpoint, client);
|
||||
errorCode = SendFileWithClient(info, client);
|
||||
}
|
||||
else if (originalEndpoint)
|
||||
{
|
||||
errorCode = SendFileWithoutClient(info, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
if (errorCode != fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
if (info.callbackMtime == null)
|
||||
info.callback(0, errorCode);
|
||||
else
|
||||
info.callbackMtime(0, 0, errorCode);
|
||||
}
|
||||
|
||||
if (connected)
|
||||
client.SetConnectionConnectedDelegate(null);
|
||||
});
|
||||
|
||||
client.AsyncConnect();
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private int UploadFileWithoutClient(SendFileInfo info, bool originalEndpoint)
|
||||
{
|
||||
string fileGateEndpoint;
|
||||
if (originalEndpoint)
|
||||
fileGateEndpoint = info.endpoint;
|
||||
else
|
||||
{
|
||||
if (ConvertIPv4EndpointToIPv6IPPort(info.endpoint, out string ipv6, out int port))
|
||||
{
|
||||
fileGateEndpoint = ipv6 + ":" + port;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
|
||||
TCPClient client = TCPClient.Create(fileGateEndpoint, true);
|
||||
if (errorRecorder != null)
|
||||
client.SetErrorRecorder(errorRecorder);
|
||||
|
||||
client.SetConnectionConnectedDelegate((Int64 connectionId, string endpoint, bool connected) => {
|
||||
int errorCode = fpnn.ErrorCode.FPNN_EC_OK;
|
||||
|
||||
if (connected)
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(info.endpoint, client);
|
||||
errorCode = UploadFileWithClient(info, client);
|
||||
}
|
||||
else if (originalEndpoint)
|
||||
{
|
||||
errorCode = UploadFileWithoutClient(info, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
if (errorCode != fpnn.ErrorCode.FPNN_EC_OK)
|
||||
info.uploadCallback(null, 0, errorCode);
|
||||
|
||||
if (connected)
|
||||
client.SetConnectionConnectedDelegate(null);
|
||||
});
|
||||
|
||||
client.AsyncConnect();
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private void GetFileTokenCallback(SendFileInfo info, string token, string endpoint, int errorCode)
|
||||
{
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
info.token = token;
|
||||
info.endpoint = endpoint;
|
||||
|
||||
TCPClient fileClient = RTMControlCenter.FecthFileGateClient(info.endpoint);
|
||||
if (fileClient != null)
|
||||
errorCode = SendFileWithClient(info, fileClient);
|
||||
else
|
||||
errorCode = SendFileWithoutClient(info, true);
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.callbackMtime == null)
|
||||
info.callback(0, errorCode);
|
||||
else
|
||||
info.callbackMtime(0, 0, errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetFileTokenUploadCallback(SendFileInfo info, string token, string endpoint, int errorCode)
|
||||
{
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
info.token = token;
|
||||
info.endpoint = endpoint;
|
||||
|
||||
TCPClient fileClient = RTMControlCenter.FecthFileGateClient(info.endpoint);
|
||||
if (fileClient != null)
|
||||
errorCode = UploadFileWithClient(info, fileClient);
|
||||
else
|
||||
errorCode = UploadFileWithoutClient(info, true);
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
return;
|
||||
}
|
||||
else
|
||||
info.uploadCallback(null, 0, errorCode);
|
||||
}
|
||||
|
||||
//===========================[ Real Send File ]=========================//
|
||||
private bool RealSendFile(MessageIdDelegate callback, FileTokenType tokenType, long targetId, byte mtype,
|
||||
byte[] fileContent, string filename, string fileExtension, string attrs, Dictionary<string, object> rtmAttrs, long messageId, int timeout)
|
||||
{
|
||||
if (mtype < 40 || mtype > 50)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Send file require mtype between [40, 50], current mtype is " + mtype);
|
||||
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, ErrorCode.RTM_EC_INVALID_MTYPE);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SendFileInfo info = new SendFileInfo
|
||||
{
|
||||
actionType = tokenType,
|
||||
xid = targetId,
|
||||
mtype = mtype,
|
||||
fileContent = fileContent,
|
||||
filename = filename,
|
||||
fileExtension = fileExtension,
|
||||
userAttrs = attrs,
|
||||
messageId = messageId,
|
||||
remainTimeout = timeout,
|
||||
lastActionTimestamp = ClientEngine.GetCurrentMilliseconds(),
|
||||
callback = callback
|
||||
};
|
||||
info.rtmAttrs = rtmAttrs;
|
||||
|
||||
bool asyncStarted = FileToken((string token, string endpoint, int errorCode) => {
|
||||
GetFileTokenCallback(info, token, endpoint, errorCode);
|
||||
}, tokenType, info.xid, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool RealSendFile(SendMessageDelegate callback, FileTokenType tokenType, long targetId, byte mtype,
|
||||
byte[] fileContent, string filename, string fileExtension, string attrs, Dictionary<string, object> rtmAttrs, long messageId, int timeout)
|
||||
{
|
||||
if (mtype < 40 || mtype > 50)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Send file require mtype between [40, 50], current mtype is " + mtype);
|
||||
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, ErrorCode.RTM_EC_INVALID_MTYPE);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SendFileInfo info = new SendFileInfo
|
||||
{
|
||||
actionType = tokenType,
|
||||
xid = targetId,
|
||||
mtype = mtype,
|
||||
fileContent = fileContent,
|
||||
filename = filename,
|
||||
fileExtension = fileExtension,
|
||||
userAttrs = attrs,
|
||||
messageId = messageId,
|
||||
remainTimeout = timeout,
|
||||
lastActionTimestamp = ClientEngine.GetCurrentMilliseconds(),
|
||||
callbackMtime = callback
|
||||
};
|
||||
info.rtmAttrs = rtmAttrs;
|
||||
|
||||
bool asyncStarted = FileToken((string token, string endpoint, int errorCode) => {
|
||||
GetFileTokenCallback(info, token, endpoint, errorCode);
|
||||
}, tokenType, info.xid, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int RealSendFile(out long messageId, out long mtime, FileTokenType tokenType, long targetId, byte mtype,
|
||||
byte[] fileContent, string filename, string fileExtension, string attrs, Dictionary<string, object> rtmAttrs, long mid, int timeout)
|
||||
{
|
||||
messageId = mid;
|
||||
mtime = 0;
|
||||
|
||||
//----------[ 1. check mtype ]---------------//
|
||||
|
||||
if (mtype < 40 || mtype > 50)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Send file require mtype between [40, 50], current mtype is " + mtype);
|
||||
|
||||
return ErrorCode.RTM_EC_INVALID_MTYPE;
|
||||
}
|
||||
|
||||
//----------[ 2. Get File Token ]---------------//
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
long lastActionTimestamp = ClientEngine.GetCurrentMilliseconds();
|
||||
|
||||
int errorCode = FileToken(out string token, out string endpoint, tokenType, targetId, timeout);
|
||||
if (errorCode != fpnn.ErrorCode.FPNN_EC_OK)
|
||||
return errorCode;
|
||||
|
||||
//----------[ 2.1 check timeout ]---------------//
|
||||
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
//----------[ 3. fetch file gate client ]---------------//
|
||||
|
||||
TCPClient fileClient = RTMControlCenter.FecthFileGateClient(endpoint);
|
||||
if (fileClient == null)
|
||||
{
|
||||
fileClient = TCPClient.Create(endpoint, true);
|
||||
if (fileClient.SyncConnect())
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
//----------[ 3.1 check timeout ]---------------//
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
if (ConvertIPv4EndpointToIPv6IPPort(endpoint, out string ipv6, out int port))
|
||||
{
|
||||
fileClient = TCPClient.Create(ipv6 + ":" + port, true);
|
||||
if (fileClient.SyncConnect())
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------[ 3.2 check timeout ]---------------//
|
||||
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
//----------[ 4. build quest ]---------------//
|
||||
SendFileInfo info = new SendFileInfo
|
||||
{
|
||||
actionType = tokenType,
|
||||
xid = targetId,
|
||||
mtype = mtype,
|
||||
fileContent = fileContent,
|
||||
filename = filename,
|
||||
fileExtension = fileExtension,
|
||||
userAttrs = attrs,
|
||||
messageId = mid,
|
||||
token = token,
|
||||
};
|
||||
info.rtmAttrs = rtmAttrs;
|
||||
|
||||
Quest quest = BuildSendFileQuest(out messageId, info);
|
||||
Answer answer = fileClient.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private bool RealUploadFile(Action<string, uint, int> callback, FileTokenType tokenType, byte mtype,
|
||||
byte[] fileContent, string filename, string fileExtension, string attrs, Dictionary<string, object> rtmAttrs, int timeout)
|
||||
{
|
||||
if (mtype < 40 || mtype > 50)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Send file require mtype between [40, 50], current mtype is " + mtype);
|
||||
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, 0, ErrorCode.RTM_EC_INVALID_MTYPE);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SendFileInfo info = new SendFileInfo
|
||||
{
|
||||
actionType = tokenType,
|
||||
xid = 0,
|
||||
mtype = mtype,
|
||||
fileContent = fileContent,
|
||||
filename = filename,
|
||||
fileExtension = fileExtension,
|
||||
userAttrs = attrs,
|
||||
remainTimeout = timeout,
|
||||
lastActionTimestamp = ClientEngine.GetCurrentMilliseconds(),
|
||||
uploadCallback = callback
|
||||
};
|
||||
info.rtmAttrs = rtmAttrs;
|
||||
|
||||
bool asyncStarted = FileToken((string token, string endpoint, int errorCode) => {
|
||||
GetFileTokenUploadCallback(info, token, endpoint, errorCode);
|
||||
}, tokenType, info.xid, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int RealUploadFile(out string url, out uint size, FileTokenType tokenType, byte mtype,
|
||||
byte[] fileContent, string filename, string fileExtension, string attrs, Dictionary<string, object> rtmAttrs, int timeout)
|
||||
{
|
||||
url = null;
|
||||
size = 0;
|
||||
|
||||
//----------[ 1. check mtype ]---------------//
|
||||
|
||||
if (mtype < 40 || mtype > 50)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Send file require mtype between [40, 50], current mtype is " + mtype);
|
||||
|
||||
return ErrorCode.RTM_EC_INVALID_MTYPE;
|
||||
}
|
||||
|
||||
//----------[ 2. Get File Token ]---------------//
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
long lastActionTimestamp = ClientEngine.GetCurrentMilliseconds();
|
||||
|
||||
int errorCode = FileToken(out string token, out string endpoint, tokenType, 0, timeout);
|
||||
if (errorCode != fpnn.ErrorCode.FPNN_EC_OK)
|
||||
return errorCode;
|
||||
|
||||
//----------[ 2.1 check timeout ]---------------//
|
||||
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
//----------[ 3. fetch file gate client ]---------------//
|
||||
|
||||
TCPClient fileClient = RTMControlCenter.FecthFileGateClient(endpoint);
|
||||
if (fileClient == null)
|
||||
{
|
||||
fileClient = TCPClient.Create(endpoint, true);
|
||||
if (fileClient.SyncConnect())
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
//----------[ 3.1 check timeout ]---------------//
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
if (ConvertIPv4EndpointToIPv6IPPort(endpoint, out string ipv6, out int port))
|
||||
{
|
||||
fileClient = TCPClient.Create(ipv6 + ":" + port, true);
|
||||
if (fileClient.SyncConnect())
|
||||
{
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------[ 3.2 check timeout ]---------------//
|
||||
|
||||
UpdateTimeout(ref timeout, ref lastActionTimestamp);
|
||||
if (timeout <= 0)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_TIMEOUT;
|
||||
|
||||
//----------[ 4. build quest ]---------------//
|
||||
SendFileInfo info = new SendFileInfo
|
||||
{
|
||||
actionType = tokenType,
|
||||
xid = 0,
|
||||
mtype = mtype,
|
||||
fileContent = fileContent,
|
||||
filename = filename,
|
||||
fileExtension = fileExtension,
|
||||
userAttrs = attrs,
|
||||
token = token,
|
||||
};
|
||||
info.rtmAttrs = rtmAttrs;
|
||||
|
||||
long messageId = 0;
|
||||
Quest quest = BuildSendFileQuest(out messageId, info);
|
||||
Answer answer = fileClient.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
url = answer.Want<string>("url");
|
||||
size = answer.Want<uint>("size");
|
||||
|
||||
RTMControlCenter.ActiveFileGateClient(endpoint, fileClient);
|
||||
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
//===========================[ Send File ]=========================//
|
||||
public bool SendFile(MessageIdDelegate callback, long peerUid, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.P2P, peerUid, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendFile(out long messageId, long peerUid, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.P2P, peerUid, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendFile(SendMessageDelegate callback, long peerUid, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.P2P, peerUid, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendFile(out long messageId, out long mtime, long peerUid, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.P2P, peerUid, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
//===========================[ Sned Group File ]=========================//
|
||||
public bool SendGroupFile(MessageIdDelegate callback, long groupId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Group, groupId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendGroupFile(out long messageId, long groupId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.Group, groupId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendGroupFile(SendMessageDelegate callback, long groupId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Group, groupId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendGroupFile(out long messageId, out long mtime, long groupId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.Group, groupId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
//===========================[ Sned Room File ]=========================//
|
||||
public bool SendRoomFile(MessageIdDelegate callback, long roomId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Room, roomId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendRoomFile(out long messageId, long roomId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out _, FileTokenType.Room, roomId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public bool SendRoomFile(SendMessageDelegate callback, long roomId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(callback, FileTokenType.Room, roomId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
public int SendRoomFile(out long messageId, out long mtime, long roomId, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealSendFile(out messageId, out mtime, FileTokenType.Room, roomId, (byte)type, fileContent, filename, fileExtension, attrs, null, 0, timeout);
|
||||
}
|
||||
|
||||
//===========================[ Upload File ]=========================//
|
||||
public bool UploadFile(Action<string, uint, int> callback, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealUploadFile(callback, FileTokenType.Upload, (byte)type, fileContent, filename, fileExtension, attrs, null, timeout);
|
||||
}
|
||||
|
||||
public int UploadFile(out string url, out uint size, MessageType type, byte[] fileContent, string filename, string fileExtension = "", string attrs = "", int timeout = 120)
|
||||
{
|
||||
return RealUploadFile(out url, out size, FileTokenType.Upload, (byte)type, fileContent, filename, fileExtension, attrs, null, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f33ee6002df954ce3a69f01c981cc58c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,315 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//===========================[ Add Friends ]=========================//
|
||||
public bool AddFriends(DoneDelegate callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("addfriends");
|
||||
quest.Param("friends", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddFriends(HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("addfriends");
|
||||
quest.Param("friends", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Delete Friends ]=========================//
|
||||
public bool DeleteFriends(DoneDelegate callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("delfriends");
|
||||
quest.Param("friends", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DeleteFriends(HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("delfriends");
|
||||
quest.Param("friends", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Friends ]=========================//
|
||||
//-- Action<friend_uids, errorCode>
|
||||
public bool GetFriends(Action<HashSet<long>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getfriends");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> friends = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
friends = WantLongHashSet(answer, "uids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(friends, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetFriends(out HashSet<long> friends, int timeout = 0)
|
||||
{
|
||||
friends = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getfriends");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
friends = WantLongHashSet(answer, "uids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Add Blacklist ]=========================//
|
||||
public bool AddBlacklist(DoneDelegate callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("addblacks");
|
||||
quest.Param("blacks", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddBlacklist(HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("addblacks");
|
||||
quest.Param("blacks", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Delete Blacklist ]=========================//
|
||||
public bool DeleteBlacklist(DoneDelegate callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("delblacks");
|
||||
quest.Param("blacks", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DeleteBlacklist(HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("delblacks");
|
||||
quest.Param("blacks", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Blacklist ]=========================//
|
||||
//-- Action<uids, errorCode>
|
||||
public bool GetBlacklist(Action<HashSet<long>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getblacks");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> friends = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
friends = WantLongHashSet(answer, "uids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(friends, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetBlacklist(out HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
uids = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getblacks");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
uids = WantLongHashSet(answer, "uids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b19d83ff9c43b4bc78d49fe3b5c65073
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,807 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//===========================[ Add Group Members ]=========================//
|
||||
public bool AddGroupMembers(DoneDelegate callback, long groupId, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("addgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("uids", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddGroupMembers(long groupId, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("addgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("uids", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Delete Group Members ]=========================//
|
||||
public bool DeleteGroupMembers(DoneDelegate callback, long groupId, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("delgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("uids", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int DeleteGroupMembers(long groupId, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("delgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("uids", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Group Members ]=========================//
|
||||
//-- Action<uids, errorCode>
|
||||
public bool GetGroupMembers(Action<HashSet<long>, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> uids = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
uids = WantLongHashSet(answer, "uids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(uids, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
//-- Action<member_uids, online_uids, errorCode>
|
||||
public bool GetGroupMembers(Action<HashSet<long>, HashSet<long>, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("online", true);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> allUids = null;
|
||||
HashSet<long> onlineUids = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
allUids = WantLongHashSet(answer, "uids");
|
||||
onlineUids = GetLongHashSet(answer, "onlines");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(allUids, onlineUids, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupMembers(out HashSet<long> uids, long groupId, int timeout = 0)
|
||||
{
|
||||
uids = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
uids = WantLongHashSet(answer, "uids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetGroupMembers(out HashSet<long> allUids, out HashSet<long> onlineUids, long groupId, int timeout = 0)
|
||||
{
|
||||
allUids = null;
|
||||
onlineUids = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupmembers");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("online", true);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
allUids = WantLongHashSet(answer, "uids");
|
||||
onlineUids = GetLongHashSet(answer, "onlines");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Group Count ]=========================//
|
||||
//-- Action<member_count, errorCode>
|
||||
public bool GetGroupCount(Action<int, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupcount");
|
||||
quest.Param("gid", groupId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
int memberCount = 0;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
memberCount = answer.Want<int>("cn");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(memberCount, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
//-- Action<member_count, online_count, errorCode>
|
||||
public bool GetGroupCount(Action<int, int, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupcount");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("online", true);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
int memberCount = 0;
|
||||
int onlineCount = 0;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
memberCount = answer.Want<int>("cn");
|
||||
onlineCount = answer.Want<int>("online");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(memberCount, onlineCount, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupCount(out int memberCount, long groupId, int timeout = 0)
|
||||
{
|
||||
memberCount = 0;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupcount");
|
||||
quest.Param("gid", groupId);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
memberCount = answer.Want<int>("cn");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetGroupCount(out int memberCount, out int onlineCount, long groupId, int timeout = 0)
|
||||
{
|
||||
memberCount = 0;
|
||||
onlineCount = 0;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupcount");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("online", true);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
memberCount = answer.Want<int>("cn");
|
||||
onlineCount = answer.Want<int>("online");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get User Groups ]=========================//
|
||||
//-- Action<groupIds, errorCode>
|
||||
public bool GetUserGroups(Action<HashSet<long>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getusergroups");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> groupIds = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
groupIds = WantLongHashSet(answer, "gids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(groupIds, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetUserGroups(out HashSet<long> groupIds, int timeout = 0)
|
||||
{
|
||||
groupIds = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getusergroups");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
groupIds = WantLongHashSet(answer, "gids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Set Group Info ]=========================//
|
||||
public bool SetGroupInfo(DoneDelegate callback, long groupId, string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("setgroupinfo");
|
||||
quest.Param("gid", groupId);
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int SetGroupInfo(long groupId, string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("setgroupinfo");
|
||||
quest.Param("gid", groupId);
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Group Info ]=========================//
|
||||
//-- Action<publicInfo, privateInfo, errorCode>
|
||||
public bool GetGroupInfo(Action<string, string, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupinfo");
|
||||
quest.Param("gid", groupId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string publicInfo = "";
|
||||
string privateInfo = "";
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string>("pinfo");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfo, privateInfo, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupInfo(out string publicInfo, out string privateInfo, long groupId, int timeout = 0)
|
||||
{
|
||||
publicInfo = null;
|
||||
privateInfo = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupinfo");
|
||||
quest.Param("gid", groupId);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string>("pinfo");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Group Open Info ]=========================//
|
||||
//-- Action<public_info, errorCode>
|
||||
public bool GetGroupPublicInfo(Action<string, int> callback, long groupId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(string.Empty, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupopeninfo");
|
||||
quest.Param("gid", groupId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string publicInfo = "";
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{ publicInfo = answer.Want<string>("oinfo"); }
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfo, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(string.Empty, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetGroupPublicInfo(out string publicInfo, long groupId, int timeout = 0)
|
||||
{
|
||||
publicInfo = "";
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupopeninfo");
|
||||
quest.Param("gid", groupId);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Groups Open Info ]=========================//
|
||||
//-- Action<Dictionary<string_groupId, public_info>, errorCode>
|
||||
[System.Obsolete("GetGroupsPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public bool GetGroupsPublicInfo(Action<Dictionary<string, string>, int> callback, HashSet<long> groupIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupsopeninfo");
|
||||
quest.Param("gids", groupIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<string, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
//-- Action<Dictionary<groupId, public_info>, errorCode>
|
||||
public bool GetGroupsPublicInfo(Action<Dictionary<long, string>, int> callback, HashSet<long> groupIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getgroupsopeninfo");
|
||||
quest.Param("gids", groupIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
[System.Obsolete("GetGroupsPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public int GetGroupsPublicInfo(out Dictionary<string, string> publicInfos, HashSet<long> groupIds, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupsopeninfo");
|
||||
quest.Param("gids", groupIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetGroupsPublicInfo(out Dictionary<long, string> publicInfos, HashSet<long> groupIds, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getgroupsopeninfo");
|
||||
quest.Param("gids", groupIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 625503492ea1340aa8dc7d9fd044beb0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,706 @@
|
||||
using System;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//======================[ string message version ]================================//
|
||||
private bool InternalSendMessage(long uid, byte mtype, string message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendMessage(long uid, byte mtype, string message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendMessage(out long messageId, out long mtime, long uid, byte mtype, string message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private bool InternalSendGroupMessage(long groupId, byte mtype, string message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendGroupMessage(long groupId, byte mtype, string message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendGroupMessage(out long messageId, out long mtime, long groupId, byte mtype, string message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private bool InternalSendRoomMessage(long roomId, byte mtype, string message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendRoomMessage(long roomId, byte mtype, string message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendRoomMessage(out long messageId, out long mtime, long roomId, byte mtype, string message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
//======================[ binary message version ]================================//
|
||||
private bool InternalSendMessage(long uid, byte mtype, byte[] message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendMessage(long uid, byte mtype, byte[] message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendMessage(out long messageId, out long mtime, long uid, byte mtype, byte[] message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendmsg");
|
||||
quest.Param("to", uid);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private bool InternalSendGroupMessage(long groupId, byte mtype, byte[] message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendGroupMessage(long groupId, byte mtype, byte[] message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendGroupMessage(out long messageId, out long mtime, long groupId, byte mtype, byte[] message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendgroupmsg");
|
||||
quest.Param("gid", groupId);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
|
||||
private bool InternalSendRoomMessage(long roomId, byte mtype, byte[] message, string attrs, MessageIdDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
//long mtime = 0;
|
||||
//if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
// mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private bool InternalSendRoomMessage(long roomId, byte mtype, byte[] message, string attrs, SendMessageDelegate callback, long messageId, int timeout)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
long mid = messageId;
|
||||
if (messageId == 0)
|
||||
mid = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", mid);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
long mtime = 0;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
mtime = answer.Want<long>("mtime");
|
||||
|
||||
callback(mid, mtime, errorCode);
|
||||
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(0, 0, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
private int InternalSendRoomMessage(out long messageId, out long mtime, long roomId, byte mtype, byte[] message, string attrs, long mid, int timeout)
|
||||
{
|
||||
mtime = 0;
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
messageId = mid;
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
}
|
||||
|
||||
messageId = mid;
|
||||
if (mid == 0)
|
||||
messageId = MidGenerator.Gen();
|
||||
|
||||
Quest quest = new Quest("sendroommsg");
|
||||
quest.Param("rid", roomId);
|
||||
quest.Param("mid", messageId);
|
||||
quest.Param("mtype", mtype);
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
mtime = answer.Want<long>("mtime");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e31f3e9ee2b14cd898b34496b5f97da
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2622dc5f09afe4c3fbf6d24dda5e30b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,794 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.common;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//===========================[ Enter Room ]=========================//
|
||||
public bool EnterRoom(DoneDelegate callback, long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("enterroom");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int EnterRoom(long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("enterroom");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
public bool EnterRooms(DoneDelegate callback, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("enterrooms");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int EnterRooms(HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("enterrooms");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
//===========================[ Leave Room ]=========================//
|
||||
public bool LeaveRoom(DoneDelegate callback, long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("leaveroom");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int LeaveRoom(long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("leaveroom");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get User Rooms ]=========================//
|
||||
//-- Action<roomIds, errorCode>
|
||||
public bool GetUserRooms(Action<HashSet<long>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getuserrooms");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> roomIds = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
roomIds = WantLongHashSet(answer, "rooms");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(roomIds, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetUserRooms(out HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
roomIds = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getuserrooms");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
roomIds = WantLongHashSet(answer, "rooms");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Set Room Info ]=========================//
|
||||
public bool SetRoomInfo(DoneDelegate callback, long roomId, string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("setroominfo");
|
||||
quest.Param("rid", roomId);
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int SetRoomInfo(long roomId, string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("setroominfo");
|
||||
quest.Param("rid", roomId);
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Room Info ]=========================//
|
||||
//-- Action<publicInfo, privateInfo, errorCode>
|
||||
public bool GetRoomInfo(Action<string, string, int> callback, long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback("", "", fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroominfo");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string publicInfo = "";
|
||||
string privateInfo = "";
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string>("pinfo");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfo, privateInfo, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback("", "", fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetRoomInfo(out string publicInfo, out string privateInfo, long roomId, int timeout = 0)
|
||||
{
|
||||
publicInfo = null;
|
||||
privateInfo = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroominfo");
|
||||
quest.Param("rid", roomId);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string>("pinfo");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Room Open Info ]=========================//
|
||||
//-- Action<public_info, errorCode>
|
||||
public bool GetRoomPublicInfo(Action<string, int> callback, long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback("", fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroomopeninfo");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string publicInfo = "";
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{ publicInfo = answer.Want<string>("oinfo"); }
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfo, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback("", fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetRoomPublicInfo(out string publicInfo, long roomId, int timeout = 0)
|
||||
{
|
||||
publicInfo = "";
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroomopeninfo");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Rooms Open Info ]=========================//
|
||||
//-- Action<Dictionary<string_roomId, public_info>, errorCode>
|
||||
[System.Obsolete("GetRoomsPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public bool GetRoomsPublicInfo(Action<Dictionary<string, string>, int> callback, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroomsopeninfo");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<string, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
//-- Action<Dictionary<roomId, public_info>, errorCode>
|
||||
public bool GetRoomsPublicInfo(Action<Dictionary<long, string>, int> callback, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroomsopeninfo");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
[System.Obsolete("GetRoomsPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public int GetRoomsPublicInfo(out Dictionary<string, string> publicInfos, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroomsopeninfo");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetRoomsPublicInfo(out Dictionary<long, string> publicInfos, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroomsopeninfo");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Room Members ]=========================//
|
||||
//-- Action<HashSet<uids>, errorCode>
|
||||
public bool GetRoomMembers(Action<HashSet<long>, int> callback, long roomId, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroommembers");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> uids = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
uids = WantLongHashSet(answer, "uids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(uids, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetRoomMembers(out HashSet<long> uids, long roomId, int timeout = 0)
|
||||
{
|
||||
uids = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroommembers");
|
||||
quest.Param("rid", roomId);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
uids = WantLongHashSet(answer, "uids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get Room Count ]=========================//
|
||||
//-- Action<Dictionary<roomId, count>, errorCode>
|
||||
public bool GetRoomMemberCount(Action<Dictionary<long, int>, int> callback, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getroomcount");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, int> counts = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
counts = WantLongIntDictionary(answer, "cn");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(counts, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetRoomMemberCount(out Dictionary<long, int> counts, HashSet<long> roomIds, int timeout = 0)
|
||||
{
|
||||
counts = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getroomcount");
|
||||
quest.Param("rids", roomIds);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
counts = WantLongIntDictionary(answer, "cn");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get User Room Last Message ]=========================//
|
||||
void GetRoomLastMessage(ref Dictionary<long, HistoryMessage> roomMessages, Answer answer)
|
||||
{
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)answer.Want("rooms");
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
{
|
||||
long roomId = (long)Convert.ChangeType(kvp.Key, TypeCode.Int64);
|
||||
List<object> items = (List<object>)kvp.Value;
|
||||
|
||||
HistoryMessage message = new HistoryMessage();
|
||||
message.cursorId = (long)Convert.ChangeType(items[0], TypeCode.Int64);
|
||||
message.fromUid = (long)Convert.ChangeType(items[1], TypeCode.Int64);
|
||||
message.toId = roomId;
|
||||
message.messageType = (byte)Convert.ChangeType(items[2], TypeCode.Byte);
|
||||
message.messageId = (long)Convert.ChangeType(items[3], TypeCode.Int64);
|
||||
|
||||
if (!CheckBinaryType(items[5]))
|
||||
message.stringMessage = (string)Convert.ChangeType(items[5], TypeCode.String);
|
||||
else
|
||||
message.binaryMessage = (byte[])items[5];
|
||||
|
||||
message.attrs = (string)Convert.ChangeType(items[6], TypeCode.String);
|
||||
message.modifiedTime = (long)Convert.ChangeType(items[7], TypeCode.Int64);
|
||||
|
||||
if (message.messageType >= 40 && message.messageType <= 50)
|
||||
RTMClient.BuildFileInfo(message, errorRecorder);
|
||||
|
||||
roomMessages.Add(roomId, message);
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetUserRoomLastMessage(Action<Dictionary<long, HistoryMessage>, int> callback, HashSet<long> mtypes = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getuserroomsandlastmsg");
|
||||
if (mtypes != null)
|
||||
quest.Param("mtypes", mtypes);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, HistoryMessage> roomMessages = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
roomMessages = new Dictionary<long, HistoryMessage>();
|
||||
GetRoomLastMessage(ref roomMessages, answer);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(roomMessages, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetUserRoomLastMessage(out Dictionary<long, HistoryMessage> roomMessages, HashSet<long> mtypes = null, int timeout = 0)
|
||||
{
|
||||
roomMessages = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getuserroomsandlastmsg");
|
||||
if (mtypes != null)
|
||||
quest.Param("mtypes", mtypes);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
roomMessages = new Dictionary<long, HistoryMessage>();
|
||||
GetRoomLastMessage(ref roomMessages, answer); ;
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d13c3df96419848328a7e475f4c5c273
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,562 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
public void Bye(bool async = true)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (autoReloginInfo != null)
|
||||
autoReloginInfo.Disable();
|
||||
}
|
||||
|
||||
Quest quest = new Quest("bye");
|
||||
if (async)
|
||||
{
|
||||
bool success = client.SendQuest(quest, (Answer answer, int errorCode) => { Close(); });
|
||||
if (!success)
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
client.SendQuest(quest);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Add Attributes ]=========================//
|
||||
public bool AddAttributes(DoneDelegate callback, Dictionary<string, string> attrs, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("addattrs");
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddAttributes(Dictionary<string, string> attrs, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("addattrs");
|
||||
quest.Param("attrs", attrs);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Attributes ]=========================//
|
||||
//-- Action<attributes, errorCode>
|
||||
public bool GetAttributes(Action<Dictionary<string, string>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getattrs");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<string, string> result = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = WantStringDictionary(answer, "attrs");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(result, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetAttributes(out Dictionary<string, string> attributes, int timeout = 0)
|
||||
{
|
||||
attributes = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getattrs");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
attributes = WantStringDictionary(answer, "attrs");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Add Debug Log ]=========================//
|
||||
public bool AddDebugLog(DoneDelegate callback, string message, string attrs, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("adddebuglog");
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddDebugLog(string message, string attrs, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("adddebuglog");
|
||||
quest.Param("msg", message);
|
||||
quest.Param("attrs", attrs);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Add Device ]=========================//
|
||||
public bool AddDevice(DoneDelegate callback, string appType, string deviceToken, string tag = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("adddevice");
|
||||
quest.Param("apptype", appType);
|
||||
quest.Param("devicetoken", deviceToken);
|
||||
if (tag != null)
|
||||
quest.Param("tag", tag);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddDevice(string appType, string deviceToken, string tag = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("adddevice");
|
||||
quest.Param("apptype", appType);
|
||||
quest.Param("devicetoken", deviceToken);
|
||||
if (tag != null)
|
||||
quest.Param("tag", tag);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Remove Device ]=========================//
|
||||
public bool RemoveDevice(DoneDelegate callback, string deviceToken, string tag = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("removedevice");
|
||||
quest.Param("devicetoken", deviceToken);
|
||||
if (tag != null)
|
||||
quest.Param("tag", tag);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int RemoveDevice(string deviceToken, string tag = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("removedevice");
|
||||
quest.Param("devicetoken", deviceToken);
|
||||
if (tag != null)
|
||||
quest.Param("tag", tag);
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Add Device Push Option ]=========================//
|
||||
public bool AddDevicePushOption(DoneDelegate callback, MessageCategory messageCategory, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
byte type = 99;
|
||||
switch (messageCategory)
|
||||
{
|
||||
case MessageCategory.P2PMessage:
|
||||
type = 0; break;
|
||||
case MessageCategory.GroupMessage:
|
||||
type = 1; break;
|
||||
}
|
||||
|
||||
return AddDevicePushOption(callback, type, targetId, mTypes, timeout);
|
||||
}
|
||||
|
||||
internal bool AddDevicePushOption(DoneDelegate callback, byte type, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
if (type > 1)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(ErrorCode.RTM_EC_INVALID_PARAMETER);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("addoption");
|
||||
quest.Param("type", type);
|
||||
quest.Param("xid", targetId);
|
||||
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int AddDevicePushOption(MessageCategory messageCategory, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
byte type = 99;
|
||||
switch (messageCategory)
|
||||
{
|
||||
case MessageCategory.P2PMessage:
|
||||
type = 0; break;
|
||||
case MessageCategory.GroupMessage:
|
||||
type = 1; break;
|
||||
}
|
||||
|
||||
return AddDevicePushOption(type, targetId, mTypes, timeout);
|
||||
}
|
||||
|
||||
internal int AddDevicePushOption(byte type, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
if (type > 1)
|
||||
return ErrorCode.RTM_EC_INVALID_PARAMETER;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("addoption");
|
||||
quest.Param("type", type);
|
||||
quest.Param("xid", targetId);
|
||||
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Remove Device Push Option ]=========================//
|
||||
public bool RemoveDevicePushOption(DoneDelegate callback, MessageCategory messageCategory, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
byte type = 99;
|
||||
switch (messageCategory)
|
||||
{
|
||||
case MessageCategory.P2PMessage:
|
||||
type = 0; break;
|
||||
case MessageCategory.GroupMessage:
|
||||
type = 1; break;
|
||||
}
|
||||
|
||||
return RemoveDevicePushOption(callback, type, targetId, mTypes, timeout);
|
||||
}
|
||||
|
||||
internal bool RemoveDevicePushOption(DoneDelegate callback, byte type, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
if (type > 1)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(ErrorCode.RTM_EC_INVALID_PARAMETER);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("removeoption");
|
||||
quest.Param("type", type);
|
||||
quest.Param("xid", targetId);
|
||||
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int RemoveDevicePushOption(MessageCategory messageCategory, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
byte type = 99;
|
||||
switch (messageCategory)
|
||||
{
|
||||
case MessageCategory.P2PMessage:
|
||||
type = 0; break;
|
||||
case MessageCategory.GroupMessage:
|
||||
type = 1; break;
|
||||
}
|
||||
|
||||
return RemoveDevicePushOption(type, targetId, mTypes, timeout);
|
||||
}
|
||||
|
||||
internal int RemoveDevicePushOption(byte type, long targetId, HashSet<byte> mTypes = null, int timeout = 0)
|
||||
{
|
||||
if (type > 1)
|
||||
return ErrorCode.RTM_EC_INVALID_PARAMETER;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("removeoption");
|
||||
quest.Param("type", type);
|
||||
quest.Param("xid", targetId);
|
||||
|
||||
if (mTypes != null)
|
||||
quest.Param("mtypes", mTypes);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get Device Push Option ]=========================//
|
||||
//-- Utilities functions
|
||||
private Dictionary<long, HashSet<byte>> WantLongByteHashSetDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary <long, HashSet<byte>> rev = new Dictionary<long, HashSet<byte>>();
|
||||
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)message.Want(key);
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
{
|
||||
List<object> originalList = (List<object>)(kvp.Value);
|
||||
HashSet<byte> resultSet = new HashSet<byte>();
|
||||
|
||||
foreach (object obj in originalList)
|
||||
{
|
||||
resultSet.Add((byte)Convert.ChangeType(obj, TypeCode.Byte));
|
||||
}
|
||||
|
||||
rev.Add((long)Convert.ChangeType(kvp.Key, TypeCode.Int64), resultSet);
|
||||
}
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
//-- Action<Dictionary<p2p_uid,HashSet<mType>>, Dictionary<groupId, HashSet<mType>>, errorCode>
|
||||
public bool GetDevicePushOption(Action<Dictionary<long, HashSet<byte>>, Dictionary<long, HashSet<byte>>, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getoption");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, HashSet<byte>> p2pDictionary = null;
|
||||
Dictionary<long, HashSet<byte>> groupDictionary = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
p2pDictionary = WantLongByteHashSetDictionary(answer, "p2p");
|
||||
groupDictionary = WantLongByteHashSetDictionary(answer, "group");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(p2pDictionary, groupDictionary, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetDevicePushOption(out Dictionary<long, HashSet<byte>> p2pDictionary, out Dictionary<long, HashSet<byte>> groupDictionary, int timeout = 0)
|
||||
{
|
||||
p2pDictionary = null;
|
||||
groupDictionary = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getoption");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
p2pDictionary = WantLongByteHashSetDictionary(answer, "p2p");
|
||||
groupDictionary = WantLongByteHashSetDictionary(answer, "group");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3687230688d70456b9134a3bcfabed46
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
using com.fpnn.common;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
public static string GetTranslatedLanguage(TranslateLanguage language)
|
||||
{
|
||||
if (language == TranslateLanguage.None)
|
||||
return "";
|
||||
|
||||
if (language == TranslateLanguage.zh_cn)
|
||||
return "zh-CN";
|
||||
|
||||
if (language == TranslateLanguage.zh_tw)
|
||||
return "zh-TW";
|
||||
|
||||
return language.ToString("G");
|
||||
}
|
||||
|
||||
public static HashSet<long> WantLongHashSet(Message message, string key)
|
||||
{
|
||||
HashSet<long> rev = new HashSet<long>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Want(key);
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((long)Convert.ChangeType(obj, TypeCode.Int64));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static HashSet<long> GetLongHashSet(Message message, string key)
|
||||
{
|
||||
HashSet<long> rev = new HashSet<long>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
|
||||
if (originalList != null)
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((long)Convert.ChangeType(obj, TypeCode.Int64));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static List<long> WantLongList(Message message, string key)
|
||||
{
|
||||
List<long> rev = new List<long>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Want(key);
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((long)Convert.ChangeType(obj, TypeCode.Int64));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static List<long> GetLongList(Message message, string key)
|
||||
{
|
||||
List<long> rev = new List<long>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
if (originalList == null)
|
||||
return null;
|
||||
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((long)Convert.ChangeType(obj, TypeCode.Int64));
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static List<List<long>> GetLongListList(Message message, string key)
|
||||
{
|
||||
List<List<long>> rev = new List<List<long>>();
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
if (originalList == null)
|
||||
return null;
|
||||
|
||||
foreach (object obj in originalList)
|
||||
{
|
||||
if (obj == null)
|
||||
continue;
|
||||
List<long> list = new List<long>();
|
||||
List<object> listObject = (List<object>)obj;
|
||||
foreach (var val in listObject)
|
||||
list.Add((long)Convert.ChangeType(val, TypeCode.Int64));
|
||||
|
||||
rev.Add(list);
|
||||
}
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static List<int> GetIntList(Message message, string key)
|
||||
{
|
||||
List<int> rev = new List<int>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
if (originalList == null)
|
||||
return null;
|
||||
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((int)Convert.ChangeType(obj, TypeCode.Int32));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private static List<bool> GetBoolList(Message message, string key)
|
||||
{
|
||||
List<bool> rev = new List<bool>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
if (originalList == null)
|
||||
return null;
|
||||
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((bool)Convert.ChangeType(obj, TypeCode.Boolean));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private List<string> GetStringList(Message message, string key)
|
||||
{
|
||||
List<string> rev = new List<string>();
|
||||
|
||||
List<object> originalList = (List<object>)message.Get(key);
|
||||
if (originalList == null)
|
||||
return null;
|
||||
|
||||
foreach (object obj in originalList)
|
||||
rev.Add((string)Convert.ChangeType(obj, TypeCode.String));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private Dictionary<string, Dictionary<string, string>> GetStringStringDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary<string, Dictionary<string, string>> rev = new Dictionary<string, Dictionary<string, string>>();
|
||||
|
||||
Dictionary<object, Dictionary<object, object>> originalDict = (Dictionary<object, Dictionary<object, object>>)message.Want(key);
|
||||
foreach (var kvp in originalDict)
|
||||
{
|
||||
Dictionary<string, string> subDict = new Dictionary<string, string>();
|
||||
foreach(var kvp2 in kvp.Value)
|
||||
subDict.Add((string)Convert.ChangeType(kvp2.Key, TypeCode.String), (string)Convert.ChangeType(kvp2.Value, TypeCode.String));
|
||||
rev.Add((string)Convert.ChangeType(kvp.Key, TypeCode.String), subDict);
|
||||
}
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> WantStringDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary<string, string> rev = new Dictionary<string, string>();
|
||||
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)message.Want(key);
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
rev.Add((string)Convert.ChangeType(kvp.Key, TypeCode.String), (string)Convert.ChangeType(kvp.Value, TypeCode.String));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private Dictionary<long, string> WantLongStringDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary<long, string> rev = new Dictionary<long, string>();
|
||||
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)message.Want(key);
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
rev.Add((long)Convert.ChangeType(kvp.Key, TypeCode.Int64), (string)Convert.ChangeType(kvp.Value, TypeCode.String));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private Dictionary<long, int> WantLongIntDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary<long, int> rev = new Dictionary<long, int>();
|
||||
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)message.Want(key);
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
rev.Add((long)Convert.ChangeType(kvp.Key, TypeCode.Int64), (int)Convert.ChangeType(kvp.Value, TypeCode.Int32));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private Dictionary<long, long> WantLongLongDictionary(Message message, string key)
|
||||
{
|
||||
Dictionary<long, long> rev = new Dictionary<long, long>();
|
||||
|
||||
Dictionary<object, object> originalDict = (Dictionary<object, object>)message.Want(key);
|
||||
foreach (KeyValuePair<object, object> kvp in originalDict)
|
||||
rev.Add((long)Convert.ChangeType(kvp.Key, TypeCode.Int64), (long)Convert.ChangeType(kvp.Value, TypeCode.Int64));
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
private List<Dictionary<string, string>> GetListStringDictionary(Message message, string key)
|
||||
{
|
||||
List<Dictionary<string, string>> rev = new List<Dictionary<string, string>>();
|
||||
|
||||
List<Dictionary<object, object>> originalList = (List<Dictionary<object, object>>)message.Get(key);
|
||||
foreach (var value in originalList)
|
||||
{
|
||||
Dictionary<string, string> dict = new Dictionary<string, string>();
|
||||
foreach (var kv in value)
|
||||
dict.Add((string)Convert.ChangeType(kv.Key, TypeCode.String), (string)Convert.ChangeType(kv.Value, TypeCode.String));
|
||||
rev.Add(dict);
|
||||
}
|
||||
return rev;
|
||||
}
|
||||
|
||||
internal static void ParseFileMessage(BaseMessage baseMessage, ErrorRecorder errorRecorder)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> infoDict = Json.ParseObject(baseMessage.stringMessage);
|
||||
if (infoDict != null)
|
||||
{
|
||||
if (infoDict.TryGetValue("url", out object urlText))
|
||||
baseMessage.fileInfo.url = (string)urlText;
|
||||
|
||||
if (infoDict.TryGetValue("size", out object sizeInt))
|
||||
baseMessage.fileInfo.size = (Int32)Convert.ChangeType(sizeInt, TypeCode.Int32);
|
||||
|
||||
if (baseMessage.messageType == (byte)MessageType.ImageFile)
|
||||
{
|
||||
if (infoDict.TryGetValue("surl", out object surlText))
|
||||
baseMessage.fileInfo.surl = (string)surlText;
|
||||
}
|
||||
|
||||
baseMessage.stringMessage = null;
|
||||
}
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Parse file msg error. Full msg: " + baseMessage.stringMessage, e);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ParseFileAttrs(BaseMessage baseMessage, ErrorRecorder errorRecorder)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> attrsDict = Json.ParseObject(baseMessage.attrs);
|
||||
if (attrsDict != null)
|
||||
{
|
||||
if (attrsDict.TryGetValue("rtm", out object rtmAttrs))
|
||||
{
|
||||
Dictionary<string, object> rtmAttrsDict = (Dictionary<string, object>)rtmAttrs;
|
||||
if (rtmAttrsDict.TryGetValue("type", out object typeText))
|
||||
{
|
||||
string typeStr = (string)typeText;
|
||||
if (typeStr.Equals("audiomsg"))
|
||||
baseMessage.fileInfo.isRTMAudio = true;
|
||||
}
|
||||
|
||||
if (baseMessage.fileInfo.isRTMAudio)
|
||||
{
|
||||
if (rtmAttrsDict.TryGetValue("lang", out object languageText))
|
||||
baseMessage.fileInfo.language = (string)languageText;
|
||||
|
||||
if (rtmAttrsDict.TryGetValue("duration", out object durationInt))
|
||||
baseMessage.fileInfo.duration = (Int32)Convert.ChangeType(durationInt, TypeCode.Int32);
|
||||
}
|
||||
}
|
||||
|
||||
if (attrsDict.TryGetValue("custom", out object attrsInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> userAttrsDict = (Dictionary<string, object>)attrsInfo;
|
||||
baseMessage.attrs = Json.ToString(userAttrsDict);
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
string userAttrs = (string)attrsInfo;
|
||||
baseMessage.attrs = userAttrs;
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Convert user attrs to string type for file attrs error. Full attrs: " + baseMessage.attrs, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("Parse file attrs error. Full attrs: " + baseMessage.attrs, e);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void BuildFileInfo(BaseMessage baseMessage, ErrorRecorder errorRecorder)
|
||||
{
|
||||
baseMessage.fileInfo = new FileInfo();
|
||||
ParseFileMessage(baseMessage, errorRecorder);
|
||||
ParseFileAttrs(baseMessage, errorRecorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31055209098fa4d01a29a37a2ba0e6f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public partial class RTMClient
|
||||
{
|
||||
//===========================[ Get Online Users ]=========================//
|
||||
//-- Action<online_uids, errorCode>
|
||||
public bool GetOnlineUsers(Action<HashSet<long>, int> callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getonlineusers");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
HashSet<long> onlineUids = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
onlineUids = WantLongHashSet(answer, "uids");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(onlineUids, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetOnlineUsers(out HashSet<long> onlineUids, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
onlineUids = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getonlineusers");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
onlineUids = WantLongHashSet(answer, "uids");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Set User Info ]=========================//
|
||||
public bool SetUserInfo(DoneDelegate callback, string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("setuserinfo");
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => { callback(errorCode); }, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int SetUserInfo(string publicInfo = null, string privateInfo = null, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("setuserinfo");
|
||||
if (publicInfo != null)
|
||||
quest.Param("oinfo", publicInfo);
|
||||
if (privateInfo != null)
|
||||
quest.Param("pinfo", privateInfo);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
return answer.ErrorCode();
|
||||
}
|
||||
|
||||
//===========================[ Get User Info ]=========================//
|
||||
//-- Action<publicInfo, privateInfo, errorCode>
|
||||
public bool GetUserInfo(Action<string, string, int> callback, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getuserinfo");
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
string publicInfo = null;
|
||||
string privateInfo = null;
|
||||
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string> ("pinfo");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfo, privateInfo, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
public int GetUserInfo(out string publicInfo, out string privateInfo, int timeout = 0)
|
||||
{
|
||||
publicInfo = null;
|
||||
privateInfo = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getuserinfo");
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfo = answer.Want<string>("oinfo");
|
||||
privateInfo = answer.Want<string>("pinfo");
|
||||
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Get User Open Info ]=========================//
|
||||
//-- Action<Dictionary<string_uid, public_info>, errorCode>
|
||||
[System.Obsolete("GetUserPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public bool GetUserPublicInfo(Action<Dictionary<string, string>, int> callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getuseropeninfo");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<string, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
//-- Action<Dictionary<uid, public_info>, errorCode>
|
||||
public bool GetUserPublicInfo(Action<Dictionary<long, string>, int> callback, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
{
|
||||
if (RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Quest quest = new Quest("getuseropeninfo");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
bool asyncStarted = client.SendQuest(quest, (Answer answer, int errorCode) => {
|
||||
|
||||
Dictionary<long, string> publicInfos = null;
|
||||
if (errorCode == fpnn.ErrorCode.FPNN_EC_OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorCode = fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
callback(publicInfos, errorCode);
|
||||
}, timeout);
|
||||
|
||||
if (!asyncStarted && RTMConfig.triggerCallbackIfAsyncMethodReturnFalse)
|
||||
ClientEngine.RunTask(() =>
|
||||
{
|
||||
callback(null, fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION);
|
||||
});
|
||||
|
||||
return asyncStarted;
|
||||
}
|
||||
|
||||
[System.Obsolete("GetUserPublicInfo() with dictionary in string key type is deprecated, please using the overloaded function with dictionary in long key type instead.")]
|
||||
public int GetUserPublicInfo(out Dictionary<string, string> publicInfos, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getuseropeninfo");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
|
||||
public int GetUserPublicInfo(out Dictionary<long, string> publicInfos, HashSet<long> uids, int timeout = 0)
|
||||
{
|
||||
publicInfos = null;
|
||||
|
||||
TCPClient client = GetCoreClient();
|
||||
if (client == null)
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_CONNECTION;
|
||||
|
||||
Quest quest = new Quest("getuseropeninfo");
|
||||
quest.Param("uids", uids);
|
||||
|
||||
Answer answer = client.SendQuest(quest, timeout);
|
||||
if (answer.IsException())
|
||||
return answer.ErrorCode();
|
||||
|
||||
try
|
||||
{
|
||||
publicInfos = WantLongStringDictionary(answer, "info");
|
||||
return fpnn.ErrorCode.FPNN_EC_OK;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return fpnn.ErrorCode.FPNN_EC_CORE_INVALID_PACKAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7562b11f9e2a64037a65479e77af641e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class RegressiveStrategy
|
||||
{
|
||||
public int maxIntervalSeconds = 8; //-- 退行性重连最大时间间隔
|
||||
public int linearRegressiveCount = 4; //-- 从第一次退行性连接开始,到最大链接时间,允许尝试几次连接,每次时间间隔都会增大
|
||||
public int maxRegressvieCount = 10; //-- 退行性重连最大次数,超出该次数则不再进行重连
|
||||
}
|
||||
|
||||
public class RTMConfig
|
||||
{
|
||||
public static readonly string SDKVersion = "2.7.20";
|
||||
public static readonly string InterfaceVersion = "2.7.3";
|
||||
public static readonly string RTMGameObjectName = "RTM_GAMEOBJECT";
|
||||
|
||||
internal static int lostConnectionAfterLastPingInSeconds = 60;
|
||||
internal static int globalConnectTimeoutSeconds = 30;
|
||||
internal static int globalQuestTimeoutSeconds = 30;
|
||||
internal static int fileGateClientHoldingSeconds = 150;
|
||||
internal static common.ErrorRecorder errorRecorder = null;
|
||||
internal static bool triggerCallbackIfAsyncMethodReturnFalse = false;
|
||||
internal static RegressiveStrategy globalRegressiveStrategy = new RegressiveStrategy();
|
||||
|
||||
public int maxPingInterval;
|
||||
public int globalConnectTimeout;
|
||||
public int globalQuestTimeout;
|
||||
public int fileClientHoldingSeconds;
|
||||
public common.ErrorRecorder defaultErrorRecorder;
|
||||
public bool forceTriggerCallbackWhenAsyncMethodReturnFalse;
|
||||
public long adminID;
|
||||
public RegressiveStrategy regressiveStrategy;
|
||||
|
||||
public RTMConfig()
|
||||
{
|
||||
maxPingInterval = 60;
|
||||
globalConnectTimeout = 30;
|
||||
globalQuestTimeout = 30;
|
||||
fileClientHoldingSeconds = 150;
|
||||
forceTriggerCallbackWhenAsyncMethodReturnFalse = false;
|
||||
adminID = 111;
|
||||
|
||||
regressiveStrategy = new RegressiveStrategy();
|
||||
}
|
||||
|
||||
internal static void Config(RTMConfig config)
|
||||
{
|
||||
lostConnectionAfterLastPingInSeconds = config.maxPingInterval;
|
||||
globalConnectTimeoutSeconds = config.globalConnectTimeout;
|
||||
globalQuestTimeoutSeconds = config.globalQuestTimeout;
|
||||
fileGateClientHoldingSeconds = config.fileClientHoldingSeconds;
|
||||
errorRecorder = config.defaultErrorRecorder;
|
||||
triggerCallbackIfAsyncMethodReturnFalse = config.forceTriggerCallbackWhenAsyncMethodReturnFalse;
|
||||
|
||||
globalRegressiveStrategy = config.regressiveStrategy;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TranslateLanguage
|
||||
{
|
||||
ar, //阿拉伯语
|
||||
nl, //荷兰语
|
||||
en, //英语
|
||||
fr, //法语
|
||||
de, //德语
|
||||
el, //希腊语
|
||||
id, //印度尼西亚语
|
||||
it, //意大利语
|
||||
ja, //日语
|
||||
ko, //韩语
|
||||
no, //挪威语
|
||||
pl, //波兰语
|
||||
pt, //葡萄牙语
|
||||
ru, //俄语
|
||||
es, //西班牙语
|
||||
sv, //瑞典语
|
||||
tl, //塔加路语(菲律宾语)
|
||||
th, //泰语
|
||||
tr, //土耳其语
|
||||
vi, //越南语
|
||||
zh_cn, //中文(简体)
|
||||
zh_tw, //中文(繁体)
|
||||
None
|
||||
}
|
||||
|
||||
public enum MessageType : byte
|
||||
{
|
||||
Withdraw = 1,
|
||||
GEO = 2,
|
||||
SystemNotification = 6,
|
||||
MultiLogin = 7,
|
||||
Chat = 30,
|
||||
Cmd = 32,
|
||||
RealAudio = 35,
|
||||
RealVideo = 36,
|
||||
ImageFile = 40,
|
||||
AudioFile = 41,
|
||||
VideoFile = 42,
|
||||
VoiceFile = 43,
|
||||
NormalFile = 50
|
||||
}
|
||||
|
||||
public enum MessageCategory : byte
|
||||
{
|
||||
P2PMessage = 1,
|
||||
GroupMessage = 2,
|
||||
RoomMessage = 3,
|
||||
BroadcastMessage = 4
|
||||
}
|
||||
|
||||
public enum IMLIB_MessageType
|
||||
{
|
||||
AddFriendApply = 1,
|
||||
RefuseFriendApply = 2,
|
||||
EnterGroupApply = 3,
|
||||
RefuseEnterGroupApply = 4,
|
||||
InvitedIntoGroup = 5,
|
||||
RefuseInvitedIntoGroup = 7,
|
||||
FriendChanged = 15,
|
||||
GroupChanged = 17,
|
||||
GroupMemberChanged = 19,
|
||||
RoomMemberChanged = 20,
|
||||
AcceptFriendApply = 21,
|
||||
AcceptEnterGroupApply = 22,
|
||||
AcceptInvitedIntoGroup = 24,
|
||||
AddGroupManagers = 26,
|
||||
RemoveGroupManagers = 27,
|
||||
GroupOwnerChanged = 28,
|
||||
AddRoomManagers = 29,
|
||||
RemoveRoomManagers = 30,
|
||||
RoomOwnerChanged = 31,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8421e6d8001b9435797cf8212505374d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,471 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using static com.fpnn.rtm.RTMClient;
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public static class RTMControlCenter
|
||||
{
|
||||
private static object interLocker = new object();
|
||||
//private static volatile bool networkReachable = true;
|
||||
private static volatile NetworkType networkType = NetworkType.NetworkType_Uninited;
|
||||
private static Dictionary<Int64, RTMClient> rtmClients = new Dictionary<long, RTMClient>();
|
||||
private static Dictionary<Int64, Dictionary<Int64, RTMClient>> pidUidClients = new Dictionary<Int64, Dictionary<Int64, RTMClient>>();
|
||||
private static Dictionary<RTMClient, Int64> reloginClients = new Dictionary<RTMClient, Int64>();
|
||||
|
||||
private static Dictionary<string, Dictionary<TCPClient, long>> fileClients = new Dictionary<string, Dictionary<TCPClient, long>>();
|
||||
|
||||
private static volatile bool routineInited;
|
||||
private static volatile bool routineRunning;
|
||||
private static Thread routineThread;
|
||||
private static GameObject rtmGameObject;
|
||||
public static RTMCallbackQueue callbackQueue;
|
||||
|
||||
static RTMControlCenter()
|
||||
{
|
||||
routineInited = false;
|
||||
}
|
||||
|
||||
public static NetworkType NetworkStatus
|
||||
{
|
||||
get { return networkType; }
|
||||
}
|
||||
//===========================[ Session Functions ]=========================//
|
||||
internal static void RegisterSession(Int64 connectionId, RTMClient client)
|
||||
{
|
||||
CheckRoutineInit();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
rtmClients.Add(connectionId, client);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void UnregisterSession(Int64 connectionId)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
rtmClients.Remove(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void CloseSession(Int64 connectionId)
|
||||
{
|
||||
RTMClient client = null;
|
||||
lock (interLocker)
|
||||
{
|
||||
rtmClients.TryGetValue(connectionId, out client);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
client.Close();
|
||||
}
|
||||
|
||||
internal static ClientStatus GetClientStatus(Int64 connectionId)
|
||||
{
|
||||
RTMClient client = null;
|
||||
lock (interLocker)
|
||||
{
|
||||
rtmClients.TryGetValue(connectionId, out client);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
return client.Status;
|
||||
else
|
||||
return ClientStatus.Closed;
|
||||
}
|
||||
internal static void AddClient(Int64 projectId, Int64 uid, RTMClient client)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
pidUidClients.TryGetValue(projectId, out Dictionary<Int64, RTMClient> clients);
|
||||
if (clients == null)
|
||||
{
|
||||
clients = new Dictionary<long, RTMClient>{ { uid, client } };
|
||||
pidUidClients.Add(projectId, clients);
|
||||
}
|
||||
else
|
||||
{
|
||||
clients.TryGetValue(uid, out RTMClient rtmClient);
|
||||
if (rtmClient == null)
|
||||
clients.Add(uid, client);
|
||||
else
|
||||
throw new Exception("duplicated RTMClient pid = " + projectId.ToString() + ", uid = " + uid.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static RTMClient FetchClient(Int64 projectId, Int64 uid)
|
||||
{
|
||||
RTMClient client = null;
|
||||
lock (interLocker)
|
||||
{
|
||||
pidUidClients.TryGetValue(projectId, out Dictionary<Int64, RTMClient> clients);
|
||||
if (clients == null)
|
||||
return null;
|
||||
clients.TryGetValue(uid, out client);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
//===========================[ Relogin Functions ]=========================//
|
||||
internal static void DelayRelogin(RTMClient client, long triggeredMs)
|
||||
{
|
||||
CheckRoutineInit();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
try
|
||||
{
|
||||
reloginClients.Add(client, triggeredMs);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
//-- Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReloginCheck()
|
||||
{
|
||||
//if (!networkReachable)
|
||||
//return;
|
||||
if (networkType != NetworkType.NetworkType_4G && networkType != NetworkType.NetworkType_Wifi)
|
||||
return;
|
||||
|
||||
HashSet<RTMClient> clients = new HashSet<RTMClient>();
|
||||
long now = ClientEngine.GetCurrentMilliseconds();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
foreach (KeyValuePair<RTMClient, Int64> kvp in reloginClients)
|
||||
{
|
||||
if (kvp.Value <= now)
|
||||
clients.Add(kvp.Key);
|
||||
}
|
||||
|
||||
foreach (RTMClient client in clients)
|
||||
reloginClients.Remove(client);
|
||||
}
|
||||
|
||||
foreach (RTMClient client in clients)
|
||||
{
|
||||
ClientEngine.RunTask(() => {
|
||||
if (client.CheckRelogin())
|
||||
client.StartRelogin();
|
||||
else
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
reloginClients.Add(client, now);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//internal static void NetworkReachableChanged(bool reachable)
|
||||
//{
|
||||
// if (reachable != networkReachable)
|
||||
// {
|
||||
// networkReachable = reachable;
|
||||
// long now = ClientEngine.GetCurrentMilliseconds();
|
||||
// if (reachable)
|
||||
// {
|
||||
// Dictionary<RTMClient, Int64> clients = new Dictionary<RTMClient, Int64>();
|
||||
// lock (interLocker)
|
||||
// {
|
||||
// foreach (KeyValuePair<RTMClient, Int64> kvp in reloginClients)
|
||||
// clients.Add(kvp.Key, now);
|
||||
|
||||
// reloginClients = clients;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// lock (interLocker)
|
||||
// {
|
||||
// foreach (KeyValuePair<UInt64, RTMClient> kvp in rtmClients)
|
||||
// {
|
||||
// kvp.Value.Close();
|
||||
// reloginClients.Add(kvp.Value, now);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
internal static void NetworkChanged(NetworkType type)
|
||||
{
|
||||
if (networkType == NetworkType.NetworkType_Uninited)
|
||||
networkType = type;
|
||||
if (type == NetworkType.NetworkType_Unknown)
|
||||
type = NetworkType.NetworkType_Unreachable;
|
||||
if (networkType == type)
|
||||
return;
|
||||
long now = ClientEngine.GetCurrentMilliseconds();
|
||||
NetworkType oldType = networkType;
|
||||
networkType = type;
|
||||
ClientEngine.RunTask(()=>
|
||||
{
|
||||
if (oldType == NetworkType.NetworkType_Unreachable && (type == NetworkType.NetworkType_4G || type == NetworkType.NetworkType_Wifi))
|
||||
{//之前没有网络,现在有网络
|
||||
Dictionary<RTMClient, Int64> clients = new Dictionary<RTMClient, Int64>();
|
||||
List<RTMClient> activeClients = new List<RTMClient>();
|
||||
lock (interLocker)
|
||||
{
|
||||
foreach (KeyValuePair<RTMClient, Int64> kvp in reloginClients)
|
||||
clients.Add(kvp.Key, now);
|
||||
|
||||
foreach (KeyValuePair<Int64, RTMClient> kvp in rtmClients)
|
||||
{
|
||||
if (!clients.ContainsKey(kvp.Value))
|
||||
{
|
||||
if (kvp.Value.Status != ClientStatus.Connecting)
|
||||
{
|
||||
activeClients.Add(kvp.Value);
|
||||
clients.Add(kvp.Value, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (RTMClient client in activeClients)
|
||||
client.Close(false, false);
|
||||
|
||||
reloginClients = clients;
|
||||
}
|
||||
}
|
||||
else if ((type == NetworkType.NetworkType_4G && oldType == NetworkType.NetworkType_Wifi) || (oldType == NetworkType.NetworkType_4G && type == NetworkType.NetworkType_Wifi))
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
List<RTMClient> clients = new List<RTMClient>();
|
||||
foreach (KeyValuePair<Int64, RTMClient> kvp in rtmClients)
|
||||
{
|
||||
if (kvp.Value.Status != ClientStatus.Connecting)
|
||||
{
|
||||
clients.Add(kvp.Value);
|
||||
}
|
||||
}
|
||||
foreach (RTMClient client in clients)
|
||||
client.Close(false, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
List<RTMClient> clients = new List<RTMClient>();
|
||||
foreach (KeyValuePair<Int64, RTMClient> kvp in rtmClients)
|
||||
{
|
||||
if (kvp.Value.Status != ClientStatus.Connecting)
|
||||
{
|
||||
clients.Add(kvp.Value);
|
||||
reloginClients.Add(kvp.Value, now);
|
||||
}
|
||||
}
|
||||
foreach (RTMClient client in clients)
|
||||
client.Close(false, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//===========================[ File Gate Client Functions ]=========================//
|
||||
internal static void ActiveFileGateClient(string endpoint, TCPClient client)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
if (fileClients.TryGetValue(endpoint, out Dictionary<TCPClient, long> clients))
|
||||
{
|
||||
if (clients.ContainsKey(client))
|
||||
clients[client] = ClientEngine.GetCurrentSeconds();
|
||||
else
|
||||
clients.Add(client, ClientEngine.GetCurrentSeconds());
|
||||
}
|
||||
else
|
||||
{
|
||||
clients = new Dictionary<TCPClient, long>
|
||||
{
|
||||
{ client, ClientEngine.GetCurrentSeconds() }
|
||||
};
|
||||
fileClients.Add(endpoint, clients);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static TCPClient FecthFileGateClient(string endpoint)
|
||||
{
|
||||
lock (interLocker)
|
||||
{
|
||||
if (fileClients.TryGetValue(endpoint, out Dictionary<TCPClient, long> clients))
|
||||
{
|
||||
foreach (KeyValuePair<TCPClient, long> kvp in clients)
|
||||
return kvp.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void CheckFileGateClients()
|
||||
{
|
||||
HashSet<string> emptyEndpoints = new HashSet<string>();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
long threshold = ClientEngine.GetCurrentSeconds() - RTMConfig.fileGateClientHoldingSeconds;
|
||||
|
||||
foreach (KeyValuePair<string, Dictionary<TCPClient, long>> kvp in fileClients)
|
||||
{
|
||||
HashSet<TCPClient> unactivedClients = new HashSet<TCPClient>();
|
||||
|
||||
foreach (KeyValuePair<TCPClient, long> subKvp in kvp.Value)
|
||||
{
|
||||
if (subKvp.Value <= threshold)
|
||||
unactivedClients.Add(subKvp.Key);
|
||||
}
|
||||
|
||||
foreach (TCPClient client in unactivedClients)
|
||||
{
|
||||
kvp.Value.Remove(client);
|
||||
}
|
||||
|
||||
if (kvp.Value.Count == 0)
|
||||
emptyEndpoints.Add(kvp.Key);
|
||||
}
|
||||
|
||||
foreach (string endpoint in emptyEndpoints)
|
||||
fileClients.Remove(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================[ Init & Routine Functions ]=========================//
|
||||
public static void Init()
|
||||
{
|
||||
Init(null);
|
||||
}
|
||||
|
||||
public static void Init(RTMConfig config)
|
||||
{
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
StatusMonitor.Instance.Init();
|
||||
#endif
|
||||
InitCallbackQueue();
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
RTMConfig.Config(config);
|
||||
}
|
||||
|
||||
private static void InitCallbackQueue()
|
||||
{
|
||||
rtmGameObject = new GameObject(RTMConfig.RTMGameObjectName);
|
||||
callbackQueue = rtmGameObject.AddComponent<RTMCallbackQueue>();
|
||||
GameObject.DontDestroyOnLoad(rtmGameObject);
|
||||
rtmGameObject.hideFlags = HideFlags.HideInHierarchy;
|
||||
}
|
||||
|
||||
private static void CheckRoutineInit()
|
||||
{
|
||||
if (routineInited)
|
||||
return;
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (routineInited)
|
||||
return;
|
||||
|
||||
routineRunning = true;
|
||||
|
||||
routineThread = new Thread(RoutineFunc)
|
||||
{
|
||||
Name = "RTM.ControlCenter.RoutineThread",
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
#else
|
||||
IsBackground = true
|
||||
#endif
|
||||
};
|
||||
routineThread.Start();
|
||||
|
||||
|
||||
routineInited = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RoutineFunc()
|
||||
{
|
||||
while (routineRunning)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
|
||||
HashSet<RTMClient> clients;
|
||||
try
|
||||
{
|
||||
clients = new HashSet<RTMClient>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
RTMConfig.errorRecorder?.RecordError(e);
|
||||
continue;
|
||||
}
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
foreach (KeyValuePair<Int64, RTMClient> kvp in rtmClients)
|
||||
clients.Add(kvp.Value);
|
||||
}
|
||||
|
||||
foreach (RTMClient client in clients)
|
||||
if (client.ConnectionIsAlive() == false)
|
||||
client.Close(false, true);
|
||||
|
||||
CheckFileGateClients();
|
||||
ReloginCheck();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
AudioRecorderNative.destroy();
|
||||
#endif
|
||||
StatusMonitor.Instance.Close();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
if (!routineInited)
|
||||
return;
|
||||
|
||||
if (!routineRunning)
|
||||
return;
|
||||
|
||||
routineRunning = false;
|
||||
}
|
||||
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
routineThread.Join();
|
||||
#endif
|
||||
HashSet<RTMClient> clients = new HashSet<RTMClient>();
|
||||
|
||||
lock (interLocker)
|
||||
{
|
||||
foreach (KeyValuePair<Int64, RTMClient> kvp in rtmClients)
|
||||
clients.Add(kvp.Value);
|
||||
}
|
||||
|
||||
foreach (RTMClient client in clients)
|
||||
client.Close(true, true);
|
||||
|
||||
rtmClients.Clear();
|
||||
pidUidClients.Clear();
|
||||
reloginClients.Clear();
|
||||
fileClients.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dadf9429ba622491882482f8801503c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using com.fpnn.common;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public interface IRTMMasterProcessor: IQuestProcessor
|
||||
{
|
||||
void SetErrorRecorder(ErrorRecorder recorder);
|
||||
void SetConnectionId(Int64 connId);
|
||||
void BeginCheckPingInterval();
|
||||
bool ConnectionIsAlive();
|
||||
void SessionClosed(int ClosedByErrorCode);
|
||||
|
||||
bool ReloginWillStart(int lastErrorCode, int retriedCount);
|
||||
void ReloginCompleted(bool successful, bool retryAgain, int errorCode, int retriedCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61fa0a40c29974b65b1b6548d0db902f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,582 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using com.fpnn.common;
|
||||
using com.fpnn.proto;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public delegate void SessionClosedDelegate(int ClosedByErrorCode);
|
||||
public delegate bool ReloginWillStartDelegate(int lastErrorCode, int retriedCount);
|
||||
public delegate void ReloginCompletedDelegate(bool successful, bool retryAgain, int errorCode, int retriedCount);
|
||||
public delegate void KickOutDelegate();
|
||||
public delegate void KickoutRoomDelegate(long roomId);
|
||||
public delegate void PushMessageDelegate(RTMMessage message);
|
||||
|
||||
public class RTMQuestProcessor
|
||||
{
|
||||
//----------------[ System Events ]-----------------//
|
||||
public virtual void SessionClosed(int ClosedByErrorCode) { } //-- ErrorCode: com.fpnn.ErrorCode & com.fpnn.rtm.ErrorCode
|
||||
public SessionClosedDelegate SessionClosedCallback;
|
||||
|
||||
//-- Return true for starting relogin, false for stopping relogin.
|
||||
public virtual bool ReloginWillStart(int lastErrorCode, int retriedCount) { return true; }
|
||||
public ReloginWillStartDelegate ReloginWillStartCallback;
|
||||
|
||||
public virtual void ReloginCompleted(bool successful, bool retryAgain, int errorCode, int retriedCount) { }
|
||||
public ReloginCompletedDelegate ReloginCompletedCallback;
|
||||
|
||||
public virtual void Kickout() { }
|
||||
public KickOutDelegate KickoutCallback;
|
||||
|
||||
public virtual void KickoutRoom(long roomId) { }
|
||||
public KickoutRoomDelegate KickoutRoomCallback;
|
||||
|
||||
//----------------[ Message Interfaces ]-----------------//
|
||||
//-- Messages
|
||||
public virtual void PushMessage(RTMMessage message) { }
|
||||
public PushMessageDelegate PushMessageCallback;
|
||||
|
||||
public virtual void PushGroupMessage(RTMMessage message) { }
|
||||
public PushMessageDelegate PushGroupMessageCallback;
|
||||
|
||||
public virtual void PushRoomMessage(RTMMessage message) { }
|
||||
public PushMessageDelegate PushRoomMessageCallback;
|
||||
|
||||
public virtual void PushBroadcastMessage(RTMMessage message) { }
|
||||
public PushMessageDelegate PushBroadcastMessageCallback;
|
||||
|
||||
//-- Chat
|
||||
public virtual void PushChat(RTMMessage message) { }
|
||||
public PushMessageDelegate PushChatCallback;
|
||||
|
||||
public virtual void PushGroupChat(RTMMessage message) { }
|
||||
public PushMessageDelegate PushGroupChatCallback;
|
||||
|
||||
public virtual void PushRoomChat(RTMMessage message) { }
|
||||
public PushMessageDelegate PushRoomChatCallback;
|
||||
|
||||
public virtual void PushBroadcastChat(RTMMessage message) { }
|
||||
public PushMessageDelegate PushBroadcastChatCallback;
|
||||
|
||||
//-- Cmd
|
||||
public virtual void PushCmd(RTMMessage message) { }
|
||||
public PushMessageDelegate PushCmdCallback;
|
||||
|
||||
public virtual void PushGroupCmd(RTMMessage message) { }
|
||||
public PushMessageDelegate PushGroupCmdCallback;
|
||||
|
||||
public virtual void PushRoomCmd(RTMMessage message) { }
|
||||
public PushMessageDelegate PushRoomCmdCallback;
|
||||
|
||||
public virtual void PushBroadcastCmd(RTMMessage message) { }
|
||||
public PushMessageDelegate PushBroadcastCmdCallback;
|
||||
|
||||
//-- Files
|
||||
public virtual void PushFile(RTMMessage message) { }
|
||||
public PushMessageDelegate PushFileCallback;
|
||||
|
||||
public virtual void PushGroupFile(RTMMessage message) { }
|
||||
public PushMessageDelegate PushGroupFileCallback;
|
||||
|
||||
public virtual void PushRoomFile(RTMMessage message) { }
|
||||
public PushMessageDelegate PushRoomFileCallback;
|
||||
|
||||
public virtual void PushBroadcastFile(RTMMessage message) { }
|
||||
public PushMessageDelegate PushBroadcastFileCallback;
|
||||
}
|
||||
|
||||
public class RTMMasterProcessor: IRTMMasterProcessor
|
||||
{
|
||||
private RTMQuestProcessor questProcessor;
|
||||
private DuplicatedMessageFilter duplicatedFilter;
|
||||
private ErrorRecorder errorRecorder;
|
||||
private Int64 connectionId;
|
||||
private Int64 lastPingTime;
|
||||
private readonly Dictionary<string, QuestProcessDelegate> methodMap;
|
||||
|
||||
public RTMMasterProcessor()
|
||||
{
|
||||
duplicatedFilter = new DuplicatedMessageFilter();
|
||||
lastPingTime = 0;
|
||||
|
||||
methodMap = new Dictionary<string, QuestProcessDelegate> {
|
||||
{ "ping", Ping },
|
||||
|
||||
{ "kickout", Kickout },
|
||||
{ "kickoutroom", KickoutRoom },
|
||||
|
||||
{ "pushmsg", PushMessage },
|
||||
{ "pushgroupmsg", PushGroupMessage },
|
||||
{ "pushroommsg", PushRoomMessage },
|
||||
{ "pushbroadcastmsg", PushBroadcastMessage },
|
||||
};
|
||||
}
|
||||
|
||||
public void SetProcessor(RTMQuestProcessor processor)
|
||||
{
|
||||
questProcessor = processor;
|
||||
}
|
||||
|
||||
public void SetErrorRecorder(ErrorRecorder recorder)
|
||||
{
|
||||
errorRecorder = recorder;
|
||||
}
|
||||
|
||||
public void SetConnectionId(Int64 connId)
|
||||
{
|
||||
connectionId = connId;
|
||||
Interlocked.Exchange(ref lastPingTime, 0);
|
||||
}
|
||||
|
||||
public void BeginCheckPingInterval()
|
||||
{
|
||||
Int64 now = ClientEngine.GetCurrentSeconds();
|
||||
Interlocked.Exchange(ref lastPingTime, now);
|
||||
}
|
||||
|
||||
public bool ConnectionIsAlive()
|
||||
{
|
||||
Int64 lastPingSec = Interlocked.Read(ref lastPingTime);
|
||||
|
||||
if (lastPingSec == 0 || ClientEngine.GetCurrentSeconds() - lastPingSec < RTMConfig.lostConnectionAfterLastPingInSeconds)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public QuestProcessDelegate GetQuestProcessDelegate(string method)
|
||||
{
|
||||
if (methodMap.TryGetValue(method, out QuestProcessDelegate process))
|
||||
{
|
||||
return process;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SessionClosed(int ClosedByErrorCode)
|
||||
{
|
||||
if (questProcessor != null)
|
||||
{
|
||||
questProcessor.SessionClosed(ClosedByErrorCode);
|
||||
RTMControlCenter.callbackQueue.PostAction(() => {
|
||||
questProcessor.SessionClosedCallback?.Invoke(ClosedByErrorCode);
|
||||
});
|
||||
}
|
||||
|
||||
RTMControlCenter.UnregisterSession(connectionId);
|
||||
}
|
||||
|
||||
public bool ReloginWillStart(int lastErrorCode, int retriedCount)
|
||||
{
|
||||
bool startRelogin = true;
|
||||
if (questProcessor != null)
|
||||
{
|
||||
if (questProcessor.ReloginWillStartCallback == null)
|
||||
startRelogin = questProcessor.ReloginWillStart(lastErrorCode, retriedCount);
|
||||
else
|
||||
{
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.ReloginWillStartCallback?.Invoke(lastErrorCode, retriedCount);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (startRelogin) //-- if startRelogin == false, will call SessionClosed(), the UnregisterSession() will be called in SessionClosed().
|
||||
RTMControlCenter.UnregisterSession(connectionId);
|
||||
|
||||
return startRelogin;
|
||||
}
|
||||
|
||||
public void ReloginCompleted(bool successful, bool retryAgain, int errorCode, int retriedCount)
|
||||
{
|
||||
if (questProcessor != null)
|
||||
{
|
||||
questProcessor.ReloginCompleted(successful, retryAgain, errorCode, retriedCount);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.ReloginCompletedCallback?.Invoke(successful, retryAgain, errorCode, retriedCount);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------[ RTM Operations ]-------------------//
|
||||
public Answer Ping(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
AdvanceAnswer.SendAnswer(new Answer(quest));
|
||||
|
||||
Int64 now = ClientEngine.GetCurrentSeconds();
|
||||
Interlocked.Exchange(ref lastPingTime, now);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Answer Kickout(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
bool closed = RTMControlCenter.GetClientStatus(connectionId) == RTMClient.ClientStatus.Closed;
|
||||
RTMControlCenter.CloseSession(connectionId);
|
||||
|
||||
if (questProcessor != null && closed == false)
|
||||
{
|
||||
questProcessor.Kickout();
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.KickoutCallback?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Answer KickoutRoom(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
if (questProcessor != null)
|
||||
{
|
||||
long roomId = quest.Want<Int64>("rid");
|
||||
questProcessor.KickoutRoom(roomId);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.KickoutRoomCallback?.Invoke(roomId);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//----------------------[ RTM Messagess Utilities ]-------------------//
|
||||
private TranslatedInfo ProcessChatMessage(Quest quest)
|
||||
{
|
||||
TranslatedInfo tm = new TranslatedInfo();
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<object, object> msg = quest.Want<Dictionary<object, object>>("msg");
|
||||
if (msg.TryGetValue("source", out object source))
|
||||
{
|
||||
tm.sourceLanguage = (string)source;
|
||||
}
|
||||
else
|
||||
tm.sourceLanguage = string.Empty;
|
||||
|
||||
if (msg.TryGetValue("target", out object target))
|
||||
{
|
||||
tm.targetLanguage = (string)target;
|
||||
}
|
||||
else
|
||||
tm.targetLanguage = string.Empty;
|
||||
|
||||
if (msg.TryGetValue("sourceText", out object sourceText))
|
||||
{
|
||||
tm.sourceText = (string)sourceText;
|
||||
}
|
||||
else
|
||||
tm.sourceText = string.Empty;
|
||||
|
||||
if (msg.TryGetValue("targetText", out object targetText))
|
||||
{
|
||||
tm.targetText = (string)targetText;
|
||||
}
|
||||
else
|
||||
tm.targetText = string.Empty;
|
||||
|
||||
return tm;
|
||||
}
|
||||
catch (InvalidCastException e)
|
||||
{
|
||||
if (errorRecorder != null)
|
||||
errorRecorder.RecordError("ProcessChatMessage failed.", e);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageInfo
|
||||
{
|
||||
public bool isBinary;
|
||||
public byte[] binaryData;
|
||||
public string message;
|
||||
}
|
||||
|
||||
private MessageInfo BuildMessageInfo(Quest quest)
|
||||
{
|
||||
MessageInfo info = new MessageInfo();
|
||||
|
||||
object message = quest.Want("msg");
|
||||
info.isBinary = RTMClient.CheckBinaryType(message);
|
||||
if (info.isBinary)
|
||||
info.binaryData = (byte[])message;
|
||||
else
|
||||
info.message = (string)message;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private RTMMessage BuildRTMMessage(Quest quest, long from, long to, long mid)
|
||||
{
|
||||
RTMMessage rtmMessage = new RTMMessage
|
||||
{
|
||||
fromUid = from,
|
||||
toId = to,
|
||||
messageId = mid,
|
||||
messageType = quest.Want<byte>("mtype"),
|
||||
attrs = quest.Want<string>("attrs"),
|
||||
modifiedTime = quest.Want<long>("mtime")
|
||||
};
|
||||
|
||||
if (rtmMessage.messageType == (byte)MessageType.Chat)
|
||||
{
|
||||
rtmMessage.translatedInfo = ProcessChatMessage(quest);
|
||||
if (rtmMessage.translatedInfo != null)
|
||||
{
|
||||
if (rtmMessage.translatedInfo.targetText.Length > 0)
|
||||
rtmMessage.stringMessage = rtmMessage.translatedInfo.targetText;
|
||||
else
|
||||
rtmMessage.stringMessage = rtmMessage.translatedInfo.sourceText;
|
||||
}
|
||||
}
|
||||
else if (rtmMessage.messageType == (byte)MessageType.Cmd)
|
||||
{
|
||||
rtmMessage.stringMessage = quest.Want<string>("msg");
|
||||
}
|
||||
else if (rtmMessage.messageType >= 40 && rtmMessage.messageType <= 50)
|
||||
{
|
||||
rtmMessage.stringMessage = quest.Want<string>("msg");
|
||||
RTMClient.BuildFileInfo(rtmMessage, errorRecorder);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageInfo messageInfo = BuildMessageInfo(quest);
|
||||
if (messageInfo.isBinary)
|
||||
{
|
||||
rtmMessage.binaryMessage = messageInfo.binaryData;
|
||||
}
|
||||
else
|
||||
rtmMessage.stringMessage = messageInfo.message;
|
||||
}
|
||||
|
||||
return rtmMessage;
|
||||
}
|
||||
|
||||
//----------------------[ RTM Messagess ]-------------------//
|
||||
public Answer PushMessage(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
AdvanceAnswer.SendAnswer(new Answer(quest));
|
||||
|
||||
if (questProcessor == null)
|
||||
return null;
|
||||
|
||||
long from = quest.Want<long>("from");
|
||||
long to = quest.Want<long>("to");
|
||||
long mid = quest.Want<long>("mid");
|
||||
|
||||
if (duplicatedFilter.CheckP2PMessage(from, mid, to) == false)
|
||||
return null;
|
||||
|
||||
RTMMessage rtmMessage = BuildRTMMessage(quest, from, to, mid);
|
||||
|
||||
if (rtmMessage.messageType == (byte)MessageType.Chat)
|
||||
{
|
||||
if (rtmMessage.translatedInfo != null)
|
||||
{
|
||||
questProcessor.PushChat(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushChatCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (rtmMessage.messageType == (byte)MessageType.Cmd)
|
||||
{
|
||||
questProcessor.PushCmd(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushCmdCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else if (rtmMessage.messageType >= 40 && rtmMessage.messageType <= 50)
|
||||
{
|
||||
questProcessor.PushFile(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushFileCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
questProcessor.PushMessage(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushMessageCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Answer PushGroupMessage(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
AdvanceAnswer.SendAnswer(new Answer(quest));
|
||||
|
||||
if (questProcessor == null)
|
||||
return null;
|
||||
|
||||
long groupId = quest.Want<long>("gid");
|
||||
long from = quest.Want<long>("from");
|
||||
long mid = quest.Want<long>("mid");
|
||||
|
||||
if (duplicatedFilter.CheckGroupMessage(groupId, from, mid) == false)
|
||||
return null;
|
||||
|
||||
RTMMessage rtmMessage = BuildRTMMessage(quest, from, groupId, mid);
|
||||
|
||||
if (rtmMessage.messageType == (byte)MessageType.Chat)
|
||||
{
|
||||
if (rtmMessage.translatedInfo != null)
|
||||
{
|
||||
questProcessor.PushGroupChat(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushGroupChatCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (rtmMessage.messageType == (byte)MessageType.Cmd)
|
||||
{
|
||||
questProcessor.PushGroupCmd(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushGroupCmdCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else if (rtmMessage.messageType >= 40 && rtmMessage.messageType <= 50)
|
||||
{
|
||||
questProcessor.PushGroupFile(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushGroupFileCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
questProcessor.PushGroupMessage(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushGroupMessageCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Answer PushRoomMessage(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
AdvanceAnswer.SendAnswer(new Answer(quest));
|
||||
|
||||
if (questProcessor == null)
|
||||
return null;
|
||||
|
||||
long from = quest.Want<long>("from");
|
||||
long roomId = quest.Want<long>("rid");
|
||||
long mid = quest.Want<long>("mid");
|
||||
|
||||
if (duplicatedFilter.CheckRoomMessage(roomId, from, mid) == false)
|
||||
return null;
|
||||
|
||||
RTMMessage rtmMessage = BuildRTMMessage(quest, from, roomId, mid);
|
||||
|
||||
if (rtmMessage.messageType == (byte)MessageType.Chat)
|
||||
{
|
||||
if (rtmMessage.translatedInfo != null)
|
||||
{
|
||||
questProcessor.PushRoomChat(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushRoomChatCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (rtmMessage.messageType == (byte)MessageType.Cmd)
|
||||
{
|
||||
questProcessor.PushRoomCmd(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushRoomCmdCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else if (rtmMessage.messageType >= 40 && rtmMessage.messageType <= 50)
|
||||
{
|
||||
questProcessor.PushRoomFile(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushRoomFileCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
questProcessor.PushRoomMessage(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushRoomMessageCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Answer PushBroadcastMessage(Int64 connectionId, string endpoint, Quest quest)
|
||||
{
|
||||
AdvanceAnswer.SendAnswer(new Answer(quest));
|
||||
|
||||
if (questProcessor == null)
|
||||
return null;
|
||||
|
||||
long from = quest.Want<long>("from");
|
||||
long mid = quest.Want<long>("mid");
|
||||
|
||||
if (duplicatedFilter.CheckBroadcastMessage(from, mid) == false)
|
||||
return null;
|
||||
|
||||
RTMMessage rtmMessage = BuildRTMMessage(quest, from, 0, mid);
|
||||
|
||||
if (rtmMessage.messageType == (byte)MessageType.Chat)
|
||||
{
|
||||
if (rtmMessage.translatedInfo != null)
|
||||
{
|
||||
questProcessor.PushBroadcastChat(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushBroadcastChatCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (rtmMessage.messageType == (byte)MessageType.Cmd)
|
||||
{
|
||||
questProcessor.PushBroadcastCmd(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushBroadcastCmdCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else if (rtmMessage.messageType >= 40 && rtmMessage.messageType <= 50)
|
||||
{
|
||||
questProcessor.PushBroadcastFile(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushBroadcastFileCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
questProcessor.PushBroadcastMessage(rtmMessage);
|
||||
RTMControlCenter.callbackQueue.PostAction(() =>
|
||||
{
|
||||
questProcessor.PushBroadcastMessageCallback?.Invoke(rtmMessage);
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3baaa308ec0214907890eaae1e90cbc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47ff5e9cc3e4d47faa5766841754abc2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,86 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
internal static class AudioConvert
|
||||
{
|
||||
#if (UNITY_ANDROID || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("audio-convert")]
|
||||
public static extern IntPtr convert_wav_to_amrwb(IntPtr wavSrc, int wavSrcSize, ref int status, ref int amrSize);
|
||||
|
||||
[DllImport("audio-convert")]
|
||||
public static extern IntPtr convert_amrwb_to_wav(IntPtr amrSrc, int amrSrcSize, ref int status, ref int wavSize);
|
||||
|
||||
[DllImport("audio-convert")]
|
||||
public static extern void free_memory(IntPtr ptr);
|
||||
|
||||
|
||||
#elif UNITY_IOS
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern IntPtr convert_wav_to_amrwb(IntPtr wavSrc, int wavSrcSize, ref int status, ref int amrSize);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern IntPtr convert_amrwb_to_wav(IntPtr amrSrc, int amrSrcSize, ref int status, ref int wavSize);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void free_memory(IntPtr ptr);
|
||||
|
||||
#endif
|
||||
|
||||
public static byte[] ConvertToAmrwb(byte[] wavBuffer)
|
||||
{
|
||||
int status = 0;
|
||||
int amrSize = 0;
|
||||
|
||||
IntPtr wavSrcPtr = Marshal.AllocHGlobal(wavBuffer.Length);
|
||||
Marshal.Copy(wavBuffer, 0, wavSrcPtr, wavBuffer.Length);
|
||||
|
||||
IntPtr amrPtr = AudioConvert.convert_wav_to_amrwb(wavSrcPtr, wavBuffer.Length, ref status, ref amrSize);
|
||||
|
||||
Marshal.FreeHGlobal(wavSrcPtr);
|
||||
|
||||
if (amrPtr != null && status == 0) {
|
||||
byte[] amrBuffer = new byte[amrSize];
|
||||
Marshal.Copy(amrPtr, amrBuffer, 0, amrSize);
|
||||
AudioConvert.free_memory(amrPtr);
|
||||
return amrBuffer;
|
||||
}
|
||||
|
||||
if (amrPtr != null)
|
||||
AudioConvert.free_memory(amrPtr);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] ConvertToWav(byte[] amrBuffer)
|
||||
{
|
||||
int status = 0;
|
||||
int wavSize = 0;
|
||||
|
||||
IntPtr amrSrcPtr = Marshal.AllocHGlobal(amrBuffer.Length);
|
||||
Marshal.Copy(amrBuffer, 0, amrSrcPtr, amrBuffer.Length);
|
||||
|
||||
IntPtr wavPtr = AudioConvert.convert_amrwb_to_wav(amrSrcPtr, amrBuffer.Length, ref status, ref wavSize);
|
||||
|
||||
Marshal.FreeHGlobal(amrSrcPtr);
|
||||
|
||||
if (wavPtr != null && status == 0) {
|
||||
byte[] wavBuffer = new byte[wavSize];
|
||||
Marshal.Copy(wavPtr, wavBuffer, 0, wavSize);
|
||||
AudioConvert.free_memory(wavPtr);
|
||||
return wavBuffer;
|
||||
}
|
||||
|
||||
if (wavPtr != null)
|
||||
AudioConvert.free_memory(wavPtr);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfaf510d97fd04302bf3d50f2486b91d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,324 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using AOT;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
static public class AudioRecorderNative
|
||||
{
|
||||
public enum AudioDeviceType
|
||||
{
|
||||
Microphone = 0,
|
||||
Speaker = 1,
|
||||
}
|
||||
public interface IAudioRecorderListener
|
||||
{
|
||||
void RecordStart(bool success);
|
||||
void RecordEnd();
|
||||
void OnRecord(RTMAudioData audioData);
|
||||
void OnVolumn(double db);
|
||||
void PlayStart(bool success);
|
||||
void PlayEnd();
|
||||
}
|
||||
|
||||
static internal IAudioRecorderListener audioRecorderListener;
|
||||
static internal string language;
|
||||
static volatile bool cancelRecord = false;
|
||||
static volatile bool recording = false;
|
||||
|
||||
delegate void VolumnCallbackDelegate(float volumn);
|
||||
[MonoPInvokeCallback(typeof(VolumnCallbackDelegate))]
|
||||
private static void VolumnCallback(float volumn)
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
float minValue = -60;
|
||||
float range = 60;
|
||||
float outRange = 100;
|
||||
if (volumn < minValue)
|
||||
volumn = minValue;
|
||||
|
||||
volumn = (volumn + range) / range * outRange;
|
||||
audioRecorderListener.OnVolumn(volumn);
|
||||
}
|
||||
}
|
||||
|
||||
delegate void StartRecordCallbackDelegate(bool success);
|
||||
[MonoPInvokeCallback(typeof(StartRecordCallbackDelegate))]
|
||||
private static void StartRecordCallback(bool success)
|
||||
{
|
||||
if (success == false)
|
||||
recording = false;
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.RecordStart(success);
|
||||
}
|
||||
|
||||
delegate void StopRecordCallbackDelegate(IntPtr data, int length, long time);
|
||||
[MonoPInvokeCallback(typeof(StopRecordCallbackDelegate))]
|
||||
private static void StopRecordCallback(IntPtr data, int length, long time)
|
||||
{
|
||||
recording = false;
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
audioRecorderListener.RecordEnd();
|
||||
if (cancelRecord)
|
||||
{
|
||||
cancelRecord = false;
|
||||
return;
|
||||
}
|
||||
if (data == IntPtr.Zero)
|
||||
return;
|
||||
byte[] payload = new byte[length];
|
||||
Marshal.Copy(data, payload, 0, length);
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
RTMAudioData audioData = new RTMAudioData(AudioConvert.ConvertToAmrwb(payload), language, time);
|
||||
#else
|
||||
RTMAudioData audioData = new RTMAudioData(payload, language, time);
|
||||
#endif
|
||||
audioRecorderListener.OnRecord(audioData);
|
||||
}
|
||||
}
|
||||
|
||||
delegate void PlayFinishCallbackDelegate();
|
||||
[MonoPInvokeCallback(typeof(PlayFinishCallbackDelegate))]
|
||||
private static void PlayFinishCallback()
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.PlayEnd();
|
||||
}
|
||||
|
||||
delegate void PlayStartCallbackDelegate(bool success);
|
||||
[MonoPInvokeCallback(typeof(PlayStartCallbackDelegate))]
|
||||
private static void PlayStartCallback(bool success)
|
||||
{
|
||||
audioRecorderListener?.PlayStart(success);
|
||||
}
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
delegate void AudioDeviceChangedDelegate(int type);
|
||||
static bool microphoneChanged = false;
|
||||
static bool speakerChanged = false;
|
||||
[MonoPInvokeCallback(typeof(AudioDeviceChangedDelegate))]
|
||||
private static void AudioDeviceChangedCallback(int type)
|
||||
{
|
||||
AudioDeviceType deviceType = (AudioDeviceType)type;
|
||||
if (deviceType == AudioDeviceType.Microphone)
|
||||
microphoneChanged = true;
|
||||
if (deviceType == AudioDeviceType.Speaker)
|
||||
speakerChanged = true;
|
||||
}
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initAudioDeviceChecker(AudioDeviceChangedDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback, bool update);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback, bool update);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopPlay();
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void playWithPath(byte[] data, int length, PlayFinishCallbackDelegate callback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopPlay();
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void playWithPath(byte[] data, int length, PlayFinishCallbackDelegate callback);
|
||||
#elif UNITY_IOS
|
||||
[DllImport("__Internal")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void stopPlay();
|
||||
#elif UNITY_ANDROID
|
||||
class AudioRecordAndroidProxy : AndroidJavaProxy
|
||||
{
|
||||
public AudioRecordAndroidProxy() : base("com.NetForUnity.IAudioAction")
|
||||
{
|
||||
}
|
||||
|
||||
public void startRecord(bool success, string errorMsg)
|
||||
{
|
||||
if (success == false)
|
||||
recording = false;
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.RecordStart(success);
|
||||
}
|
||||
|
||||
public void stopRecord()
|
||||
{
|
||||
recording = false;
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.RecordEnd();
|
||||
}
|
||||
|
||||
public void startBroad(bool success)
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.PlayStart(success);
|
||||
}
|
||||
|
||||
public void broadFinish()
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.PlayEnd();
|
||||
}
|
||||
|
||||
public void listenVolume(double db)
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
{
|
||||
float minValue = -60;
|
||||
float range = 60;
|
||||
float outRange = 100;
|
||||
if (db < minValue)
|
||||
db = minValue;
|
||||
|
||||
db = (db + range) / range * outRange;
|
||||
|
||||
AudioRecorderNative.audioRecorderListener.OnVolumn(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
static AndroidJavaObject AudioRecord = null;
|
||||
#endif
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
[DllImport("RTMNative")]
|
||||
internal static extern void destroy();
|
||||
#endif
|
||||
|
||||
static public void Init(string language, IAudioRecorderListener listener)
|
||||
{
|
||||
AudioRecorderNative.language = language;
|
||||
audioRecorderListener = listener;
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
initAudioDeviceChecker(AudioDeviceChangedCallback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
|
||||
#elif UNITY_ANDROID
|
||||
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
||||
AndroidJavaObject appconatext = jc.GetStatic<AndroidJavaObject>("currentActivity");
|
||||
if (AudioRecord == null)
|
||||
{
|
||||
AndroidJavaClass playerClass = new AndroidJavaClass("com.NetForUnity.RTMAudio");
|
||||
AudioRecord = playerClass.CallStatic<AndroidJavaObject>("getInstance");
|
||||
}
|
||||
AudioRecord.Call("init", appconatext, language, new AudioRecordAndroidProxy());
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static public bool IsRecording()
|
||||
{
|
||||
return recording;
|
||||
}
|
||||
|
||||
static public void StartRecord()
|
||||
{
|
||||
recording = true;
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
startRecord(VolumnCallback, StartRecordCallback, microphoneChanged);
|
||||
microphoneChanged = false;
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
startRecord(VolumnCallback, StartRecordCallback);
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("startRecord");
|
||||
#else
|
||||
startRecord(VolumnCallback, StartRecordCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void StopRecord()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
stopRecord(StopRecordCallback);
|
||||
#elif UNITY_ANDROID
|
||||
AndroidJavaObject audio = AudioRecord.Call<AndroidJavaObject>("stopRecord");
|
||||
if (audio == null)
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.OnRecord(null);
|
||||
return;
|
||||
}
|
||||
int duration = audio.Get<int>("duration");
|
||||
byte[] audioData = audio.Get<byte[]>("audioData");
|
||||
//byte[] audioData = (byte[])(Array)audio.Get<sbyte[]>("audioData");
|
||||
if (cancelRecord)
|
||||
{
|
||||
cancelRecord = false;
|
||||
return;
|
||||
}
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
RTMAudioData data = new RTMAudioData(audioData, language, duration);
|
||||
audioRecorderListener.OnRecord(data);
|
||||
}
|
||||
#else
|
||||
stopRecord(StopRecordCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void CancelRecord()
|
||||
{
|
||||
cancelRecord = true;
|
||||
StopRecord();
|
||||
}
|
||||
|
||||
static public void Play(RTMAudioData data)
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
byte[] wavBuffer = AudioConvert.ConvertToWav(data.Audio);
|
||||
startPlay(wavBuffer, wavBuffer.Length, PlayFinishCallback, PlayStartCallback, speakerChanged);
|
||||
speakerChanged = false;
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
startPlay(data.Audio, data.Audio.Length, PlayFinishCallback, PlayStartCallback);
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("broadAudio", AudioConvert.ConvertToWav(data.Audio));
|
||||
#else
|
||||
startPlay(data.Audio, data.Audio.Length, PlayFinishCallback, PlayStartCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void StopPlay()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
stopPlay();
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("stopAudio");
|
||||
#else
|
||||
stopPlay();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 297ecbe86374440b18db4b398678923e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,337 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class AudioRecorder : Singleton<AudioRecorder>
|
||||
{
|
||||
public interface IMicrophone {
|
||||
void Start();
|
||||
void End();
|
||||
void OnRecord(RTMAudioData audioData);
|
||||
}
|
||||
|
||||
public static int RECORD_SAMPLE_RATE = 16000;
|
||||
private int LOUDNESS_SAMPLE_WINDOW = 128;
|
||||
private int UPDATE_LOUDNESS_MS = 50;
|
||||
|
||||
private int maxRecordSeconds = 60;
|
||||
private bool isPause;
|
||||
private bool isFocus;
|
||||
|
||||
private string lang;
|
||||
private string device;
|
||||
private bool isRecording;
|
||||
private float loudness;
|
||||
private long lastUpdateLoudnessTime = 0;
|
||||
|
||||
private int position;
|
||||
private AudioClip clipRecord;
|
||||
private IMicrophone micPhone;
|
||||
private object selfLocker = new object();
|
||||
|
||||
void OnEnable() {
|
||||
this.isPause = false;
|
||||
this.isFocus = false;
|
||||
}
|
||||
|
||||
void OnDisable() {
|
||||
StopAllCoroutines();
|
||||
CancelInput();
|
||||
}
|
||||
|
||||
void OnApplicationPause() {
|
||||
if (!this.isPause) {
|
||||
CancelInput();
|
||||
} else {
|
||||
this.isFocus = true;
|
||||
}
|
||||
|
||||
this.isPause = true;
|
||||
}
|
||||
|
||||
void OnApplicationFocus() {
|
||||
if (isFocus) {
|
||||
isPause = false;
|
||||
isFocus = false;
|
||||
}
|
||||
|
||||
if (isPause) {
|
||||
isFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Update() {
|
||||
lock (selfLocker) {
|
||||
if (!isRecording)
|
||||
return;
|
||||
|
||||
long now = ClientEngine.GetCurrentMilliseconds();
|
||||
if (now - lastUpdateLoudnessTime > UPDATE_LOUDNESS_MS) {
|
||||
lastUpdateLoudnessTime = now;
|
||||
UpdateLoudness();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateLoudness() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
float levelMax = 0;
|
||||
float[] data = new float[LOUDNESS_SAMPLE_WINDOW];
|
||||
int pos = Microphone.GetPosition(device) - (LOUDNESS_SAMPLE_WINDOW + 1);
|
||||
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipRecord.GetData(data, pos);
|
||||
|
||||
for (int i = 0; i < LOUDNESS_SAMPLE_WINDOW; i++) {
|
||||
float wavePeak = data[i] * data[i];
|
||||
if (levelMax < wavePeak) {
|
||||
levelMax = wavePeak;
|
||||
}
|
||||
}
|
||||
loudness = levelMax;
|
||||
#endif
|
||||
}
|
||||
|
||||
private IEnumerator TimeDown() {
|
||||
int time = 0;
|
||||
while (++time <= this.maxRecordSeconds) {
|
||||
lock (selfLocker) {
|
||||
if (!isRecording) {
|
||||
yield return 0;
|
||||
}
|
||||
}
|
||||
yield return new WaitForSeconds(1);
|
||||
}
|
||||
FinishInput();
|
||||
}
|
||||
|
||||
public void Init(string lang, string device, IMicrophone micPhone) {
|
||||
position = 0;
|
||||
isRecording = false;
|
||||
this.lang = lang;
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone != null) {
|
||||
this.micPhone = micPhone;
|
||||
}
|
||||
|
||||
lock (selfLocker) {
|
||||
this.device = device;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetLanguage(string lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
public int GetRelativeLoudness(float maxLoudness) {
|
||||
float loudnessNormalized = loudness;
|
||||
if (loudnessNormalized > maxLoudness)
|
||||
loudnessNormalized = maxLoudness;
|
||||
return (int)(loudnessNormalized / maxLoudness * 100);
|
||||
}
|
||||
|
||||
public float GetAbsoluteLoudness() {
|
||||
return loudness;
|
||||
}
|
||||
|
||||
public void StartInput(int maxRecordSeconds = 60) {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Microphone.devices.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (selfLocker) {
|
||||
if (device == null) {
|
||||
device = Microphone.devices[0];
|
||||
}
|
||||
|
||||
if (isRecording) {
|
||||
return;
|
||||
}
|
||||
this.maxRecordSeconds = maxRecordSeconds;
|
||||
isRecording = true;
|
||||
clipRecord = Microphone.Start(device, false, this.maxRecordSeconds, RECORD_SAMPLE_RATE);
|
||||
micPhone.Start();
|
||||
}
|
||||
StartCoroutine("TimeDown");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void FinishInput() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool timeDown = false;
|
||||
lock (selfLocker) {
|
||||
if (isRecording) {
|
||||
timeDown = true;
|
||||
isRecording = false;
|
||||
position = Microphone.GetPosition(device);
|
||||
Microphone.End(device);
|
||||
micPhone.End();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeDown) {
|
||||
StopCoroutine("TimeDown");
|
||||
|
||||
if (micPhone != null && clipRecord != null) {
|
||||
GetAudioData(clipRecord);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
loudness = 0;
|
||||
}
|
||||
|
||||
public void CancelInput() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool timeDown = false;
|
||||
lock (selfLocker) {
|
||||
if (isRecording) {
|
||||
timeDown = true;
|
||||
isRecording = false;
|
||||
Microphone.End(device);
|
||||
micPhone.End();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeDown) {
|
||||
StopCoroutine("TimeDown");
|
||||
}
|
||||
#endif
|
||||
loudness = 0;
|
||||
}
|
||||
|
||||
private void GetAudioData(AudioClip clip) {
|
||||
var soundData = new float[clip.samples * clip.channels];
|
||||
clip.GetData(soundData, 0);
|
||||
var newData = new float[position * clip.channels];
|
||||
|
||||
for (int i = 0; i < newData.Length; i++) {
|
||||
newData[i] = soundData[i];
|
||||
}
|
||||
var newClip = AudioClip.Create (clip.name,
|
||||
position,
|
||||
clip.channels,
|
||||
clip.frequency,
|
||||
false);
|
||||
|
||||
newClip.SetData(newData, 0);
|
||||
long duration = (long)(newClip.length * 1000);
|
||||
|
||||
MemoryStream amrStream = new MemoryStream();
|
||||
ConvertAndWriteWav(amrStream, newClip);
|
||||
WriteWavHeader(amrStream, newClip);
|
||||
int lengthSamples = newClip.samples;
|
||||
|
||||
ClientEngine.RunTask(() => {
|
||||
micPhone.OnRecord(new RTMAudioData(AudioConvert.ConvertToAmrwb(amrStream.ToArray()), newData, RTMAudioData.DefaultCodec, lang, duration, lengthSamples, RECORD_SAMPLE_RATE));
|
||||
});
|
||||
}
|
||||
|
||||
private void ConvertAndWriteWav(MemoryStream stream, AudioClip clip) {
|
||||
float[] samples = new float[clip.samples];
|
||||
clip.GetData(samples, 0);
|
||||
|
||||
Int16[] intData = new Int16[samples.Length];
|
||||
|
||||
Byte[] bytesData = new Byte[samples.Length * 2];
|
||||
|
||||
int rescaleFactor = 32767;
|
||||
|
||||
for (int i = 0; i < samples.Length; i++)
|
||||
{
|
||||
intData[i] = (short)(samples[i] * rescaleFactor);
|
||||
Byte[] byteArr = new Byte[2];
|
||||
byteArr = BitConverter.GetBytes(intData[i]);
|
||||
byteArr.CopyTo(bytesData, i * 2);
|
||||
}
|
||||
stream.Write(bytesData, 0, bytesData.Length);
|
||||
}
|
||||
|
||||
public static void WriteWavHeader(MemoryStream stream, AudioClip clip)
|
||||
{
|
||||
int hz = clip.frequency;
|
||||
int channels = clip.channels;
|
||||
int samples = clip.samples;
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
|
||||
stream.Write(riff, 0, 4);
|
||||
|
||||
Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);
|
||||
stream.Write(chunkSize, 0, 4);
|
||||
|
||||
Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
|
||||
stream.Write(wave, 0, 4);
|
||||
|
||||
Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
|
||||
stream.Write(fmt, 0, 4);
|
||||
|
||||
Byte[] subChunk1 = BitConverter.GetBytes(16);
|
||||
stream.Write(subChunk1, 0, 4);
|
||||
UInt16 one = 1;
|
||||
Byte[] audioFormat = BitConverter.GetBytes(one);
|
||||
stream.Write(audioFormat, 0, 2);
|
||||
|
||||
Byte[] numChannels = BitConverter.GetBytes(channels);
|
||||
stream.Write(numChannels, 0, 2);
|
||||
|
||||
Byte[] sampleRate = BitConverter.GetBytes(hz);
|
||||
stream.Write(sampleRate, 0, 4);
|
||||
|
||||
Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2);
|
||||
stream.Write(byteRate, 0, 4);
|
||||
|
||||
UInt16 blockAlign = (ushort)(channels * 2);
|
||||
stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);
|
||||
|
||||
UInt16 bps = 16;
|
||||
Byte[] bitsPerSample = BitConverter.GetBytes(bps);
|
||||
stream.Write(bitsPerSample, 0, 2);
|
||||
|
||||
Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
|
||||
stream.Write(datastring, 0, 4);
|
||||
|
||||
Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
|
||||
stream.Write(subChunk2, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f568454c4f1fc45d4acea6416df9086e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,182 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using AOT;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public enum NetworkType
|
||||
{
|
||||
NetworkType_Uninited = -2,
|
||||
NetworkType_Unknown = -1,
|
||||
NetworkType_Unreachable = 0,
|
||||
NetworkType_4G = 1,
|
||||
NetworkType_Wifi = 2,
|
||||
}
|
||||
public class StatusMonitor : Singleton<StatusMonitor>
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void closeNetworkStatusChecker();
|
||||
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
#elif UNITY_IOS
|
||||
[DllImport("__Internal")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
#elif UNITY_ANDROID
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void HeadsetStatusDelegate(int networkStatus);
|
||||
|
||||
[MonoPInvokeCallback(typeof(HeadsetStatusDelegate))]
|
||||
public static void HeadsetStatusCallback(int headsetType)
|
||||
{
|
||||
}
|
||||
|
||||
static AndroidJavaObject AndroidNativeManager= null;
|
||||
class NetChangeListener : AndroidJavaProxy
|
||||
{
|
||||
Action<int> msgCallback;
|
||||
public NetChangeListener(Action<int> callback) : base("com.NetForUnity.INetChange") { msgCallback = callback; }
|
||||
public void netChangeNotify(int type)
|
||||
{
|
||||
msgCallback(type);
|
||||
}
|
||||
}
|
||||
class HeadsetListener: AndroidJavaProxy
|
||||
{
|
||||
Action<int> headsetCallback;
|
||||
public HeadsetListener(Action<int> callback) : base("com.NetForUnity.IHeadsetChange") { headsetCallback = callback; }
|
||||
|
||||
public void headsetChange(int type) // //0-无网 1-移动网络 2-wifi
|
||||
{
|
||||
headsetCallback(type);
|
||||
}
|
||||
}
|
||||
private static void initNetworkStatusChecker(Action<int> netChangeCallback, Action<int> headersetCallback)
|
||||
{
|
||||
if (AndroidNativeManager == null)
|
||||
{
|
||||
AndroidJavaClass playerClass = new AndroidJavaClass("com.NetForUnity.ListenUnity");
|
||||
AndroidNativeManager = playerClass.CallStatic<AndroidJavaObject>("getInstance");
|
||||
}
|
||||
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
||||
var context = jc.GetStatic<AndroidJavaObject>("currentActivity");
|
||||
AndroidNativeManager.Call("registerNetChange", context, new NetChangeListener(netChangeCallback));
|
||||
AndroidNativeManager.Call("registerHeadsetChange", context, new HeadsetListener(headersetCallback));
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void NetworkStatusDelegate(int networkStatus);
|
||||
|
||||
[MonoPInvokeCallback(typeof(NetworkStatusDelegate))]
|
||||
static void NetworkStatusCallback(int networkStatus)
|
||||
{
|
||||
RTMControlCenter.NetworkChanged((NetworkType)networkStatus);
|
||||
}
|
||||
|
||||
static private bool _isPause;
|
||||
static private bool _isFocus;
|
||||
static private bool _isBackground;
|
||||
|
||||
internal static bool IsBackground() { return _isBackground; }
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_isPause = false;
|
||||
_isFocus = true;
|
||||
_isBackground = false;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif UNITY_IOS
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif UNITY_ANDROID
|
||||
initNetworkStatusChecker(NetworkStatusCallback, HeadsetStatusCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
closeNetworkStatusChecker();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
// public void Start()
|
||||
// {
|
||||
// StartCoroutine(PerSecondCoroutine());
|
||||
// }
|
||||
//
|
||||
// public void OnDestroy()
|
||||
// {
|
||||
// StopAllCoroutines();
|
||||
// }
|
||||
//
|
||||
// private IEnumerator PerSecondCoroutine()
|
||||
// {
|
||||
// yield return new WaitForSeconds(1.0f);
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// CheckNetworkChange();
|
||||
//
|
||||
// yield return new WaitForSeconds(1.0f);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void CheckNetworkChange()
|
||||
// {
|
||||
// int networkStatus = (int)Application.internetReachability;
|
||||
// RTMControlCenter.NetworkChanged((NetworkType)networkStatus);
|
||||
// }
|
||||
//#endif
|
||||
|
||||
private void CheckInBackground()
|
||||
{
|
||||
if (_isPause && !_isFocus)
|
||||
{
|
||||
if (_isBackground == false)
|
||||
{
|
||||
_isBackground = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isBackground)
|
||||
{
|
||||
_isBackground = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
_isPause = pauseStatus;
|
||||
CheckInBackground();
|
||||
}
|
||||
|
||||
void OnApplicationFocus(bool hasFocus)
|
||||
{
|
||||
_isFocus = hasFocus;
|
||||
CheckInBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d55621c6e649e4542952aed2bc0f5cf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user