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 UpdateHostFTPReceiver : GenericReceiverBase, IUpdateHostFTPReceiver { private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(UpdateHostFTPReceiver)); 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 + "】文件不存在。"); } this.updateHostList.Clear(); foreach (var host in hosts) { SendUpdateRequest(host, fileMd5, (byte)fileType, fileHref.Substring(fileHref.IndexOf("/"))); this.updateHostList.Add(new UpdateHostWorker(host, hostUpdate, MessageIP, fileHref, updateFile)); ; 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); } } public override void Process(ReceiverContext context) { int startIndex = StructConverter.SizeOf(context.SystemHeader); UpdateHostPacketReply? reply = DecodeUpdateHostPacketReply(context.Data, startIndex); if (reply.HasValue) { //logger.Error(string.Format("收到ftp升级回复命令({0}:{1}):{2}", context.RemoteEndPoint.Address.ToString(), context.RemoteEndPoint.Port, Tools.ByteToString(context.Data))); var updateHostWorker = updateHostList.FirstOrDefault(r => r.Host.SysHotel.Code == context.SystemHeader.Value.HostNumber.ToHotelCode().ToString() && r.Host.HostNumber == context.SystemHeader.Value.HostNumber.ToString()); if (updateHostWorker != null) { SaveSystemLog(30, "升级主机", string.Format("收到主机({0})升级回复命令,状态:{1}", updateHostWorker.Host.RoomNumber, reply.Value.Status), "收到命令", "RCU", context.RemoteEndPoint.Address.ToString(), updateHostWorker.Host.SysHotel.ID); 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; } switch (reply.Value.Status) { case UpdateHostPacketReply.Ready: hostUpdateStatus.Status = 0; break; case UpdateHostPacketReply.Completed: Reply(context);//升级完成回复主机 hostUpdateStatus.Status = 1; updateHostList.Remove(updateHostWorker); break; default: hostUpdateStatus.Status = 2; updateHostList.Remove(updateHostWorker); break; } hostUpdateStatus.UpdatedTime = DateTime.Now; HostUpdateStatusRepository.SaveOrUpdate(hostUpdateStatus); } } } public override CommandType CommandType { get { return CommandType.FTPUpdate; } } #region Private Methods /// /// 发送升级指令到RCU主机 /// /// /// 升级文件MD5值 private void SendUpdateRequest(Host host, string updateFileMd5, byte fileType, string fileName) { byte[] data = CreateUpdateRequestPacket(updateFileMd5, fileType, fileName); Send(data, host.HostNumber, host.MAC);// host.IP, host.Port); } /// /// 创建主机升级请求数据包 /// /// 升级文件MD5值 /// 块数量 /// 文件类型 /// 文件名(含酒店编码) /// private byte[] CreateUpdateRequestPacket(string updateFileMd5, byte fileType, string fileName) { SystemHeader systemHeader = CreateSystemHeader(); int headerSize = StructConverter.SizeOf(systemHeader); byte[] ipArr = IPAddress.Parse(this.FTPServer).GetAddressBytes(); byte[] portArr = BitConverter.GetBytes(this.FTPPort);//ftp通讯端口 //string ftpName = SysSettingRepository.GetValue("FTPName").ToString(); byte[] bFTPName = System.Text.Encoding.Default.GetBytes(this.FTPName); //string ftpPassword = SysSettingRepository.GetValue("FTPPassword").ToString(); byte[] bFTPPassword = System.Text.Encoding.Default.GetBytes(this.FTPPassword); uint[] md5Arr = Tools.MD5StringToUIntArray(updateFileMd5); byte[] bFileName = System.Text.Encoding.Default.GetBytes(fileName); 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(new byte[] { fileType }, 0, 1);//文件类型:0是bin,1是cfg stream.Write(BitConverter.GetBytes(this.FTPName.Length), 0, 1);//用户名长度 stream.Write(BitConverter.GetBytes(this.FTPPassword.Length), 0, 1);//密码长度 stream.Write(BitConverter.GetBytes(Tools.GetLength(fileName)), 0, 1);//文件名长度 stream.Write(bFTPName, 0, bFTPName.Length);//用户名 stream.Write(bFTPPassword, 0, bFTPPassword.Length);//密码 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 } }