/*
更新了EMQ连接方式
*/
using System.Collections.Generic;
using System;
using MQTTnet.Client;
using System.Threading.Tasks;
using Shared;
using Shared.SimpleControl;
using MQTTnet;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace SmartHome
{
public static class MqttCommon
{
static string mqttEncryptKey = "";
static string checkGatewayTopicBase64 = "";
static RemoteMACInfo CurRemoteMACInfo = null;
///
/// 手机标识
///
static Guid currentGuid = Guid.NewGuid ();
///
/// 外网的MQTT是否正在连接
///
///
/// 远程MqttClient
///
///
/// 远程MqttClient
///
public static IMqttClient RemoteMqttClient = new MqttFactory ().CreateMqttClient ();
static bool thisShowTip = true;
//static string mqttRequestParToken="";
///
/// 推送标识
///
static string PushSignStr = System.DateTime.Now.Ticks.ToString ();
///
/// 断开远程Mqtt的链接
///
public static async System.Threading.Tasks.Task DisConnectRemoteMqttClient (string s = "")
{
try {
if (remoteIsConnected) {
remoteIsConnected = false;
System.Console.WriteLine ($"Remote主动断开_{s}");
//await RemoteMqttClient.DisconnectAsync(new MQTTnet.Client.Disconnecting.MqttClientDisconnectOptions { }, CancellationToken.None);
await RemoteMqttClient.DisconnectAsync ();
}
} catch (Exception e) {
System.Console.WriteLine ($"Remote断开通讯连接出异常:{e.Message}");
}
}
static DateTime dateTime = DateTime.MinValue;
///
/// 外网的MQTT是否正在连接
///
static bool remoteMqttIsConnecting;
static bool remoteIsConnected;
static MqttCommon ()
{
InitMqtt ();
}
public static bool IsInitMqtt = false;
static void InitMqtt()
{
new System.Threading.Thread (async () => {
while (true) {
try {
System.Threading.Thread.Sleep (100);
//if (!MainPage.LoginUser.IsLogin) {
// continue;
//}
if (!CommonPage.IsRemote) continue;
await StartCloudMqtt ();
await SubscribeTopics ();
} catch { }
}
}) { IsBackground = true }.Start ();
}
static bool isSubscribeSuccess;
static async Task SubscribeTopics ()
{
if (remoteIsConnected && !isSubscribeSuccess) {
try {
var topicFilter1 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange" };
var topicFilter2 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/#" };
var topicFilter3 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.clientId}/Push/NotifySqueeze" };
var result = await RemoteMqttClient.SubscribeAsync (new TopicFilter [] { topicFilter1, topicFilter2, topicFilter3 });
if (result.Items [0].ResultCode == MQTTnet.Client.Subscribing.MqttClientSubscribeResultCode.GrantedQoS2) {
isSubscribeSuccess = true;
}
//var Topic1 = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange";
//var Topic2 = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/#";
//var Topic3 = $"/BusGateWayToClient/{CurRemoteMACInfo.clientId}/Push/NotifySqueeze";
//try {
// await RemoteMqttClient.SubscribeAsync (Topic1);
// await RemoteMqttClient.SubscribeAsync (Topic2);
// await RemoteMqttClient.SubscribeAsync (Topic3);
//} catch (Exception e) {
// await DisConnectRemoteMqttClient (e.Message);
// await StartCloudMqtt ();
// if (remoteIsConnected) {
// await RemoteMqttClient.SubscribeAsync (Topic1);
// await RemoteMqttClient.SubscribeAsync (Topic2);
// await RemoteMqttClient.SubscribeAsync (Topic3);
// }
//}
} catch { }
}
}
///
/// 启动远程Mqtt
///
public static async Task StartCloudMqtt ()
{
//追加:没有远程连接的权限
if (remoteMqttIsConnecting
|| remoteIsConnected || !MainPage.LoginUser.IsLogin) {
return;
}
await System.Threading.Tasks.Task.Factory.StartNew (async () => {
//try {
lock (RemoteMqttClient) {
//表示后面将进行连接
remoteMqttIsConnecting = true;
#region 初始化远程Mqtt
//(3)当[连接云端的Mqtt成功后]或者[以及后面App通过云端Mqtt转发数据给网关成功后],处理接收到云端数据包响应时在mqttServerClient_ApplicationMessageReceived这个方法处理
if (RemoteMqttClient.ApplicationMessageReceivedHandler == null) {
RemoteMqttClient.UseApplicationMessageReceivedHandler ((e) => {
try {
var topic = e.ApplicationMessage.Topic;
//Console.WriteLine ("回复Topic={0}", topic);
if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.clientId}/Push/NotifySqueeze") {
var mMes = CommonPage.MyEncodingUTF8.GetString (e.ApplicationMessage.Payload);
//收到挤下线主题
ReceiveNotifySqueezeAsync (mMes);
} else if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange") {//网关上线,需要更新aeskey
//收到网关上线消息主题
ReceiveNotifyBusGateWayInfoChange ();
}
else if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/CheckGateway") {
var ss = CommonPage.MyEncodingUTF8.GetString (e.ApplicationMessage.Payload);
ReceiveCheckGateway (ss);
}
else {
var packet = new Packet ();
if (!string.IsNullOrEmpty (mqttEncryptKey)) {
packet.Bytes = Shared.Securitys.EncryptionService.AesDecryptPayload (e.ApplicationMessage.Payload, mqttEncryptKey);
} else {
packet.Bytes = e.ApplicationMessage.Payload;
}
packet.Manager ();
}
} catch { }
});
}
if (RemoteMqttClient.DisconnectedHandler == null) {
RemoteMqttClient.UseDisconnectedHandler (async (e) => {
System.Console.WriteLine ($"远程连接断开");
isSubscribeSuccess = false;
await DisConnectRemoteMqttClient ("StartRemoteMqtt.DisconnectedHandler");
if (CommonPage.IsRemote) {
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
});
}
});
}
if (RemoteMqttClient.ConnectedHandler == null) {
RemoteMqttClient.UseConnectedHandler (async (e) => {
System.Console.WriteLine ($"远程连接成功");
Shared.Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = 0xAA69E64A;
});
Shared.SimpleControl.Phone.UserMiddle.ReadAllDeviceStatus ();
if (CurRemoteMACInfo != null) {
if (CurRemoteMACInfo.isValid == "InValid") {
MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.RemoteFailedGatewayOffline));
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
});
} else {
MqttRemoteSend (new byte [] { 0 }, 3);
}
}
});
}
#endregion
}
try {
//--第一步:获取mqtt链接参数 提交MAC 服务器自动判断是否为新网关,返回是否需要自动切换远程连接的服务器
var mqttInfoUrl = @"https://global.hdlcontrol.com/HangZhouHdlCloudApi/EmqMqtt/GetConnMqttInfo";//获取连接远程云端Emq Mqtt 服务器连接信息
var mqttInfoRequestPar = new RemoteRequestParameters () {
PlatformStr = "ON",
LoginAccessToken = MainPage.LoginUser.LoginTokenString,
RequestVersion = MainPage.CodeIDString,
RequestProtocolType = 0,
RequestSource = 1,
HdlGatewayGatewayType = 0,
PublishPayloadJsonStr = PushSignStr,
Mac = UserConfig.Instance.CurrentRegion.MAC,
//IsRedirectSelectEmqServer = true
};
var mqttInfoRequestResult = MainPage.RequestHttps ("", Newtonsoft.Json.JsonConvert.SerializeObject (mqttInfoRequestPar), false, false, mqttInfoUrl);
if (mqttInfoRequestResult != null && mqttInfoRequestResult.ResponseData != null) {
try {
var mqttInfoRequestResult_Obj = Newtonsoft.Json.JsonConvert.DeserializeObject (mqttInfoRequestResult.ResponseData.ToString ());
if (mqttInfoRequestResult_Obj != null) {
string url = mqttInfoRequestResult_Obj.connEmqDomainPort;
string clientId = mqttInfoRequestResult_Obj.connEmqClientId;
string username = mqttInfoRequestResult_Obj.connEmqUserName;
string passwordRemote = mqttInfoRequestResult_Obj.connEmqPwd;
if (mqttInfoRequestResult_Obj.AccountAllGateways != null && mqttInfoRequestResult_Obj.AccountAllGateways.Count > 0) {
//----第二步找出是否存在匹配当前住宅的mac,存在再进行远程。
CurRemoteMACInfo = mqttInfoRequestResult_Obj.AccountAllGateways.Find ((obj) => obj.mac == UserConfig.Instance.CurrentRegion.MAC);
if (CurRemoteMACInfo != null) {
CurRemoteMACInfo.LoginAccessToken = MainPage.LoginUser.LoginTokenString;
CurRemoteMACInfo.clientId = clientId;
mqttEncryptKey = CurRemoteMACInfo.isNewBusproGateway ? CurRemoteMACInfo.aesKey : "";
var options1 = new MQTTnet.Client.Options.MqttClientOptionsBuilder ()
.WithClientId (clientId)
.WithTcpServer (url.Split (':') [1].Substring ("//".Length), int.Parse (url.Split (':') [2]))
.WithCredentials (username, passwordRemote)
.WithCleanSession ()
.WithCommunicationTimeout (new TimeSpan (0, 0, 20))
.Build ();
await DisConnectRemoteMqttClient ("StartRemoteMqtt");
await RemoteMqttClient.ConnectAsync (options1);
remoteIsConnected = true;
IsDisConnectingWithSendCatch = false;
}
}
}
} catch { }
}
} catch (Exception e) {
} finally {
//最终要释放连接状态
remoteMqttIsConnecting = false;
}
});
}
///
/// 收到网关上线消息
///
static void ReceiveNotifyBusGateWayInfoChange ()
{
var gatewayListUrl = @"https://developer.hdlcontrol.com/Center/Center/GetGatewayPagger"; //App、Buspro软件登录后获取网关列表 http 请求
var gatewayListRequestPar = new RemoteRequestParameters () { Mac = CurRemoteMACInfo.mac, LoginAccessToken = MainPage.LoginUser.LoginTokenString, RequestVersion = "RequestVersion1", RequestProtocolType = 0, RequestSource = 1 };
var gatewayListRequestResult = MainPage.RequestHttps ("", Newtonsoft.Json.JsonConvert.SerializeObject (gatewayListRequestPar), false, false, gatewayListUrl);
var gatewayListRequestResult_Obj = Newtonsoft.Json.JsonConvert.DeserializeObject (gatewayListRequestResult.ResponseData.ToString ());
if (gatewayListRequestResult_Obj != null && gatewayListRequestResult_Obj.pageData.Count > 0) {
CurRemoteMACInfo.aesKey = gatewayListRequestResult_Obj.pageData [0].aesKey;
mqttEncryptKey = CurRemoteMACInfo.isNewBusproGateway ? CurRemoteMACInfo.aesKey : "";
}
}
///
/// 收到挤下线推送
///
static void ReceiveNotifySqueezeAsync (string mMes)
{
if (mMes == PushSignStr) return;//是自己的登录推送不处理
//断开远程连接
CommonPage.IsRemote = false;
if (!MainPage.LoginUser.IsLogin) {
return;
}
MainPage.LoginUser.LastTime = DateTime.MinValue;
MainPage.LoginUser.SaveUserInfo ();
Room.Lists.Clear ();
//删除推送数据
var webclient = new System.Net.WebClient ();
webclient.Headers.Add (System.Net.HttpRequestHeader.Authorization, MainPage.LoginUser.LoginTokenString);
webclient.DownloadStringAsync (new Uri ("https://global.hdlcontrol.com/HangZhouHdlCloudApi/ZigbeeUsers/SignOut"));
DisConnectRemoteMqttClient ("挤下线");
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.LinkStatusTipColor;
new Shared.SimpleControl.Phone.AccountLogin (MainPage.LoginUser.AccountString, "").Show ();
SharedMethod.SharedMethod.CurPageLayout = null;
//CommonPage.IsRemote = false;
MainPage.Loading.Hide ();
new Alert (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.Tip), Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LoggedOnOtherDevices),
Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.Close)).Show ();
});
#if HDL
if (!String.IsNullOrEmpty (MainPage.LoginUser.AllVisionRegisterDevUserNameGuid)) {
com.freeview.global.Video.Logout ();
}///BusGateWayToClient/320c1fea-1866-4708-8277-e2321a4dd236/NotifyGateWayInfoChange
#endif
}
///
/// 收到CheckGateway主题
///
static void ReceiveCheckGateway (string mMes) {
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject (mMes);
if (obj == null) {
return;
}
switch (obj.StateCode) {
case "HDLUdpDataForwardServerMqttClientNoOnLine":
case "NoOnline":
case "NetworkAnomaly"://不在线
MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.RemoteFailedGatewayOffline));
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
});
break;
case "NoRecord"://MAC不正确
MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.MACError));
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
});
break;
case "Success":
MainPage.AddTip (UserConfig.Instance.CurrentRegion.RegionName + ":" + Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkSuccess));
break;
default:
MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkLoser));
Application.RunOnMainThread (() => {
Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
});
break;
}
}
///
///
///
/// 附加数据包
/// 操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据
///
public static async Task MqttRemoteSend (byte [] message, int optionType = 0)
{
try {
string topicName;
switch (optionType) {
case 0:
topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/ON";
if (!string.IsNullOrEmpty (mqttEncryptKey)) {
message = Shared.Securitys.EncryptionService.AesEncryptPayload (message, mqttEncryptKey);
}
await RemoteMqttClient.PublishAsync (new MqttApplicationMessage { Topic = topicName, Payload = message, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
break;
case 3:
topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/CheckGateway";
Console.WriteLine ("CheckGateway");
await RemoteMqttClient.PublishAsync (new MqttApplicationMessage { Topic = topicName, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
break;
}
} catch (Exception e) {
//System.Console.WriteLine ($"============>Mqtt MqttRemoteSend catch");
if (!IsDisConnectingWithSendCatch) {
IsDisConnectingWithSendCatch = true;
await DisConnectRemoteMqttClient ("SendCatch");
}
}
}
///
/// SendCatch 后执行一次断开操作
///
static bool IsDisConnectingWithSendCatch = false;
}
}
public class RemoteRequestParameters
{
public string RequestVersion;
public int RequestSource;
public string LoginAccessToken;
public int RequestProtocolType;
public int HdlGatewayGatewayType = 0;
public bool IsRedirectSelectEmqServer = false;
///
/// 平台类型字符串
///
public string PlatformStr;
///
/// 发布主题负载
///
public string PublishPayloadJsonStr;
public string Mac = "";
public string GroupName = "";
}
public class MqttRemoteInfo
{
public List pageData;
public int pageIndex = 0;
public int pageSize = 10;
public int totalCount = 3;
public int totalPages = 1;
public bool hasPreviousPage = false;
public bool hasNextPage = false;
}
public class MqttInfo
{
public string connEmqDomainPort;
public string connEmqClientId;
public string connEmqUserName;
public string connEmqPwd;
public List AccountAllGateways;
}
public class RemoteMACInfo
{
public string mac;
public string macMark;
public string isValid;
public string aesKey;
public bool isNewBusproGateway;
public string groupName;
public string projectName;
public string userName;
public string clientId;
//app自定义数据
public string md5_mac_string;
public string LoginAccessToken;
}
namespace Shared.Securitys
{
public partial class EncryptionService
{
#region 加密
///
/// 加密主题为Base64
///
///
///
///
public static string AesEncryptTopic (string pToEncrypt, string key)
{
if (string.IsNullOrEmpty (pToEncrypt)) return null;
if (string.IsNullOrEmpty (key)) return pToEncrypt;
//需要加密内容的明文流
Byte [] toEncryptArray = Encoding.UTF8.GetBytes (pToEncrypt);
//配置AES加密Key(密钥、向量、模式、填充)
RijndaelManaged rm = new RijndaelManaged {
Key = Encoding.UTF8.GetBytes (key),
IV = Encoding.UTF8.GetBytes (key),
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
//创建AES加密器对象
ICryptoTransform cTransform = rm.CreateEncryptor ();
//使用AES将明文流转成密文字节数组
Byte [] resultArray = cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);
//将AES生成的密文字节数组转成Base64字符串
return Convert.ToBase64String (resultArray, 0, resultArray.Length);
}
///
/// 加密负载为二进制流
///
///
///
///
public static byte [] AesEncryptPayload (byte [] toEncryptArray, string key)
{
if (string.IsNullOrEmpty (key)) return toEncryptArray;
//配置AES加密Key(密钥、向量、模式、填充)
var rm = new RijndaelManaged {
Key = Encoding.UTF8.GetBytes (key),
IV = Encoding.UTF8.GetBytes (key),
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
//创建AES加密器对象
var cTransform = rm.CreateEncryptor ();
//使用AES将明文流转成密文字节数组
return cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);
}
#endregion
#region 解密
///
/// 解密主题数据
///
///
///
///
public static string AesDecryptTopic (string pToDecrypt, string key)
{
//AES密文Base64转成字符串
Byte [] toEncryptArray = Convert.FromBase64String (pToDecrypt);
//配置AES加密Key(密钥、向量、模式、填充)
RijndaelManaged rm = new RijndaelManaged {
Key = Encoding.UTF8.GetBytes (key),
IV = Encoding.UTF8.GetBytes (key),
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
//创建AES解密器对象
ICryptoTransform cTransform = rm.CreateDecryptor ();
//使用AES将密文流转成明文的字节数组
Byte [] resultArray = cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);
//转成字符串
return Encoding.UTF8.GetString (resultArray);
}
///
/// 采用Aes解密负载数据
///
///
///
///
public static byte [] AesDecryptPayload (byte [] toEncryptArray, string key)
{
//配置AES加密Key(密钥、向量、模式、填充)
var rm = new RijndaelManaged {
Key = Encoding.UTF8.GetBytes (key),
IV = Encoding.UTF8.GetBytes (key),
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
};
//创建AES解密器对象
var cTransform = rm.CreateDecryptor ();
//使用AES将密文流转成明文的字节数组
return cTransform.TransformFinalBlock (toEncryptArray, 0, toEncryptArray.Length);
}
#endregion
}
}