Files

283 lines
14 KiB
C#
Raw Permalink Normal View History

2025-12-11 09:17:16 +08:00
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();
//}
}
}
}