Files
2026-05-26 16:15:54 +08:00

997 lines
38 KiB
C#

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);
}
}
}