510 lines
23 KiB
C#
510 lines
23 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using Common;
|
||
using Dao;
|
||
using Domain;
|
||
using RCUHost.Protocols;
|
||
using System.Threading.Tasks;
|
||
using System.Threading;
|
||
using CommonEntity;
|
||
|
||
namespace RCUHost.Implement
|
||
{
|
||
public class HostSearchReceiver : GenericReceiverBase, IHostSearchReceiver
|
||
{
|
||
public static object objlock = new object();
|
||
private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(HostSearchReceiver));
|
||
|
||
public IHostRepository HostRepository { get; set; }
|
||
public IHostModalRepository HostModalRepository { get; set; }
|
||
public IRoomTypeModalRepository RoomTypeModalRepository { get; set; }
|
||
public ISysHotelRepository SysHotelRepository { get; set; }
|
||
public IGroupRepository GroupRepository { get; set; }
|
||
public IRoomTypeRepository RoomTypeRepository { get; set; }
|
||
public IDeviceSecretReceiver DeviceSecretReceiver { get; set; }
|
||
public IHostRegisterReceiver HostRegisterReceiver { get; set; }//注册时通知同步主机信息
|
||
|
||
private static bool searching = false;
|
||
|
||
/// <summary>
|
||
/// 当前搜索主机用户
|
||
/// </summary>
|
||
private static String user = "";
|
||
|
||
private SearchHostResultHandler searchHostResultHandler;
|
||
|
||
public void Start(SearchHostResultHandler handler)
|
||
{
|
||
searchHostResultHandler = handler;
|
||
searching = true;
|
||
HostServer.AddReceiver(this);
|
||
Start();
|
||
}
|
||
|
||
public void Start()
|
||
{
|
||
//byte[] data = CreateSearchHostRequestPacket();
|
||
//Send(data, MulticastIP, MulticastPort);
|
||
}
|
||
|
||
public bool Searching
|
||
{
|
||
get { return searching; }
|
||
}
|
||
|
||
public string User
|
||
{
|
||
get { return user; }
|
||
set { user = value ?? String.Empty; }
|
||
}
|
||
|
||
public void Stop()
|
||
{
|
||
HostServer.RemoveReceiver(this);
|
||
searchHostResultHandler = null;
|
||
searching = false;
|
||
user = "";
|
||
}
|
||
/// <summary>
|
||
/// 修改协议:原来的搜索改成注册,当mac地址已存在时,更新数据,否则插入新主机
|
||
/// </summary>
|
||
/// <param name="context"></param>
|
||
public override void Process(ReceiverContext context)
|
||
{
|
||
StepTongJi.SendInfo(4, "注册命令Task内部开始执行", context.MessageID, context.IsMonitor);
|
||
//Reply(context);
|
||
|
||
var OriginalByte = context.Data;
|
||
|
||
int lll = OriginalByte.Length;
|
||
var A1 = OriginalByte.Skip(15).Take(lll - 15 - 2).ToArray();
|
||
|
||
int startIndex = StructConverter.SizeOf(context.SystemHeader);
|
||
SearchHostPacketReply? reply = DecodeSearchHostPacketReply(context.Data, startIndex);
|
||
SearchHostPacketReplyV2? reply2 = null;
|
||
if (context.Data.Length > 100)//V2版本新补充的内容
|
||
{
|
||
reply2 = DecodeSearchHostPacketReplyV2(context.Data, 58);
|
||
}
|
||
if (reply.HasValue)
|
||
{
|
||
try
|
||
{
|
||
string hhostnumber = context.SystemHeader.Value.HostNumber.ToString();
|
||
string hotelCode = context.SystemHeader.Value.HostNumber.ToHotelCode().ToString();//获取酒店编码
|
||
string mac = BitConverter.ToString(reply.Value.MAC);
|
||
string version = reply.Value.Version;
|
||
string ip = context.RemoteEndPoint.Address.ToString();
|
||
int port = context.RemoteEndPoint.Port;
|
||
Host exitEntity = null;
|
||
StringBuilder sbSQL = new StringBuilder();
|
||
sbSQL.Append("UPDATE tb_Hosts SET ");
|
||
if (reply2.HasValue)//C系列主机处理:只能靠后台手工添加
|
||
{
|
||
#region C系列主要
|
||
if (string.IsNullOrEmpty(context.SystemHeader.Value.HostNumber.ToString()))
|
||
{
|
||
//logger.Error(string.Format("C主机注册主机编号不能为空。HotelCode:{0},MAC:{1}", hotelCode, mac));
|
||
return;
|
||
}
|
||
|
||
Host EEE = null;
|
||
lock (objlock)
|
||
{
|
||
EEE = HostRepository.LoadByMac(mac).OrderByDescending(r => r.ID).FirstOrDefault();
|
||
}
|
||
if (EEE == null)
|
||
{
|
||
//logger.Error(string.Format("C主机注册通过MAC和版本号C开头找不到记录。HotelCode:{0},MAC:{1}", hotelCode, mac));
|
||
return;//通过mac地址找不到C系列主机,则不新增
|
||
}
|
||
if (string.IsNullOrEmpty(EEE.RoomNumber))
|
||
{
|
||
//logger.Error(string.Format("C主机注册通过MAC和版本号C开头找到记录的房号为空。HotelCode:{0},MAC:{1}", hotelCode, mac));
|
||
return;//如果房号是空,则不更新
|
||
}
|
||
string KKK1 = CacheKey.HostInfo_Key_MAC + "_" + hotelCode + "_" + mac;
|
||
string KKK2 = CacheKey.HostInfo_Key_HostNumber + "_" + hhostnumber;
|
||
object ooo = MemoryCacheHelper.Get(KKK1);
|
||
if (ooo != null)
|
||
{
|
||
exitEntity = (Host)ooo;
|
||
}
|
||
else
|
||
{
|
||
exitEntity = EEE;
|
||
MemoryCacheHelper.Set(KKK1, EEE);
|
||
MemoryCacheHelper.SlideSet(KKK2, EEE);
|
||
}
|
||
exitEntity.DNS = string.Join(".", reply2.Value.DNS);
|
||
sbSQL.Append("DNS='" + exitEntity.DNS + "'");
|
||
if (!version.ToUpper().StartsWith("C"))
|
||
{
|
||
version = "C" + version;//如果命令里的版本号不是C开头,则补上C
|
||
}
|
||
//if (exitEntity.RoomNumber != reply2.Value.RoomNumber)
|
||
//{
|
||
// //如果房号不匹配,则给rcu发命令,同步房号
|
||
//}
|
||
#endregion
|
||
}
|
||
else
|
||
{
|
||
#region 老主机
|
||
string Key = CacheKey.HotelInfo_Key_Code + "_" + hotelCode; ;
|
||
object ooo = MemoryCacheHelper.Get(Key);
|
||
SysHotel sysHotel = null;
|
||
if (ooo != null)
|
||
{
|
||
sysHotel = (SysHotel)ooo;
|
||
}
|
||
else
|
||
{
|
||
sysHotel = SysHotelRepository.GetByCode(hotelCode);//获取酒店记录
|
||
MemoryCacheHelper.SlideSet(hotelCode, sysHotel);
|
||
}
|
||
if (sysHotel == null)//如果无酒店记录,则设置默认酒店
|
||
{
|
||
sysHotel = new SysHotel { ID = 1 };
|
||
}
|
||
exitEntity = HostRepository.GetByMAC(mac, sysHotel.ID);//根据mac地址获取指定酒店下主机
|
||
if (exitEntity == null)//老主机新增
|
||
{
|
||
var entity = new Host();
|
||
entity.HostNumber = context.SystemHeader.Value.HostNumber.ToString();
|
||
entity.RoomNumber = context.SystemHeader.Value.HostNumber.ToRoomNumber();
|
||
entity.MAC = mac;
|
||
entity.SysHotel = sysHotel;
|
||
Group group = GroupRepository.GetGroupList(sysHotel.ID).OrderBy(r => r.ID).FirstOrDefault();
|
||
entity.Group = group != null ? group : new Group { ID = 1 };
|
||
RoomType roomType = RoomTypeRepository.LoadAll().Where(r => r.HotelID == sysHotel.ID && r.Default == true).OrderBy(r => r.ID).FirstOrDefault();
|
||
entity.RoomType = roomType != null ? roomType : new RoomType { ID = 1 };
|
||
entity.IP = ip;
|
||
entity.Port = port;
|
||
entity.Version = reply.Value.Version;
|
||
entity.ConfigVersion = String.Join(".", reply.Value.ConfigVersion);
|
||
entity.SubnetMask = String.Join(".", reply.Value.SubnetMask);
|
||
entity.Gateway = String.Join(".", reply.Value.Gateway);
|
||
entity.Remark = hotelCode;
|
||
entity.RoomStatus = new RoomStatus { ID = 16 };//默认房态“空房”
|
||
entity.SafeStatus = 2;//默认未接保险箱
|
||
entity.RegisterDate = DateTime.Now;
|
||
entity.IsSyncRoomNumber = false;
|
||
entity.IsAutoUpdate = false;
|
||
entity.Last_Modified_Time = DateTime.Now;//标识有更新
|
||
entity = GetDeviceSecret(entity, ref sbSQL);//获取密钥
|
||
HostRepository.Save(entity);//保存主机
|
||
PublishDeviceSecret(entity);//下发密钥
|
||
Task.Factory.StartNew<bool>(() => UpdateHostModals(entity));//创建新回路
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
sbSQL.Append("MAC='" + mac + "'");
|
||
}
|
||
#endregion
|
||
}
|
||
|
||
bool isChanged = false;
|
||
string hostNumber = context.SystemHeader.Value.HostNumber.ToString();
|
||
string configVersion = String.Join(".", reply.Value.ConfigVersion);
|
||
string subnetMask = String.Join(".", reply.Value.SubnetMask);
|
||
string gateway = String.Join(".", reply.Value.Gateway);
|
||
if (true)
|
||
//if (exitEntity.HostNumber != hostNumber)
|
||
{
|
||
exitEntity.HostNumber = hostNumber;
|
||
isChanged = true;
|
||
sbSQL.Append(",HostNumber='" + exitEntity.HostNumber + "'");
|
||
}
|
||
//if (exitEntity.Version != version)
|
||
if (true)
|
||
{
|
||
exitEntity.Version = version;
|
||
isChanged = true;
|
||
sbSQL.Append(",Version='" + exitEntity.Version + "'");
|
||
}
|
||
if (true)
|
||
//if (exitEntity.ConfigVersion != configVersion)
|
||
{
|
||
exitEntity.ConfigVersion = configVersion;
|
||
isChanged = true;
|
||
|
||
BarData bbb = new BarData();
|
||
bbb.HostID = exitEntity.ID;
|
||
|
||
string output = NormalizeVersion(exitEntity.ConfigVersion); // 输出 "15.0.0"
|
||
bbb.ConfiguraVersion = output;
|
||
UploadCurrentVersionReceiver.UP_Grade_Json(exitEntity, bbb);
|
||
|
||
sbSQL.Append(",ConfigVersion='" + exitEntity.ConfigVersion + "'");
|
||
}
|
||
//if (exitEntity.SubnetMask != subnetMask)
|
||
if (true)
|
||
{
|
||
exitEntity.SubnetMask = subnetMask;
|
||
isChanged = true;
|
||
sbSQL.Append(",SubnetMask='" + exitEntity.SubnetMask + "'");
|
||
}
|
||
//if (exitEntity.Gateway != gateway)
|
||
if (true)
|
||
{
|
||
exitEntity.Gateway = gateway;
|
||
isChanged = true;
|
||
sbSQL.Append(",Gateway='" + exitEntity.Gateway + "'");
|
||
}
|
||
//if (exitEntity.Remark != hotelCode)
|
||
if (true)
|
||
{
|
||
exitEntity.Remark = hotelCode;
|
||
isChanged = true;
|
||
sbSQL.Append(",Remark='" + exitEntity.Remark + "'");
|
||
}
|
||
if (isChanged)
|
||
{
|
||
exitEntity.Last_Modified_Time = DateTime.Now;//标识有更新
|
||
sbSQL.Append(",Last_Modified_Time=GETDATE()");
|
||
}
|
||
//if (exitEntity.IP != ip)
|
||
if (true)
|
||
{
|
||
exitEntity.IP = ip;
|
||
isChanged = true;
|
||
sbSQL.Append(",IP='" + exitEntity.IP + "'");
|
||
}
|
||
if (true)
|
||
//if (exitEntity.Port != port)
|
||
{
|
||
exitEntity.Port = port;
|
||
isChanged = true;
|
||
sbSQL.Append(",Port=" + exitEntity.Port);
|
||
}
|
||
//Host hostTemp = HostRepository.Get(exitEntity.ID);//重新获取主机最新升级更新状态数据
|
||
//exitEntity.UpgradeStatus = hostTemp.UpgradeStatus;
|
||
//exitEntity.UpgradeTime = hostTemp.UpgradeTime;
|
||
if (isChanged)
|
||
{
|
||
exitEntity = GetDeviceSecret(exitEntity, ref sbSQL);//获取密钥
|
||
sbSQL.Append(" WHERE ID=" + exitEntity.ID);
|
||
|
||
//string RegisterKey1 = "SearchHostPass";
|
||
//string RegisterKey2 = "SearchHostFilter";
|
||
//暂时的取消
|
||
if (hotelCode.Equals("1197"))
|
||
{
|
||
HostRepository.Update(sbSQL.ToString());//更新主机,用sql语句更新更高效
|
||
}
|
||
else
|
||
{
|
||
|
||
//string KKK = "RegisterKey_" + hhostnumber;
|
||
//object OOO = MemoryCacheHelper.Get(KKK);
|
||
//if (OOO != null)
|
||
//{
|
||
// RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey2, hotelCode);
|
||
//}
|
||
//else
|
||
//{
|
||
// string ti = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
// MemoryCacheHelper.Set(KKK, ti, DateTimeOffset.Now.AddMinutes(5));
|
||
// HostRepository.Update(sbSQL.ToString());//更新主机,用sql语句更新更高效
|
||
// RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey1, hotelCode);
|
||
//}
|
||
HostRepository.Update(sbSQL.ToString());//更新主机,用sql语句更新更高效
|
||
|
||
//有升级的时候,不能被跳过
|
||
string Key = "Upgrade_UpdateSQL_" + exitEntity.HostNumber;
|
||
object OOO1 = MemoryCacheHelper.Get(Key);
|
||
if (OOO1 != null)
|
||
{
|
||
HostRepository.Update(sbSQL.ToString());//更新主机,用sql语句更新更高效
|
||
MemoryCacheHelper.Delete(Key);
|
||
}
|
||
}
|
||
|
||
PublishDeviceSecret(exitEntity);//下发密钥
|
||
}
|
||
if (exitEntity.Version.StartsWith("C"))
|
||
{
|
||
CSRedisCacheHelper.Set(mac, exitEntity.IP + ":" + exitEntity.Port);//心跳包更新
|
||
|
||
string RegisterKey1 = "HostSearchReceiveDrop";
|
||
RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey1, hotelCode);
|
||
|
||
//这里的功能暂时去掉
|
||
//这里会发送 B1 数据 一定 要注意
|
||
//B1不能被去掉
|
||
HostRegisterReceiver.Send(exitEntity);//通知同步工具
|
||
|
||
//logger.Error(string.Format("通知酒店({0})客房({1})同步主机信息。", exitEntity.SysHotel.Code, exitEntity.RoomNumber));
|
||
}
|
||
|
||
string HKey1 = CacheKey.HostInfo_Key_MAC + hotelCode + "_" + mac;
|
||
string HKey = CacheKey.HostInfo_Key_HostNumber + "_" + hostNumber;
|
||
object takeout_obj = MemoryCacheHelper.Get(HKey);
|
||
if (takeout_obj == null)
|
||
{
|
||
MemoryCacheHelper.SlideSet(HKey, exitEntity);
|
||
MemoryCacheHelper.SlideSet(HKey1, exitEntity);
|
||
}
|
||
|
||
|
||
string YiJingChuLiGuo = CacheKey.AllReadyDealWith01_Prefix + "_" + hostNumber;
|
||
MemoryCacheHelper.Set(YiJingChuLiGuo, A1, DateTimeOffset.Now.AddMinutes(5));
|
||
StepTongJi.SendInfo(5, "注册命令Task内部执行完毕", context.MessageID, context.IsMonitor);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
logger.Error(string.Format("终端注册失败,来自:{0},原因:{1},数据:{2}", context.RemoteEndPoint.Address.ToString(), ex.ToString(), Tools.ByteToString(context.Data)));
|
||
}
|
||
}
|
||
}
|
||
|
||
public static string NormalizeVersion(string version, int desiredParts = 3)
|
||
{
|
||
// 移除末尾的冗余点并分割
|
||
var parts = version.TrimEnd('.').Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
|
||
|
||
// 补零到目标位数
|
||
while (parts.Length < desiredParts)
|
||
{
|
||
parts = parts.Concat(new[] { "0" }).ToArray();
|
||
}
|
||
|
||
return string.Join(".", parts);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取主机设备密钥
|
||
/// </summary>
|
||
/// <param name="host"></param>
|
||
/// <returns></returns>
|
||
private Host GetDeviceSecret(Host host, ref StringBuilder sbSQL)
|
||
{
|
||
//如果所属酒店需要自动获取密钥,且目前密钥是空,则自动获取
|
||
if (host.SysHotel.IsAutoGetKey && string.IsNullOrEmpty(host.DeviceSecret))
|
||
{
|
||
DeviceRegisterResult resultData = FreeGoOperation.DeviceRegister(host.MAC);
|
||
if (resultData.errcode == "0")
|
||
{
|
||
host.DeviceName = resultData.device_name;
|
||
sbSQL.Append(",DeviceName='" + host.DeviceName + "'");
|
||
host.DeviceSecret = resultData.device_secret;
|
||
sbSQL.Append(",DeviceSecret='" + host.DeviceSecret + "'");
|
||
host.IotId = resultData.iot_id;
|
||
sbSQL.Append(",IotId='" + host.IotId + "'");
|
||
host.ProductKey = resultData.product_key;
|
||
sbSQL.Append(",ProductKey='" + host.ProductKey + "'");
|
||
host.IsPublish = false;
|
||
sbSQL.Append(",IsPublish=0");
|
||
}
|
||
else
|
||
{
|
||
logger.Error(string.Format("调用FreeGo接口返回错误:RoomNumber:{0},ErrorCode:{1},ErrorMessage:{2}", host.RoomNumber, resultData.errcode, resultData.msg));
|
||
}
|
||
}
|
||
return host;
|
||
}
|
||
/// <summary>
|
||
/// 下发设备密钥
|
||
/// </summary>
|
||
/// <param name="host"></param>
|
||
private void PublishDeviceSecret(Host host)
|
||
{
|
||
if (!host.IsPublish && !string.IsNullOrEmpty(host.DeviceSecret))
|
||
{
|
||
DeviceSecretReceiver.Send(host);
|
||
HostRepository.SetPublish(host, true);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 创建新回路
|
||
/// </summary>
|
||
/// <param name="host"></param>
|
||
/// <returns></returns>
|
||
private bool UpdateHostModals(Host host)
|
||
{
|
||
if (host == null)
|
||
{
|
||
return false;
|
||
}
|
||
HostModalRepository.DeteleByHostID(host.ID);
|
||
var list = RoomTypeModalRepository.LoadAll().Where(r => r.RoomType == host.RoomType);
|
||
DateTime now = DateTime.Now;
|
||
foreach (var modal in list)
|
||
{
|
||
HostModalRepository.Save(new HostModal { HostID = host.ID, Modal = modal, Status = 2, Time = 0, UpdateTime = now });
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public override CommandType CommandType
|
||
{
|
||
get { return CommandType.SearchHost; }
|
||
}
|
||
|
||
#region Private Methods
|
||
|
||
private byte[] CreateSearchHostRequestPacket()
|
||
{
|
||
SystemHeader systemHeader = CreateSystemHeader();
|
||
|
||
SearchHostPacket searchHostPacket = CreateSearchHostPacket();
|
||
|
||
int size = StructConverter.SizeOf(systemHeader) + StructConverter.SizeOf(searchHostPacket);
|
||
|
||
systemHeader.FrameLength = (ushort)size;
|
||
|
||
byte[] buffer = new byte[size];
|
||
|
||
byte[] src1 = StructConverter.StructToBytes(systemHeader);
|
||
Array.Copy(src1, 0, buffer, 0, src1.Length);
|
||
|
||
byte[] src3 = StructConverter.StructToBytes(searchHostPacket);
|
||
Array.Copy(src3, 0, buffer, src1.Length, src3.Length);
|
||
|
||
return buffer;
|
||
}
|
||
|
||
private SearchHostPacket CreateSearchHostPacket()
|
||
{
|
||
#if DEBUG
|
||
var ip = Tools.GetLocalIP();
|
||
#else
|
||
var ip = MessageIP;
|
||
#endif
|
||
|
||
SearchHostPacket packet = new SearchHostPacket
|
||
{
|
||
IsSave = 1,
|
||
IP = IPAddress.Parse(ip).GetAddressBytes(),
|
||
Port = Convert.ToUInt16(MessagePort)
|
||
};
|
||
|
||
return packet;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解码 SearchHostPacketReply
|
||
/// </summary>
|
||
/// <param name="data"></param>
|
||
/// <param name="startIndex"></param>
|
||
/// <returns></returns>
|
||
private SearchHostPacketReply? DecodeSearchHostPacketReply(byte[] data, int startIndex)
|
||
{
|
||
return StructConverter.BytesToStruct(data, startIndex, typeof(SearchHostPacketReply)) as SearchHostPacketReply?;
|
||
}
|
||
|
||
private SearchHostPacketReplyV2? DecodeSearchHostPacketReplyV2(byte[] data, int startIndex)
|
||
{
|
||
return StructConverter.BytesToStruct(data, startIndex, typeof(SearchHostPacketReplyV2)) as SearchHostPacketReplyV2?;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|