using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Common; using Dao; using Domain; using RCUHost.Protocols; namespace RCUHost.Implement { public class UpdateHostReceiver : GenericReceiverBase, IUpdateHostReceiver { private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(UpdateHostReceiver)); private readonly int TFTP_PORT = Convert.ToInt16(System.Configuration.ConfigurationManager.AppSettings["TFTPPort"]);//TFTP通信端口 private const int BLOCK_SIZE = 512;//TFTP块大小512字节 public IHostRepository HostRepository { get; set; } public IHostUpdateStatusRepository HostUpdateStatusRepository { get; set; } private IList updateHostList = new List(); /// /// 升级 /// /// /// /// /// /// public void Update(HostUpdate hostUpdate, FileType fileType, string fileHref, string fileMd5, IList hosts) { if (hosts == null || hosts.Count == 0) { throw new ApplicationException("升级失败,没有找到需要升级的主机。"); } if (String.IsNullOrEmpty(fileHref)) { throw new ApplicationException("升级失败,无效的升级文件。"); } string updateFile = Tools.GetApplicationPath() + fileHref; if (!File.Exists(updateFile)) { throw new ApplicationException("升级失败,【" + updateFile + "】文件不存在。"); } //添加升级功能标志,告诉缓存,不能被拦截 foreach (var item in hosts) { string Key="Upgrade_UpdateSQL_"+ item.HostNumber; MemoryCacheHelper.Set(Key,item.ID,DateTimeOffset.Now.AddMinutes(3)); } FileInfo fileInfo = new FileInfo(updateFile); ushort blockNum = (ushort)Math.Ceiling((double)fileInfo.Length / BLOCK_SIZE); this.updateHostList.Clear(); foreach (var host in hosts) { SendUpdateRequest(host, fileMd5, blockNum, (byte)fileType, fileHref.Substring(fileHref.IndexOf("/")));//发送升级通知 this.updateHostList.Add(new UpdateHostWorker(host, hostUpdate, MessageIP, fileHref, updateFile)); if (hostUpdate == null)//从api获取升级文件方式为null,保存主机表升级状态信息 { HostRepository.SetUpgradeStatus(host, 0, true);//重置升级状态 } else { HostUpdateStatus hostUpdateStatus = HostUpdateStatusRepository.Get(host, hostUpdate); if (hostUpdateStatus == null) { hostUpdateStatus = new HostUpdateStatus(); hostUpdateStatus.Host = host; hostUpdateStatus.HostUpdate = hostUpdate; hostUpdateStatus.PublishTime = DateTime.Now; } hostUpdateStatus.Status = 0; hostUpdateStatus.UpdatedTime = DateTime.Now; HostUpdateStatusRepository.SaveOrUpdate(hostUpdateStatus); } //logger.Error(string.Format("酒店{0}客房{1}开始升级:{2}", host.SysHotel.Code, host.RoomNumber, fileHref)); } } public override void Process(ReceiverContext context1) { int startIndex = StructConverter.SizeOf(context1.SystemHeader); UpdateHostPacketReply? reply1 = DecodeUpdateHostPacketReply(context1.Data, startIndex); var TTT = new Tuple(context1,reply1); //logger.Error(string.Format("收到tftp升级回复命令({0}:{1}):{2},解析结果:{3}", context.RemoteEndPoint.Address.ToString(), context.RemoteEndPoint.Port, Tools.ByteToString(context.Data), reply.HasValue)); if (reply1.HasValue) { Task.Factory.StartNew((State) => { var NNN = State as Tuple; var context = NNN.Item1; var reply = NNN.Item2; var updateHostWorker = this.updateHostList.FirstOrDefault(r => r.Host.HostNumber == context.SystemHeader.Value.HostNumber.ToString()); //logger.Error(string.Format("酒店{0}客房{1}升级({2}),状态{3}", updateHostWorker.Host.SysHotel.Code, updateHostWorker.Host.RoomNumber, updateHostWorker.RemoteFile, reply.Value.Status)); SaveSystemLog(30, "升级主机", string.Format("收到主机({0})升级回复命令,状态:{1}", updateHostWorker.Host.RoomNumber, reply.Value.Status), "收到命令", "RCU", context.RemoteEndPoint.Address.ToString(), updateHostWorker.Host.SysHotel.ID); if (updateHostWorker.HostUpdate == null) { BarData bbb = new BarData(); bbb.HostID = updateHostWorker.Host.ID; switch (reply.Value.Status) { case UpdateHostPacketReply.Ready: HostRepository.SetUpgradeStatus(updateHostWorker.Host, 0);//升级就绪 //updateHostWorker.Update(); bbb.Upgrade_status = "升级就绪"; break; case UpdateHostPacketReply.Completed: Reply(context);//升级完成回复主机 HostRepository.SetUpgradeStatus(updateHostWorker.Host, 1);//升级完成 bbb.Upgrade_status = "升级完成"; break; default: HostRepository.SetUpgradeStatus(updateHostWorker.Host, 2);//升级失败 bbb.Upgrade_status = "升级失败"; break; } UploadCurrentVersionReceiver.UP_Grade_Json(updateHostWorker.Host, bbb); } else { HostUpdateStatus hostUpdateStatus = HostUpdateStatusRepository.Get(updateHostWorker.Host, updateHostWorker.HostUpdate); if (hostUpdateStatus == null) { hostUpdateStatus = new HostUpdateStatus(); hostUpdateStatus.Host = updateHostWorker.Host; hostUpdateStatus.HostUpdate = updateHostWorker.HostUpdate; hostUpdateStatus.PublishTime = DateTime.Now; hostUpdateStatus.Status = 0; } BarData bbb = new BarData(); bbb.HostID = updateHostWorker.Host.ID; switch (reply.Value.Status) { case UpdateHostPacketReply.Ready: //updateHostWorker.Update(); hostUpdateStatus.Status = 0;//升级就绪 bbb.Upgrade_status = "升级就绪"; break; case UpdateHostPacketReply.Completed: bbb.Upgrade_status = "升级完成"; Reply(context);//升级完成回复主机 hostUpdateStatus.Status = 1;//升级完成 updateHostList.Remove(updateHostWorker); break; default: bbb.Upgrade_status = "升级失败"; hostUpdateStatus.Status = 2;//升级失败 updateHostList.Remove(updateHostWorker); break; } bbb.Upgrade_DateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); UploadCurrentVersionReceiver.UP_Grade_Json(updateHostWorker.Host, bbb); hostUpdateStatus.UpdatedTime = DateTime.Now; HostUpdateStatusRepository.SaveOrUpdate(hostUpdateStatus); } },TTT); } } public override CommandType CommandType { get { return CommandType.TFTPUpdate; } } #region Private Methods /// /// 发送升级指令到RCU主机 /// /// /// 升级文件MD5值 private void SendUpdateRequest(Host host, string updateFileMd5, ushort blockNum, byte fileType, string fileName) { byte[] data = CreateUpdateRequestPacket(updateFileMd5, blockNum, fileType, fileName); Send(data, host.HostNumber, host.MAC);// host.IP, host.Port); } /// /// 创建主机升级请求数据包 /// /// 升级文件MD5值 /// 块数量 /// 文件类型 /// 文件名(含酒店编码) /// private byte[] CreateUpdateRequestPacket(string updateFileMd5, ushort blockNum, byte fileType, string fileName) { SystemHeader systemHeader = CreateSystemHeader(); int headerSize = StructConverter.SizeOf(systemHeader); byte[] ipArr = IPAddress.Parse(MessageIP).GetAddressBytes(); byte[] portArr = BitConverter.GetBytes((ushort)TFTP_PORT);//tftp通讯端口 uint[] md5Arr = Tools.MD5StringToUIntArray(updateFileMd5); byte[] bFileName = System.Text.Encoding.Default.GetBytes(fileName); //Tools.GetBytes(fileName, 20); using (var stream = new MemoryStream()) { stream.Seek(headerSize, SeekOrigin.Begin); stream.Write(ipArr, 0, ipArr.Length); stream.Write(portArr, 0, portArr.Length); stream.Write(BitConverter.GetBytes(md5Arr[0]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[1]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[2]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[3]), 0, 4); stream.Write(BitConverter.GetBytes(blockNum), 0, 2); stream.Write(new byte[] { fileType }, 0, 1);//文件类型,0是bin,1是cfg,2是bat stream.Write(bFileName, 0, bFileName.Length);//文件名 stream.Write(new byte[] { 0, 0 }, 0, 2);//补两个长度 //填充 SystemHeader stream.Seek(0, SeekOrigin.Begin); systemHeader.FrameLength = (ushort)stream.Length; systemHeader.FrameNo = 0xFFFF; byte[] headerData = StructConverter.StructToBytes(systemHeader); stream.Write(headerData, 0, headerData.Length); return stream.ToArray(); } } /// /// 解码 UpdateHostPacketReply /// /// /// /// private UpdateHostPacketReply? DecodeUpdateHostPacketReply(byte[] data, int startIndex) { return StructConverter.BytesToStruct(data, startIndex, typeof(UpdateHostPacketReply)) as UpdateHostPacketReply?; } #endregion } public class UpdateHostWorker { private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(UpdateHostWorker)); private readonly int TFTP_PORT = Convert.ToInt16(System.Configuration.ConfigurationManager.AppSettings["TFTPPort"]);//TFTP通信端口 //private Comzept.Genesis.NetworkTools.TFTPClient tftpClient; public Host Host { get; private set; } public int Progress { get; private set; } public HostUpdate HostUpdate; //private Task task; public string RemoteFile; public string LocalFile; public UpdateHostWorker(Host host, HostUpdate hostUpdate, string tftpServer, string remoteFile, string localFile) { this.Host = host; this.HostUpdate = hostUpdate; this.RemoteFile = remoteFile; this.LocalFile = localFile; //this.tftpClient = new Comzept.Genesis.NetworkTools.TFTPClient(tftpServer, TFTP_PORT); //this.tftpClient.ReportCompletedProgress += new Comzept.Genesis.NetworkTools.TFTPClient.ReportCompletedProgressEventDelegate(tftpClient_ReportCompletedProgress); } /// /// Puts the specified remote file. /// public void Update() { logger.Error(string.Format("酒店({0})客房({1})主机升级:RemoteFile:{2},LocalFile:{3}", this.Host.SysHotel.Code, this.Host.RoomNumber, this.RemoteFile, this.LocalFile)); //this.tftpClient.Put(this.RemoteFile, this.LocalFile); } private void tftpClient_ReportCompletedProgress(string remoteIP, int completedBlock, int totalBlock) { this.Progress = completedBlock; logger.Error(string.Format("收到酒店({0})客房({1})主机升级总块数({2})", this.Host.SysHotel.Code, this.Host.RoomNumber, totalBlock)); } public void Dispose() { //if (task != null) //{ // task.Dispose(); //} } } }