Files
Web_CRICS_Server_VS2010_Prod/RCUHost/Implement/UpdateHostReceiver.cs
2025-12-11 09:17:16 +08:00

283 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<UpdateHostWorker> updateHostList = new List<UpdateHostWorker>();
/// <summary>
/// 升级
/// </summary>
/// <param name="hostUpdate"></param>
/// <param name="fileType"></param>
/// <param name="fileHref"></param>
/// <param name="fileMd5"></param>
/// <param name="hosts"></param>
public void Update(HostUpdate hostUpdate, FileType fileType, string fileHref, string fileMd5, IList<Host> 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<ReceiverContext, UpdateHostPacketReply?>(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<ReceiverContext, UpdateHostPacketReply?>;
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
/// <summary>
/// 发送升级指令到RCU主机
/// </summary>
/// <param name="host"></param>
/// <param name="updateFileMd5">升级文件MD5值</param>
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);
}
/// <summary>
/// 创建主机升级请求数据包
/// </summary>
/// <param name="updateFileMd5">升级文件MD5值</param>
/// <param name="blockNum">块数量</param>
/// <param name="fileType">文件类型</param>
/// <param name="fileName">文件名(含酒店编码)</param>
/// <returns></returns>
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是bin1是cfg2是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();
}
}
/// <summary>
/// 解码 UpdateHostPacketReply
/// </summary>
/// <param name="data"></param>
/// <param name="startIndex"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Puts the specified remote file.
/// </summary>
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();
//}
}
}
}