using System; using System.Collections.Generic; using System.IO; using Google.Protobuf.WellKnownTypes; using Sog; using FileTransDataObject; namespace SMAgent { class AgentFileTransMng : Singleton { public SMAgentDoCommandReq pullReq; public bool isFinish; public string errorMsg; private FileTransMgr transMgr; private long lastTickTime; private int testMode; public AgentFileTransMng() { transMgr = new FileTransMgr(SMAgentUtils.HostName); transMgr._SendTransFileNotify = SendTransFileNotify; isFinish = true; } public void Clear() { TraceLog.Debug("AgentFileTransMng.Clear"); pullReq = null; errorMsg = null; isFinish = true; transMgr.Clear(); } public void Tick(long nowMs) { if (nowMs < lastTickTime + 1000) { return; } lastTickTime = nowMs; transMgr.Tick(nowMs); if (! isFinish && transMgr.IsFinish()) { isFinish = true; Clear(); } } // pull文件时, SMAgentDoCommandRes直接回应Center, Center根据是不是在接收文件再确定是不是接收console的新命令 public int DoTransCmd(SMAgentDoCommandReq req) { if (pullReq != null) { errorMsg = string.Format("last file transfer not finish, cmd {0} file num {1}" , pullReq.Command, transMgr.TotalFile); TraceLog.Error("AgentFileTransMng.DoTransCmd {0}", errorMsg); return -1; } pullReq = req; if (BeginTrans() != 0) { TraceLog.Error("AgentFileTransMng.DoTransCmd {0}", errorMsg); pullReq = null; return -1; } testMode = req.TestMode; // 测试模式, 每次传输1字节, 模拟大文件 if (testMode == 1) { transMgr.SetContentSlice(1); } return 0; } // 初始化文件列表 private List GetTransFiles() { List fileList = new List(); if (pullReq.Command == "pullagentlog") { GetAgentLogFile(fileList); } else if (pullReq.Command == "pull") { GetPullFile(fileList); } return fileList; } public int BeginTrans() { var fileList = GetTransFiles(); if (fileList.Count == 0) { return -1; } var hostList = new List(); hostList.Add(pullReq.CenterName); if (transMgr.BeginTrans(fileList, hostList) != 0) { return -1; } isFinish = false; return 0; } public void SendTransFileNotify(long transSeq, List fileList, List hostList) { var notify = new SMTransFileNotify {TransSeq = transSeq, HostName = SMAgentUtils.HostName}; foreach (FileData file in fileList) { var attr = new FileAttr { FileMd5 = file.fileMd5, FileName = file.fileName, FileSize = file.FileSize, FilePath = file.writeFilePath, FileTime = file.fileWriteTime.ToFileTimeUtc() }; notify.FileList.Add(attr); } foreach (string name in hostList) { SMAgentNet.Instance.SendMsgToCenter(notify, SMMsgID.TransFileNotify); } } public static int count = 0; public void OnFileContentReq(SMFileContentReq req) { // 测试模式, 模拟50%丢包率 if (testMode == 1 && count++ % 2 == 1) { return; } var res = transMgr.OnFileContentReq(req); SMAgentNet.Instance.SendMsgToCenter(res, SMMsgID.FileContentRes); } public void OnFileRecvStateReq(SMFileRecvStateReq req) { transMgr.OnFileRecvStateReq(req); var res = new SMFileRecvStateRes {TransSeq = req.TransSeq, HostName = SMAgentUtils.HostName}; SMAgentNet.Instance.SendMsgToCenter(res, SMMsgID.FileRecvStateRes); } private int GetAgentLogFile(List fileList) { try { // agent的运行目录可以选择硬编码完整路径,或根据center计算(center和agent的部署层次应该是一样) string dir = "../log"; string logFullPath = Path.GetFullPath(dir); foreach (string path in Directory.GetFiles(dir)) { string name = Path.GetFileName(path); if (name.Split('.')[0] != "smagent") { continue; } var file = FileUtils.CreateFileData(path, true); if (file != null) { // 文件名加上host前缀作区分 file.fileName = SMAgentUtils.HostName + "_" + name; // center和agent的部署层级应该是一样的, agent的log目录也是center的目录 file.writeFilePath = logFullPath; fileList.Add(file); } } } catch (Exception e) { TraceLog.Exception(e); errorMsg = e.Message + "\n" + e.StackTrace; return -1; } return 0; } private int GetPullFile(List fileList) { try { /* push 命令支持绝对路径,如果是相对路径,那么是center和agent所在的bin目录为当前目录 * 所以最好用绝对路径,不容易出错 * -r 表示递归 * push 1.200.1 -r /data/mmogrun/publish/cfg/* /data/mmogrun/publish/cfg/ */ //先处理一下参数 bool recursive = false; List pushfileParams = new List(); string[] cmdParams = pullReq.CmdArgs.Split(' '); for (int i = 1; i < cmdParams.Length; i++) { var param = cmdParams[i]; if (param == "-r") { recursive = true; } else { pushfileParams.Add(param); } } if (pushfileParams.Count != 2) { TraceLog.Error("AgentFileTransMng.GetPullFile invalid param"); return -1; } string srcFile, srcfullPath; string dstPath = pushfileParams[1]; string srcfilePath = pushfileParams[0]; //补一下'/',否则Path.GetFullPath结果不会带有'/' if (dstPath[dstPath.Length - 1] != '/' && dstPath[dstPath.Length - 1] != '\\') { dstPath += '/'; } string dstfullPath = Path.GetFullPath(dstPath); int lastindex = srcfilePath.LastIndexOf('/'); if (lastindex == -1) { lastindex = srcfilePath.LastIndexOf('\\'); if (lastindex == -1) { TraceLog.Error("AgentFileTransMng.GetPullFile invalid srcpath {0}", srcfilePath); return -1; } } //源是个目录而不是文件名或通配符,那么在最后加个*上去,这样统一了 if (recursive && Directory.Exists(srcfilePath)) { if (srcfilePath[srcfilePath.Length - 1] != '/' && srcfilePath[srcfilePath.Length - 1] != '\\') { srcfilePath += '/'; } srcFile = "*"; srcfullPath = Path.GetFullPath(srcfilePath); srcfullPath = Path.GetDirectoryName(srcfullPath); } else { string srcPath = srcfilePath.Substring(0, lastindex + 1); srcFile = srcfilePath.Substring(lastindex + 1); srcfullPath = Path.GetFullPath(srcPath); srcfullPath = Path.GetDirectoryName(srcfullPath); } //说明只传一个文件 if (srcFile.Contains('*') == false) { var filefullpath = srcfullPath + "/" + srcFile; var file = FileUtils.CreateFileData(filefullpath, true); file.writeFilePath = dstfullPath; fileList.Add(file); TraceLog.Trace("AgentFileTransMng.GetPullFile add file to list, path {0} file {1}" , file.readFilePath, file.fileName); return 0; } //根据通配符传送多个文件,先判断是否递归 SearchOption so = SearchOption.TopDirectoryOnly; if (recursive) { so = SearchOption.AllDirectories; } foreach (string filefullpath in Directory.GetFiles(srcfullPath, srcFile, so)) { var file = FileUtils.CreateFileData(filefullpath, true); //判断是否子目录 file.writeFilePath = dstfullPath; if (file.readFilePath != srcfullPath) //子目录 { string addsubdir = file.readFilePath.Substring(srcfullPath.Length); file.writeFilePath += addsubdir; } fileList.Add(file); TraceLog.Trace("AgentFileTransMng.GetPullFile add file to list, path {0} file {1}" , file.readFilePath, file.fileName); } } catch (Exception e) { TraceLog.Exception(e); errorMsg = e.Message + "\n" + e.StackTrace; return -1; } return 0; } } }