备份CatanBuilding瘦身独立工程
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user