陈嘉乐
2020-11-30 ed3bfb7462d44747230437717e8673a5192f833f
HDL_ON/DAL/Net/Mqtt_Cloud.cs
New file
@@ -0,0 +1,463 @@
using System;
using MQTTnet.Client;
using System.Threading.Tasks;
using Shared;
using MQTTnet;
using System.Text;
using HDL_ON.Entity;
namespace HDL_ON.DAL.Net
{
    public static class Mqtt_Cloud
    {
        static string mqttEncryptKey = "";
        static string checkGatewayTopicBase64 = "";
        static RemoteMACInfo CurRemoteMACInfo = null;
        /// <summary>
        /// 手机标识
        /// </summary>
        static Guid currentGuid = Guid.NewGuid();
        /// <summary>
        /// 外网的MQTT是否正在连接
        /// </summary>
        /// <summary>
        /// 远程MqttClient
        /// </summary>
        /// <summary>
        /// 远程MqttClient
        /// </summary>
        public static IMqttClient RemoteMqttClient = new MqttFactory().CreateMqttClient();
        static bool thisShowTip = true;
        //static string mqttRequestParToken="";
        /// <summary>
        /// 推送标识
        /// </summary>
        static string PushSignStr = System.DateTime.Now.Ticks.ToString();
        /// <summary>
        /// 断开远程Mqtt的链接
        /// </summary>
        public static async Task DisConnectRemoteMqttClient(string s = "")
        {
            try
            {
                if (remoteIsConnected)
                {
                    remoteIsConnected = false;
                    MainPage.Log($"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;
        /// <summary>
        /// 外网的MQTT是否正在连接
        /// </summary>
        static bool remoteMqttIsConnecting;
        static bool remoteIsConnected;
        static Mqtt_Cloud()
        {
            InitMqtt();
        }
        public static bool IsInitMqtt = false;
        static void InitMqtt()
        {
            new System.Threading.Thread(async () => {
                while (true)
                {
                    try
                    {
                        System.Threading.Thread.Sleep(1000);
                        if (!MainPage.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;
                    }
                }
                catch { }
            }
        }
        /// <summary>
        /// 启动远程Mqtt
        /// </summary>
        public static async Task StartCloudMqtt()
        {
            //追加:没有远程连接的权限
            if (remoteMqttIsConnecting
               || remoteIsConnected || !MainPage.LoginUser.IsLogin)
            {
                return;
            }
            await 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 = Encoding.UTF8.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 = Encoding.UTF8.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 (MainPage.IsRemote)
                            {
                                Application.RunOnMainThread(() => {
                                    //远程连接成功
                                });
                            }
                        });
                    }
                    if (RemoteMqttClient.ConnectedHandler == null)
                    {
                        RemoteMqttClient.UseConnectedHandler(async (e) => {
                            System.Console.WriteLine($"远程连接成功");
                            MainPage.IsRemote = true;
                            Application.RunOnMainThread(() => {
                                //远程连接成功
                                MainPage.IsRemote = true;
                            });
                            //刷新状态
                            if (CurRemoteMACInfo != null)
                            {
                                if (CurRemoteMACInfo.isValid == "InValid")
                                {
                                    //远程失败
                                    MainPage.IsRemote = false;
                                }
                                else
                                {
                                    MqttRemoteSend(new byte[] { 0 }, 3);
                                }
                            }
                        });
                    }
                    #endregion
                }
                try
                {
                    //--第一步:获取mqtt链接参数 提交MAC 服务器自动判断是否为新网关,返回是否需要自动切换远程连接的服务器
                    var mqttInfoRequestPar = new RemoteRequestParameters()
                    {
                        PlatformStr = "ON",
                        LoginAccessToken = MainPage.LoginUser.loginTokenString,
                        RequestVersion = MainPage.VersionString,
                        RequestProtocolType = 0,
                        RequestSource = 1,
                        HdlGatewayGatewayType = 0,
                        PublishPayloadJsonStr = PushSignStr,
                        Mac = HDL_ON.Entity.DB_ResidenceData.residenceData.residenceGatewayMAC,
                    };
                    var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(mqttInfoRequestPar);
                    var mqttInfoRequestResult = new HDL_ON.DAL.Server.HttpServerRequest().RequestMqttInfo(jsonString);
                    if (mqttInfoRequestResult != null && mqttInfoRequestResult.ResponseData != null)
                    {
                        try
                        {
                            var mqttInfoRequestResult_Obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MqttInfo>(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,存在再进行远程。
                                    foreach (var curRegionMac in DB_ResidenceData.residenceData.residecenInfo.homeGateways)
                                    {
                                        CurRemoteMACInfo = mqttInfoRequestResult_Obj.AccountAllGateways.Find((obj) => obj.mac == curRegionMac.GatewayUniqueId);
                                        if (CurRemoteMACInfo != null)
                                        {
                                            break;
                                        }
                                    }
                                    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;
                }
            });
        }
        ///// <summary>
        ///// 收到网关上线消息
        ///// </summary>
        //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<MqttRemoteInfo>(gatewayListRequestResult.ResponseData.ToString());
        //    if (gatewayListRequestResult_Obj != null && gatewayListRequestResult_Obj.pageData.Count > 0)
        //    {
        //        CurRemoteMACInfo.aesKey = gatewayListRequestResult_Obj.pageData[0].aesKey;
        //        mqttEncryptKey = CurRemoteMACInfo.isNewBusproGateway ? CurRemoteMACInfo.aesKey : "";
        //    }
        //}
        /// <summary>
        /// 收到挤下线推送
        /// </summary>
        static void ReceiveNotifySqueezeAsync(string mMes)
        {
            if (mMes == PushSignStr) return;//是自己的登录推送不处理
            //断开远程连接
            MainPage.IsRemote = false;
            if (!MainPage.LoginUser.IsLogin)
            {
                return;
            }
            MainPage.LoginUser.lastTime = DateTime.MinValue;
            MainPage.LoginUser.SaveUserInfo();
            string oldRegionRootPath = FileUtils.CreateRegionBackup(DB_ResidenceData.residenceData.CurReginID.ToString());
            new System.Threading.Thread(() =>
            {
                try
                {
                    var backuplist = FileUtils.ReadFiles();
                    FileUtils.DeleteRegionFiles(oldRegionRootPath);
                    //移动文件
                    foreach (var fileName in backuplist)
                    {
                        System.IO.FileInfo fileInfo = new System.IO.FileInfo(FileUtils.RootPath + fileName);
                        if (fileName == "headImage.png")
                        {
                            continue;
                        }
                        if (fileInfo.Exists)
                        {
                            fileInfo.MoveTo(oldRegionRootPath + fileName);
                            MainPage.Log("move file : " + fileName);
                        }
                    }
                    //删除本地文件
                    foreach (var fileName in backuplist)
                    {
                        if (fileName == "headImage.png")
                        {
                            continue;
                        }
                        FileUtils.DeleteFile(fileName);
                    }
                }
                catch (Exception ex)
                {
                    MainPage.Log(ex.Message);
                }
                finally
                {
                }
            })
            { IsBackground = true }.Start();
            //删除推送数据
            DisConnectRemoteMqttClient("挤下线");
            Application.RunOnMainThread(() =>
            {
                MainPage.GoLoginPage(MainPage.LoginUser);
            });
        }
        /// <summary>
        /// 收到CheckGateway主题
        /// </summary>
        static void ReceiveCheckGateway(string mMes)
        {
            var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponsePack>(mMes);
            if (obj == null)
            {
                return;
            }
            switch (obj.StateCode)
            {
                case "HDLUdpDataForwardServerMqttClientNoOnLine":
                case "NoOnline":
                case "NetworkAnomaly"://不在线
                    Application.RunOnMainThread(() =>
                    {
                        new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.RemoteFailedGatewayOffline), true);
                    });
                    break;
                case "NoRecord"://MAC不正确
                    Application.RunOnMainThread(() => {
                        new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.MACError), true);
                    });
                    break;
                case "Success":
                    break;
                default:
                    Application.RunOnMainThread(() => {
                        new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.LinkLoser), true);
                    });
                    break;
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="message">附加数据包</param>
        /// <param name="optionType">操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据</param>
        /// <returns></returns>
        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");
                }
            }
        }
        /// <summary>
        /// SendCatch 后执行一次断开操作
        /// </summary>
        static bool IsDisConnectingWithSendCatch = false;
    }
}