You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.4 KiB
260 lines
8.4 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Google.Protobuf;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Sog;
|
|
|
|
|
|
namespace FileTransDataObject
|
|
{
|
|
// 一次传输所需信息
|
|
public class FileTransMgr
|
|
{
|
|
public static readonly int TIME_OUT = 30000;
|
|
|
|
// 文件传输时的最大长度, 搞小一点,免得底层分包,麻烦
|
|
public static readonly int CONTENT_SLICE_SIZE = 50 * 1024;
|
|
|
|
// 请求文件内容
|
|
public delegate void SendTransFileNotify(long transSeq, List<FileData> fileList, List<string> hostList);
|
|
public SendTransFileNotify _SendTransFileNotify;
|
|
|
|
public int TotalFile => fileList.Count;
|
|
|
|
public int TotalHost => transHosts.Count;
|
|
|
|
public int TotalSize
|
|
{
|
|
get
|
|
{
|
|
if (totalSize == -1)
|
|
{
|
|
totalSize = fileList.Sum(f => f.FileSize);
|
|
}
|
|
return totalSize;
|
|
}
|
|
}
|
|
|
|
// 负责数据传输的host
|
|
private string localHost;
|
|
|
|
// 本次传送的序列号, 用于快速判断是否同一次传送的Msg, 只用判断开始结束即可
|
|
public long transSeq;
|
|
|
|
// 本次请求传输的所有文件
|
|
public List<FileData> fileList;
|
|
|
|
// 本次接收数据的所有节点
|
|
public Dictionary<string, FileTransNode> transHosts;
|
|
|
|
public long beginTime;
|
|
|
|
public int totalSize;
|
|
|
|
private int finishHostNum;
|
|
|
|
private int contentSlice;
|
|
|
|
public FileTransMgr(string host)
|
|
{
|
|
localHost = host;
|
|
totalSize = -1;
|
|
fileList = new List<FileData>();
|
|
transHosts = new Dictionary<string, FileTransNode>();
|
|
contentSlice = CONTENT_SLICE_SIZE;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
fileList.Clear();
|
|
transHosts.Clear();
|
|
transSeq = 0;
|
|
beginTime = 0;
|
|
finishHostNum = 0;
|
|
totalSize = -1;
|
|
}
|
|
|
|
public bool IsFinish()
|
|
{
|
|
if (finishHostNum == transHosts.Count)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
finishHostNum = transHosts.Values.Count(h => h.state != 0);
|
|
return finishHostNum == transHosts.Count;
|
|
}
|
|
|
|
public void SetContentSlice(int size)
|
|
{
|
|
contentSlice = size;
|
|
}
|
|
|
|
// transFiles: 待传输文件列表
|
|
// hostList: 接收文件的节点列表
|
|
public int BeginTrans(List<FileData> transFiles, List<string> hostList)
|
|
{
|
|
if (transFiles.Count == 0 || hostList.Count == 0)
|
|
{
|
|
TraceLog.Error("FileTransMgr.BeginTrans fail, file num {0} host num {1}", transFiles.Count, hostList.Count);
|
|
return -1;
|
|
}
|
|
|
|
Clear();
|
|
|
|
foreach (string hostName in hostList)
|
|
{
|
|
if (! string.IsNullOrEmpty(hostName) && ! transHosts.ContainsKey(hostName))
|
|
{
|
|
transHosts.Add(hostName, new FileTransNode {receiverHost = hostName});
|
|
}
|
|
}
|
|
|
|
if (transHosts.Count == 0)
|
|
{
|
|
TraceLog.Error("FileTransMgr.BeginTrans fail, host count is 0");
|
|
return -1;
|
|
}
|
|
|
|
fileList.AddRange(transFiles);
|
|
beginTime = AppTime.ServerAppTime.GetTime();
|
|
transSeq = beginTime;
|
|
foreach (FileTransNode transNode in transHosts.Values)
|
|
{
|
|
transNode.lastRecvMsgTime = beginTime;
|
|
}
|
|
|
|
TraceLog.Debug("FileTransMgr.BeginTrans file count {0} total size {1} host count {2}", TotalFile, TotalSize, TotalHost);
|
|
|
|
_SendTransFileNotify(transSeq, transFiles, hostList);
|
|
return 0;
|
|
}
|
|
|
|
|
|
public void Tick(long nowMs)
|
|
{
|
|
foreach (FileTransNode transNode in transHosts.Values)
|
|
{
|
|
if (transNode.state == 0 && transNode.lastRecvMsgTime > 0
|
|
&& nowMs >= transNode.lastRecvMsgTime + TIME_OUT)
|
|
{
|
|
transNode.state = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public FileTransNode GetTransNode(string name)
|
|
{
|
|
transHosts.TryGetValue(name, out FileTransNode node);
|
|
return node;
|
|
}
|
|
|
|
// 20001; // 文件传送结束
|
|
// 20002; // 文件不存在
|
|
// 20003; // 偏移值不合法
|
|
public SMFileContentRes OnFileContentReq(SMFileContentReq req)
|
|
{
|
|
var res = new SMFileContentRes
|
|
{
|
|
Ret = 20001, FileName = req.FileName, FileMd5 = req.FileMd5,
|
|
ContentOffset = req.ContentOffset, TransSeq = req.TransSeq, HostName = localHost
|
|
};
|
|
|
|
var transNode = GetTransNode(req.HostName);
|
|
if (transNode == null)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileContentReq agent {0} not exist", req.HostName);
|
|
return res;
|
|
}
|
|
|
|
transNode.lastRecvMsgTime = AppTime.ServerAppTime.GetTime();
|
|
|
|
// 不是同一轮传输请求
|
|
if (transSeq != req.TransSeq)
|
|
{
|
|
TraceLog.Error("FileRecvMgr.OnFileContentReq transSeq local {0} req {1} not equal"
|
|
, transSeq, req.TransSeq);
|
|
return res;
|
|
}
|
|
|
|
// 文件不存在
|
|
var file = fileList.First(f => f.fileMd5 == req.FileMd5 && f.fileName == req.FileName);
|
|
if (file == null)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileContentReq file {0} md5 {1} not exist", req.FileName, req.FileMd5);
|
|
res.Ret = 20002;
|
|
return res;
|
|
}
|
|
|
|
// 偏移值不合法
|
|
if (req.ContentOffset < 0 || req.ContentOffset >= file.FileSize)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileContentReq invalid offset, file {0} md5 {1} size {2} req {3}",
|
|
file.fileName, file.fileMd5, file.FileSize, req.ContentOffset);
|
|
res.Ret = 20003;
|
|
return res;
|
|
}
|
|
|
|
int length = Math.Min(contentSlice, file.FileSize - req.ContentOffset);
|
|
|
|
TraceLog.Debug("FileTransMgr.OnFileContentReq file {0} md5 {1} size {2} offset {3} length {4}",
|
|
file.fileName, file.fileMd5, file.FileSize, req.ContentOffset, length);
|
|
|
|
res.Ret = 0;
|
|
res.Content = ByteString.CopyFrom(file.fileData, req.ContentOffset, length);
|
|
return res;
|
|
}
|
|
|
|
|
|
// 收到文件接收结果通知
|
|
public void OnFileRecvStateReq(SMFileRecvStateReq req)
|
|
{
|
|
// 传输序列号不一致? 应该不可能出现, 传输由TransNode发起, 如果不一致先回复当前RecvNode成功
|
|
// 同时不做任何处理, 等TransNode超时或者收到来自正确TransSeq的结果通知
|
|
if (transSeq != req.TransSeq)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileRecvStateReq local seq {0} host {1} seq {2} not match"
|
|
, transSeq, req.HostName, req.TransSeq);
|
|
return;
|
|
}
|
|
|
|
var transNode = GetTransNode(req.HostName);
|
|
if (transNode == null)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileRecvStateReq transNode {0} not exist", req.HostName);
|
|
return;
|
|
}
|
|
|
|
transNode.lastRecvMsgTime = AppTime.ServerAppTime.GetTime();
|
|
|
|
if (transNode.state != 0)
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileRecvStateReq transNode {0} finish, state {1}", req.HostName, transNode.state);
|
|
return;
|
|
}
|
|
|
|
transNode.fileState.AddRange(req.FileList);
|
|
|
|
int succNum = 0;
|
|
foreach (FileData file in fileList)
|
|
{
|
|
var recvState = req.FileList.FirstOrDefault(f => f.FileMd5 == file.fileMd5 && f.FileName == file.fileName);
|
|
// 接收成功
|
|
if (recvState != null && recvState.RecvState == 1)
|
|
{
|
|
succNum++;
|
|
}
|
|
else
|
|
{
|
|
TraceLog.Error("FileTransMgr.OnFileRecvStateReq file {0} md5 {1} fail, host {2}",
|
|
file.fileName, file.fileMd5, req.HostName);
|
|
}
|
|
}
|
|
|
|
transNode.state = succNum == fileList.Count ? 1 : -1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|