public void IncomingMessageEventTest()
        {
            var    contentServiceThing = TheThingRegistry.GetBaseEngineAsThing(eEngineName.ContentService);
            var    contentServiceEng   = contentServiceThing.GetBaseEngine();
            int    numberOfMessages    = 0;
            string txt     = "TEST_TXT";
            string payload = "TestPayload";
            TSM    testMsg = new TSM(eEngineName.ContentService, txt, payload);

            contentServiceEng?.RegisterEvent(eEngineEvents.IncomingMessage, (t, o) =>
            {
                numberOfMessages++;
                if (o is TheProcessMessage msg)
                {
                    Assert.AreEqual(msg.Message.TXT, txt);
                    Assert.AreEqual(msg.Message.PLS, payload);
                    Assert.AreEqual(msg.Message.ENG, contentServiceEng.GetEngineName());
                    testMsg.PLS = "TestPayload2";
                    //Assert.AreNotEqual(msg.Message.PLS, testMsg.PLS); // This fails
                }
                if (t is ICDEThing thing)
                {
                    Assert.AreEqual(thing.GetBaseThing().cdeMID, contentServiceThing.cdeMID);
                }
            });
            TheCommCore.PublishCentral(testMsg, true);
            TheCommonUtils.SleepOneEye(5000, 1000);
            Assert.AreEqual(numberOfMessages, 1);
        }
        public void StartPropertyUpdateLoop()
        {
            testThing = new TheThing()
            {
                FriendlyName = "MyTestSensor"
            };
            TheThingRegistry.RegisterThing(testThing);
            Random rand = new Random(); // Used for generating "fake" sensor values

            cdeP[] props = new cdeP[propertyCount];

            // Run the loop on another thread
            TheCommonUtils.cdeRunAsync("PropertyUpdateLoop", true, (o) =>
            {
                while (TheBaseAssets.MasterSwitch)
                {
                    // Set the properties and log
                    props[0] = testThing.SetProperty(properties[0], rand.Next(25, 51));
                    props[1] = testThing.SetProperty(properties[1], rand.NextDouble());
                    props[2] = testThing.SetProperty(properties[2], rand.Next(10000, 50000));
                    LogChanges(false, props);

                    // Wait timeout of 1 second between property updates
                    TheCommonUtils.SleepOneEye(1000, 500);
                }
            });
        }
Exemple #3
0
 void sinkError(TheRequestData pData)
 {
     eventMessage?.Invoke(pData.ErrorDescription, pData);
     if (IsConnected && mRetryOnError > 0)
     {
         TheCommonUtils.SleepOneEye(mRetryOnError, 100);
         GetDevices();
     }
 }
Exemple #4
0
        public bool PostToWeb(Uri pUrl, string tPost, Action <TheRequestData> pCallback, string MimeTypeOverride = null, cdeConcurrentDictionary <string, string> paddHeader = null, string pMethodOveride = "POST")
        {
            if (!IsConnected || !TheBaseAssets.MasterSwitch || MyRequestData == null || pUrl == null)
            {
                return(false);
            }
            TheRequestData tD = MyRequestData;

            if (!string.IsNullOrEmpty(tPost))
            {
                tD.PostData = TheCommonUtils.CUTF8String2Array(tPost);
            }
            else
            {
                tD.PostData = null;
            }
            tD.RequestUri = pUrl; // new Uri($"https://ptdevices.com{Url}");
            tD.HttpMethod = pMethodOveride;
            tD.Header     = null;
            if (paddHeader != null)
            {
                tD.Header = new cdeConcurrentDictionary <string, string>();
                foreach (string key in paddHeader.Keys)
                {
                    tD.Header.TryAdd(key, paddHeader[key]);
                }
            }
            tD.DisableRedirect = true;
            tD.RequestCookies  = MyRequestData?.SessionState?.StateCookies;
            if (!string.IsNullOrEmpty(MimeTypeOverride))
            {
                tD.ResponseMimeType = MimeTypeOverride; // "application/x-www-form-urlencoded; charset=UTF-8";
            }
            else
            {
                tD.ResponseMimeType = mPostMimeType; // "application/x-www-form-urlencoded; charset=UTF-8";
            }
            while (MyRest.IsPosting > 1 && IsConnected)
            {
                TheCommonUtils.SleepOneEye(1000, 100);
            }
            if (IsConnected)
            {
                MyRest.PostRESTAsync(tD, pCallback, sinkError);
            }
            return(true);
        }
        public void IncomingMessage2EventTest()
        {
            var    contentServiceThing = TheThingRegistry.GetBaseEngineAsThing(eEngineName.ContentService);
            var    contentServiceEng   = contentServiceThing.GetBaseEngine();
            int    numberOfMessages    = 0;
            string txt     = "CDE_GET_SERVICEINFO";
            string payload = "CHNL";
            TSM    testMsg = new TSM(eEngineName.ContentService, txt, payload);

            contentServiceThing?.RegisterEvent(eEngineEvents.IncomingEngineMessage, (t, o) =>
            {
                // Two messages should be received here - The first intercepts the CDE_GET_SERVICEINFO
                // The second intercepts the CDE_SERVICEINFO response (since originator Thing was set to ContentService)
                numberOfMessages++;
            });
            testMsg.SetOriginatorThing(contentServiceThing);
            TheCommCore.PublishCentral(testMsg, true);
            TheCommonUtils.SleepOneEye(5000, 1000);
            Assert.AreEqual(numberOfMessages, 2);
        }
Exemple #6
0
        void ParseDevices(TheRequestData pdata)
        {
            MyRequestData = pdata;
            var tRes = TheCommonUtils.CArray2UTF8String(pdata.ResponseBuffer);

            eventDeviceDataReceived?.Invoke(tRes, pdata);

            if (IsConnected)
            {
                do
                {
                    TheCommonUtils.SleepOneEye(mReadyEvery, 100); //TheCommonUtils.CUInt(TheThing.GetSafePropertyNumber(MyBaseThing, "ReadEvery"))
                    if (WasDisconnected || !TheBaseAssets.MasterSwitch)
                    {
                        WasDisconnected = false;
                        return;
                    }
                } while (WaitForService);
                GetDevices();
            }
        }
Exemple #7
0
        public void ProcessHttpRequest(HttpListenerContext mContext)
        {
            TheRequestData tRequestData = new TheRequestData();

            try
            {
                tRequestData.RequestUri = mContext.Request.Url;
                // TheSystemMessageLog.ToCo(tRequestData.RequestUri.ToString(), true);
                tRequestData.UserAgent        = mContext.Request.UserAgent;
                tRequestData.ServerTags       = null;
                tRequestData.HttpMethod       = mContext.Request.HttpMethod; //NEW 3.200
                tRequestData.Header           = TheCommonUtils.cdeNameValueToDirectory(mContext.Request.Headers);
                tRequestData.ResponseMimeType = mContext.Request.ContentType;

                tRequestData.ClientCert = mContext.Request.GetClientCertificate();

                if (TheCommCore.MyHttpService != null && TheBaseAssets.MyServiceHostInfo.ClientCertificateUsage > 1) //If CDE requires a certificate, terminate all incoming requests before any processing
                {
                    var err = TheCommCore.MyHttpService.ValidateCertificateRoot(tRequestData);
                    if (TheBaseAssets.MyServiceHostInfo.DisableNMI && !string.IsNullOrEmpty(err))
                    {
                        mContext.Response.StatusCode = (int)eHttpStatusCode.NotAcceptable;
                        mContext.Response.OutputStream.Close();
                        return;
                    }
                }

                if (mContext.Request.InputStream != null)
                {
#if CDE_NET4 || CDE_NET45
                    using (MemoryStream ms = new MemoryStream())
                    {
                        mContext.Request.InputStream.CopyTo(ms);
                        tRequestData.PostData = ms.ToArray();
                    }
#else
                    byte[] buffer = new byte[TheBaseAssets.MAX_MessageSize[0]];
                    using (MemoryStream ms = new MemoryStream())
                    {
                        int read;
                        while ((read = mContext.Request.InputStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, read);
                        }
                        tRequestData.PostData = ms.ToArray();
                    }
#endif

                    tRequestData.PostDataLength = tRequestData.PostData.Length;
                }

                if (TheCommCore.MyHttpService != null)
                {
                    TheCommCore.MyHttpService.cdeProcessPost(tRequestData);
                }
            }
            catch (Exception e)
            {
                TheBaseAssets.MySYSLOG.WriteToLog(4350, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("HttpMidiServer", "ProcessRequest Error:" + firstRequestLine, eMsgLevel.l1_Error, e.ToString()));
                tRequestData.ResponseBuffer = TheCommonUtils.CUTF8String2Array(e.ToString());
                tRequestData.StatusCode     = (int)eHttpStatusCode.ServerError;
            }

            if ((tRequestData.ResponseBuffer == null && tRequestData.StatusCode != 200) || tRequestData.StatusCode == 404)    //NEW:UPNP
            {
                tRequestData.ResponseBufferStr  = "<html><head><meta http-equiv=\"Expires\" content=\"0\" /><meta http-equiv=\"Cache-Control\" content=\"no-cache\" /><meta http-equiv=\"Pragma\" content=\"no-cache\" /></html><body style=\"background-color: " + TheBaseAssets.MyServiceHostInfo.BaseBackgroundColor + ";\"><table width=\"100%\" style=\"height:100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td style=\"text-align:center;\"><p style=\"color: " + TheBaseAssets.MyServiceHostInfo.BaseForegroundColor + "; font-family: Arial; font-size: 36px\">";
                tRequestData.ResponseBufferStr += string.Format("Resource {0} not found", tRequestData.RequestUri);
                tRequestData.ResponseBufferStr += "</p></td></tr></table></body></HTML>";
                tRequestData.ResponseMimeType   = "text/html";
                tRequestData.ResponseBuffer     = TheCommonUtils.CUTF8String2Array(tRequestData.ResponseBufferStr);
                tRequestData.StatusCode         = (int)eHttpStatusCode.NotFound;
            }

            try
            {
                if (tRequestData.AllowStatePush && tRequestData.ResponseBuffer != null &&
                    (tRequestData.StatusCode == (int)eHttpStatusCode.OK || tRequestData.StatusCode == (int)eHttpStatusCode.PermanentMoved))
                {
                    if (tRequestData.SessionState != null && tRequestData.SessionState.StateCookies != null && tRequestData.SessionState.StateCookies.Count > 0)
                    {
                        string tCookie = "";
                        foreach (string nam in tRequestData.SessionState.StateCookies.Keys)
                        {
                            try
                            {
                                if (tCookie.Length > 0)
                                {
                                    tCookie += ";";
                                }
                                string[] cp = tRequestData.SessionState.StateCookies[nam].Split(';');
                                tCookie  = "";
                                tCookie += $"{nam}={cp[0]}; SameSite=none; Secure";
                                mContext.Response.Headers.Add(HttpResponseHeader.SetCookie, tCookie);
                            }
                            catch
                            {
                                //ignored
                            }
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(tRequestData.cdeRealPage) && tRequestData.cdeRealPage.StartsWith("/cdeClean", StringComparison.OrdinalIgnoreCase) &&
                        tRequestData.Header != null && tRequestData.Header.ContainsKey("Cookie"))
                    {
                        string cookieDate   = DateTime.UtcNow.AddMilliseconds(100).ToString("ddd, dd-MMM-yyyy H:mm:ss"); //Offset not needed
                        string cookieHeader = tRequestData.Header.cdeSafeGetValue("Cookie");
                        if (!string.IsNullOrEmpty(cookieHeader))
                        {
                            string        tCookie  = "";
                            List <string> tCookies = TheCommonUtils.CStringToList(cookieHeader, ';');
                            foreach (string t in tCookies)
                            {
                                if (tCookie.Length > 0)
                                {
                                    tCookie += ";";
                                }
                                string[] tc = t.Split('=');
                                tCookie += string.Format("{0}=;Path=/;Expires={1} GMT", tc[0], cookieDate);
                            }
                            mContext.Response.Headers.Add(HttpResponseHeader.SetCookie, tCookie);
                        }
                    }
                }

                if (!tRequestData.DontCompress)
                {
                    if (tRequestData.AllowCaching && !TheBaseAssets.MyServiceHostInfo.DisableCache)
                    {
                        mContext.Response.AddHeader("Cache-Control", $"max-age={TheBaseAssets.MyServiceHostInfo.CacheMaxAge}, public");
                    }
                    else
                    {
                        mContext.Response.AddHeader("Cache-Control", "no-cache");
                    }
                    mContext.Response.AddHeader("cdeDeviceID", TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString());
                    if (tRequestData.StatusCode > 300 && tRequestData.StatusCode < 400 && tRequestData.Header != null)
                    {
                        mContext.Response.AddHeader("Location", tRequestData.Header.cdeSafeGetValue("Location"));
                    }
                }
                else
                {
                    mContext.Response.Headers.Clear();
                }

                mContext.Response.Headers.Set(HttpResponseHeader.Server, "C-DEngine V4");
                if (TheBaseAssets.MyServiceHostInfo.IsSSLEnforced)
                {
                    mContext.Response.Headers.Set("Strict-Transport-Security", "max-age=298000; includeSubDomains; preload"); //HSTS Header for SSL sites...test still required
                    mContext.Response.Headers.Set("X-Frame-Options", "sameorigin");                                           //iFrame protection Header for SSL sites...test still required
                }

                var tCors = TheBaseAssets.MySettings.GetSetting("Access-Control-Allow-Origin");
                if (!string.IsNullOrEmpty(tCors))
                {
                    mContext.Response.AppendHeader("Access-Control-Allow-Origin", tCors);
                }
                if (!string.IsNullOrEmpty(tRequestData.AllowedMethods))
                {
                    mContext.Response.AppendHeader("Access-Control-Allow-Methods", tRequestData.AllowedMethods);
                }
                if (!string.IsNullOrEmpty(tRequestData.AllowedMethods))
                {
                    mContext.Response.AppendHeader("Access-Control-Allow-Headers", tRequestData.AllowedHeaders);
                }

                mContext.Response.StatusCode = tRequestData.StatusCode;
                if (tRequestData.StatusCode != 200)
                {
                    TheCDEKPIs.IncrementKPI(eKPINames.BruteDelay);
                    //Security Fix: ID#770 - wait 200 ms before returning anything with error code to limit BruteForce
                    TheCommonUtils.SleepOneEye(200, 100);
                }
                mContext.Response.ContentType = tRequestData.ResponseMimeType;

                if (tRequestData.ResponseBuffer != null)
                {
                    if (!tRequestData.DontCompress && (TheBaseAssets.MyServiceHostInfo.IsOutputCompressed || (tRequestData.Header != null && tRequestData.Header.ContainsKey("Accept-Encoding") && tRequestData.Header["Accept-Encoding"].Contains("gzip"))))
                    {
                        byte[] bBuffer = TheCommonUtils.cdeCompressBuffer(tRequestData.ResponseBuffer, 0, tRequestData.ResponseBuffer.Length);
                        mContext.Response.AddHeader("Content-Encoding", "gzip");
                        mContext.Response.ContentLength64 = bBuffer.Length;
                        mContext.Response.OutputStream.Write(bBuffer, 0, bBuffer.Length);
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(tRequestData.ResponseEncoding))
                        {
                            mContext.Response.AddHeader("Content-Encoding", tRequestData.ResponseEncoding);
                        }
                        mContext.Response.ContentLength64 = tRequestData.ResponseBuffer.Length;
                        mContext.Response.OutputStream.Write(tRequestData.ResponseBuffer, 0, tRequestData.ResponseBuffer.Length);
                    }
                }
                if (tRequestData.DisableChunking)
                {
                    mContext.Response.SendChunked = false;
                }
                if (tRequestData.DisableKeepAlive)
                {
                    mContext.Response.KeepAlive = false;
                }
                mContext.Response.OutputStream.Close();
            }
            catch (Exception ee)
            {
                TheBaseAssets.MySYSLOG.WriteToLog(4351, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM("HttpMidiServer", "HttpWriteResponse Error", eMsgLevel.l1_Error, ee.ToString()));
            }
        }
Exemple #8
0
        private bool WriteLogToFile(TheEventLogData pLogItem, bool WaitForLock)
        {
            if (pLogItem == null || string.IsNullOrEmpty(pLogItem.EventCategory))
            {
                return(false);
            }
            if (mWriteToConsole)
            {
                Console.WriteLine($"{pLogItem.EventCategory} : {TheCommonUtils.GetDateTimeString(pLogItem.EventTime, -1)} : {pLogItem.EventName} : {pLogItem.EventString}");
            }
            if (string.IsNullOrEmpty(mLogFilePath) && string.IsNullOrEmpty(TheThing.GetSafePropertyString(MyBaseThing, "LogFilePath")))
            {
                return(false);
            }

            if (EachCategoryInOwnFile)
            {
                //TODO: Tune with array of EventCategory Log file names
                //MyCurLog = mLogFilePath + string.Format("\\{1}_{0:yyyMMdd_HHmmss}.txt", DateTime.Now,pLogItem.EventCategory);
                //MyCurLog = TheCommonUtils.cdeFixupFileName(MyCurLog);
                //TheCommonUtils.CreateDirectories(MyCurLog);
            }
            if (EachDayInOwnFile && mLogFileDate.Day != DateTimeOffset.Now.Day)
            {
                LogFilePath = MyCurLog = TheCommonUtils.cdeFixupFileName(mLogFilePath + string.Format("\\LOG_{0:yyyMMdd_HHmmss}.txt", DateTime.Now));
                LogFileDate = mLogFileDate = DateTimeOffset.Now;
            }
            // ReSharper disable once EmptyEmbeddedStatement
            if (WaitForLock)
            {
                while (TheCommonUtils.cdeIsLocked(writeLock))
                {
                    TheCommonUtils.SleepOneEye(50, 50);
                }
            }
            if (!TheCommonUtils.cdeIsLocked(writeLock))
            {
                lock (writeLock)
                {
                    var bLogFileExists = System.IO.File.Exists(MyCurLog);
                    if (mMaxLogFileSize > 0 && bLogFileExists)
                    {
                        try
                        {
                            System.IO.FileInfo f2 = new System.IO.FileInfo(MyCurLog);
                            if (f2.Length > mMaxLogFileSize * (1024 * 1024))
                            {
                                MyCurLog    = LogFilePath = TheCommonUtils.cdeFixupFileName(mLogFilePath + string.Format("\\LOG_{0:yyyMMdd_HHmmss}.txt", DateTime.Now));
                                LogFileDate = mLogFileDate = DateTimeOffset.Now;
                            }
                        }
                        catch
                        {
                            //ignored
                        }
                        bLogFileExists = System.IO.File.Exists(MyCurLog);
                    }
                    try
                    {
                        using (System.IO.StreamWriter fs = new System.IO.StreamWriter(MyCurLog, bLogFileExists))
                        {
                            if (EachCategoryInOwnFile)
                            {
                                fs.WriteLine($"{pLogItem.EventTime} : {TheCommonUtils.GetDateTimeString(pLogItem.EventTime, -1)} : {pLogItem.EventString}");
                            }
                            else
                            {
                                fs.WriteLine($"{pLogItem.EventCategory} : {TheCommonUtils.GetDateTimeString(pLogItem.EventTime,-1)} : {pLogItem.EventName} : {pLogItem.EventString}");
                            }
                        }
                    }
                    catch
                    {
                        //ignored
                    }
                }
            }
            return(true);
        }
Exemple #9
0
        public void GetDevices(Uri pDeviceURL = null, string tPost = null, cdeConcurrentDictionary <string, string> addHeader = null)
        {
            if (!IsConnected || !TheBaseAssets.MasterSwitch)
            {
                return;
            }
            if (pDeviceURL != null)
            {
                mDeviceUrl = pDeviceURL;
            }
            if (tPost != null)
            {
                mDevicePost = tPost;
            }
            if (addHeader != null)
            {
                mAddHeader = addHeader;
            }
            if (mDevicePost == null)
            {
                TheRequestData tRequest = new TheRequestData
                {
                    RequestUri     = mDeviceUrl,
                    RequestCookies = MyRequestData?.SessionState?.StateCookies
                };
                if (mAddHeader != null)
                {
                    tRequest.Header = new cdeConcurrentDictionary <string, string>();
                    foreach (string key in mAddHeader.Keys)
                    {
                        tRequest.Header.TryAdd(key, mAddHeader[key]);
                    }
                }
                TheREST.GetRESTAsync(tRequest, ParseDevices, sinkError);
            }
            else
            {
                MyRequestData.RequestUri = mDeviceUrl; // new Uri("https://ptdevices.com/device/all");
                //tPost = $"_token={WebSocketSharp.Ext.UrlEncode(mToken)}";
                MyRequestData.PostData   = TheCommonUtils.CUTF8String2Array(mDevicePost);
                MyRequestData.HttpMethod = "POST";
                MyRequestData.Header     = null;
                if (mAddHeader != null)
                {
                    MyRequestData.Header = new cdeConcurrentDictionary <string, string>();
                    foreach (string key in mAddHeader.Keys)
                    {
                        MyRequestData.Header.TryAdd(key, mAddHeader[key]);
                    }
                }

                MyRequestData.RequestCookies   = MyRequestData?.SessionState?.StateCookies;
                MyRequestData.ResponseMimeType = mPostMimeType; // "application/x-www-form-urlencoded; charset=UTF-8";
                while (MyRest.IsPosting > 1 && IsConnected)
                {
                    TheCommonUtils.SleepOneEye(1000, 100);
                }
                if (IsConnected)
                {
                    MyRest.PostRESTAsync(MyRequestData, ParseDevices, sinkError);
                }
            }
        }
Exemple #10
0
        public void TheRESTSenderThread()
        {
            if (IsSenderThreadRunning)
            {
                return;
            }
            try
            {
                TheDiagnostics.SetThreadName($"QSender:{MyTargetNodeChannel} SenderThread", true);
                MyREST = new TheREST();
                IsSenderThreadRunning = true;
                StringBuilder tSendBufferStr = new StringBuilder(TheBaseAssets.MyServiceHostInfo?.IsMemoryOptimized == true ? 1024 : TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2);
                TargetUri     = TheCommonUtils.CUri(MyTargetNodeChannel.TargetUrl, true);
                TargetUriPath = TargetUri.AbsolutePath;

                int QDelay = TheCommonUtils.CInt(TheBaseAssets.MySettings.GetSetting("ThrottleWS"));
                if (QDelay < 2)
                {
                    QDelay = 2;
                }
                if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON && TheBaseAssets.MyServiceHostInfo.WsJsThrottle > QDelay)
                {
                    QDelay = TheBaseAssets.MyServiceHostInfo.WsJsThrottle;
                }
                mre = new ManualResetEvent(false);
                if (eventSenderThreadRunning != null)
                {
                    TheCommonUtils.cdeRunAsync("EventSenderThreadRunning", true, (p) => { eventSenderThreadRunning(this); });
                }
                MyISBlock?.FireEvent("SenderThreadCreated");
                while (TheBaseAssets.MasterSwitch && IsAlive && IsSenderThreadRunning)
                {
                    if (QDelay > 2)
                    {
                        mre.WaitOne(QDelay);    //Throtteling should be here not in the wait loop
                    }
                    int WaitCounter = 0;
                    while (TheBaseAssets.MasterSwitch && IsAlive && IsSenderThreadRunning && ((MyCoreQueue.Count == 0 && IsConnected) || IsConnecting || IsInPost || MyREST.IsPosting > (IsConnected?TheBaseAssets.MyServiceHostInfo.ParallelPosts:0)))
                    {
                        // CODE REVIEW: This was seen looping after service route to local node was closed (due to node shutdown): IsCOnnecting/IsConnected/IsInPost were false; ISAlive true. MyREST.IsPosting was 8. Queue count ~345
                        //              This should be fixed now with IsSenderThreadRunning in the loop (I was wrong :) this happens only with cloud connections where POST fails and the IsPosting was not reset properly).
                        // Update: If found the same problem. Sometime IsPosting is not reduced properly when a Timeout or other error occured during Posting
                        if (IsInPost && MyCoreQueue.Count > 100)
                        {
                            TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"IsInPost was still on and has been reset for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l2_Warning));
                            IsInPost = false;
                        }
                        if (!IsConnected)
                        {
                            if (IsConnecting && MyREST.IsPosting == 0)
                            {
                                TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"IsConnecting is set but no Pending Post {MyTargetNodeChannel?.ToMLString()} - resetting IsConnecting", eMsgLevel.l2_Warning));
                                IsConnecting = false;
                            }
                            if (!IsConnecting && MyREST.IsPosting > (IsConnected ? 10 : 0))
                            {
                                WaitCounter++;
                                if (WaitCounter > (10000 / QDelay))
                                {
                                    TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"MyREST.IsPosting ({MyREST.IsPosting}) was higher then expected...possible POST problem. Resetting POST Counter for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l2_Warning));
                                    MyREST.IsPosting = 0;
                                }
                            }
                        }

                        mre.WaitOne(QDelay);
                    }
                    if (!TheBaseAssets.MasterSwitch || !IsAlive || !IsSenderThreadRunning)
                    {
                        IsInPost = false;
                        break;
                    }
                    IsInPost = true;
                    if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_BACKCHANNEL ||
                        MyTargetNodeChannel.SenderType == cdeSenderType.CDE_PHONE ||
                        MyTargetNodeChannel.SenderType == cdeSenderType.CDE_DEVICE ||
                        MyTargetNodeChannel.SenderType == cdeSenderType.CDE_JAVAJASON)
                    {
                        TheBaseAssets.MySYSLOG.WriteToLog(235, new TSM("QueuedSender", $"QSender Should NEVER GO HERE because SenderType is {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l1_Error));
                        IsInPost = false;
                        IsSenderThreadRunning = false;
                        return;
                    }
                    //NEW3.124: Sender Loop has to terminate if Cloud was Disabled.
                    if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE && (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri)))  //ServiceRoute can contain multiple routes...
                    {
                        break;
                    }
                    TheCoreQueueContent tQueued = null;
                    int MCQCount  = 0;
                    int IsBatchOn = 0;
#if CDE_NET35
                    tSendBufferStr = new StringBuilder(TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType] * 2);
#else
                    tSendBufferStr.Clear();
#endif
                    tSendBufferStr.Append("[");
                    byte[] BinSendBuffer = null;
                    do
                    {
                        if (!IsConnected)
                        {
                            tQueued        = new TheCoreQueueContent();
                            IsConnecting   = true;
                            ConnectRetries = 0;
                            if (CloudInRetry)
                            {
                                var count = Interlocked.Increment(ref CloudRetryCount);
                                if (count > 10)
                                {
                                    int delaySeconds = TheBaseAssets.MyServiceHostInfo.HeartbeatDelay * TheBaseAssets.MyServiceHostInfo.TO.HeartBeatRate;
                                    TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("QueuedSender", $"Too many retries for {MyTargetNodeChannel?.ToMLString()}: {count}. Waiting {delaySeconds} seconds.", eMsgLevel.l2_Warning));
                                    TheCommonUtils.SleepOneEye((uint)delaySeconds * 1000, 100);
                                    Interlocked.Exchange(ref CloudRetryCount, 0);
                                }
                                if (!TheBaseAssets.MasterSwitch || !IsAlive || !IsSenderThreadRunning || (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE &&
                                                                                                          (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri))))
                                {
                                    //Very rare but required after Sleep
                                    throw new Exception("QSender had to be terminated in Cloud Retry due to disabling of ServiceRoute or C-DEngine Shutdown");
                                }
                            }//NEW3.124: Sender Loop has to terminate if Cloud was Disabled.
                            if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE && (TheBaseAssets.MyServiceHostInfo.IsCloudDisabled || string.IsNullOrEmpty(TheBaseAssets.MyServiceHostInfo.ServiceRoute) || !TheBaseAssets.MyServiceHostInfo.HasServiceRoute(TargetUri)))
                            {
                                break;
                            }
                        }
                        else
                        {
                            if (CloudInRetry)
                            {
                                CloudInRetry = false;
                                IsInPost     = false;
                                continue;
                            }
                            tQueued = GetNextMessage(out MCQCount);
                        }
                        if (tQueued != null)
                        {
                            TheCDEKPIs.IncrementKPI(eKPINames.QSSent);

                            if (tQueued.OrgMessage == null && !IsConnecting)
                            {
                                if (MySubscriptions.Count == 0)
                                {
                                    if (IsBatchOn == 0) //Only jump out if no telegrams are in batch..
                                    {
                                        IsInPost = false;
                                        continue;
                                    }
                                }
                                if (IsBatchOn == 0) //If telegrams are in the batch dont send short message
                                {
                                    BinSendBuffer    = new byte[1];
                                    BinSendBuffer[0] = (byte)((int)(TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType)).ToString()[0];
                                    break;
                                }
                            }
                            if (tQueued.OrgMessage != null && tQueued.OrgMessage.ToCloudOnly() && MyTargetNodeChannel.SenderType == cdeSenderType.CDE_CLOUDROUTE)
                            {
                                tQueued.OrgMessage.SetToCloudOnly(false);
                            }

                            TheDeviceMessage tDev = new TheDeviceMessage
                            {
                                DID = TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString() // MyTargetNodeChannel.cdeMID.ToString();
                            };

                            if (MyTargetNodeChannel.MySessionState != null)
                            {
                                //BUGFIX: After fast Cloud Disconnect/reconnect-Relay lost Scopeing because it Scope was not properly stored in SessionState
                                if (string.IsNullOrEmpty(MyTargetNodeChannel.MySessionState.SScopeID) && TheBaseAssets.MyScopeManager.IsScopingEnabled)
                                {
                                    MyTargetNodeChannel.MySessionState.SScopeID = TheBaseAssets.MyScopeManager.GetScrambledScopeID();       //GRSI: rare
                                }
                                if (TheBaseAssets.MyServiceHostInfo.EnableFastSecurity)
                                {
                                    tDev.SID = MyTargetNodeChannel.MySessionState.SScopeID;
                                }
                                else
                                {
                                    tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(MyTargetNodeChannel.MySessionState.SScopeID, false); //GRSI: high frequency!
                                }
                            }
                            else
                            {
                                tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID();      //GRSI: rare
                            }
                            tDev.MSG = tQueued.OrgMessage;
                            tDev.FID = "1";
                            if (IsConnecting)
                            {
                                tDev.TOP = TheCommCore.SetConnectingBufferStr(MyTargetNodeChannel, null);
                            }
                            else
                            {
                                tDev.TOP = tQueued.Topic;
                                tQueued.OrgMessage?.GetNextSerial(tQueued.SubMsgCnt);
                                if (MyTargetNodeChannel.MySessionState != null)
                                {
                                    tDev.FID = MyTargetNodeChannel.MySessionState.GetNextSerial().ToString(); //(SendCounter + 1).ToString();    //V3B3: New was empty //V4.1010: Same as WS now
                                }
                            }

                            #region Batch Serialization
                            IsBatchOn++;
                            if (MCQCount == 0 || IsBatchOn > TheBaseAssets.MyServiceHostInfo.MaxBatchedTelegrams || tQueued.IsChunked)
                            {
                                if (MCQCount != 0)
                                {
                                    tDev.CNT = MCQCount;
                                }
                                IsBatchOn = 0;
                            }
                            else
                            {
                                if (tSendBufferStr.Length > TheBaseAssets.MAX_MessageSize[(int)MyTargetNodeChannel.SenderType])
                                {
                                    tDev.CNT  = MCQCount;
                                    IsBatchOn = 0;
                                }
                            }
                            if (tSendBufferStr.Length > 1)
                            {
                                tSendBufferStr.Append(",");
                            }
                            tSendBufferStr.Append(TheCommonUtils.SerializeObjectToJSONString(tDev));
                            #endregion
                        }
                        else
                        {
                            IsBatchOn = 0;
                        }
                    } while (IsBatchOn > 0 && IsInPost && TheBaseAssets.MasterSwitch);
                    if ((!IsInPost || tSendBufferStr.Length < 2) && BinSendBuffer == null)
                    {
                        IsInPost = false;
                        continue;
                    }

                    string tMimeType = "application/octet-stream";
                    if (BinSendBuffer == null)
                    {
                        tSendBufferStr.Append("]");
                        if (MyTargetNodeChannel.SenderType == cdeSenderType.CDE_MINI || TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType == cdeSenderType.CDE_MINI)
                        {
                            tMimeType     = "application/json";
                            BinSendBuffer = TheCommonUtils.CUTF8String2Array(tSendBufferStr.ToString());
                        }
                        else
                        {
                            tMimeType     = "application/x-gzip";
                            BinSendBuffer = TheCommonUtils.cdeCompressString(tSendBufferStr.ToString());
                        }
                    }
                    if (MyTargetNodeChannel == null)
                    {
                        TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("QueuedSender", $"Channel was deleted - exiting SenderThread", eMsgLevel.l2_Warning));
                        IsInPost = false;
                        break;
                    }
                    string         ISBPath = new Uri(TargetUri, TheBaseAssets.MyScopeManager.GetISBPath(TargetUriPath, TheCommonUtils.GetOriginST(MyTargetNodeChannel), MyTargetNodeChannel.SenderType, MyTargetNodeChannel.MySessionState == null? 1: MyTargetNodeChannel.MySessionState.FID /*Interlocked.Increment(ref SendCounter)*/, (MyTargetNodeChannel.MySessionState == null || !IsConnected) ?Guid.Empty: MyTargetNodeChannel.MySessionState.cdeMID, MyTargetNodeChannel.IsWebSocket)).ToString(); //V3B4: changed from TheBaseAssets.MyServiceHostInfo.MyDeviceInfo
                    TheRequestData pData   = new TheRequestData
                    {
                        RemoteAddress    = TheBaseAssets.MyServiceHostInfo.GetPrimaryStationURL(false),
                        RequestUri       = new Uri(ISBPath),
                        PostData         = BinSendBuffer,
                        ResponseMimeType = tMimeType,
                        DeviceID         = TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID,
                        HttpMethod       = "POST"
                    };
                    if (!TheCertificates.SetClientCert(pData, MyTargetNodeChannel?.ClientCertificateThumb))
                    {
                        throw new Exception("Client Certificate could not be added");
                    }
                    MyREST.PostRESTAsync(pData, sinkUploadDataCompleted, FireSenderProblem);
                    if (BinSendBuffer != null)
                    {
                        TheCDEKPIs.IncrementKPI(eKPINames.QKBSent, BinSendBuffer.Length);
                    }

                    IsInPost = false;
                }
                FlushQueue();
                TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM("QueuedSender", $"QSenderThread was closed for {MyTargetNodeChannel?.ToMLString()}", eMsgLevel.l6_Debug));
            }
            catch (Exception e)
            {
                IsInPost = false;
                TheBaseAssets.MySYSLOG.WriteToLog(235, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("QueuedSender", "Exception in jcSenderThread.", eMsgLevel.l1_Error, "Error:" + e));
                if (MyTargetNodeChannel?.SenderType != cdeSenderType.CDE_BACKCHANNEL)
                {
                    FireSenderProblem(new TheRequestData()
                    {
                        ErrorDescription = $"1308:{e}"
                    });
                }
            }
            finally
            {
                IsSenderThreadRunning = false;
                IsAlive      = false;
                IsInPost     = false;
                CloudInRetry = false;
                StopHeartBeat();
            }
        }
        public void CreateOPCWizard()
        {
            TheFieldInfo tTargetButton = null;
            var          flds          = TheNMIEngine.AddNewWizard <TheOPCSetClass>(new Guid("{56565656-6AD1-45AE-BE61-96AF02329614}"), Guid.Empty, TheNMIEngine.GetEngineDashBoardByThing(MyBaseThing).cdeMID, "Welcome to the OPC Wizard",
                                                                                    new nmiCtrlWizard {
                PanelTitle = "<i class='fa faIcon fa-3x'>&#xf0d0;</i></br>New OPC Client", SideBarTitle = "New OPC Client Wizard", SideBarIconFA = "&#xf545;", TileThumbnail = "FA5:f545"
            },
                                                                                    (myClass, pClientInfo) =>
            {
                myClass.cdeMID   = Guid.Empty;
                TheThing tMemTag = null;
                if (myClass.CreateMemoryTag)
                {
                    var tReq = new TheThingRegistry.MsgCreateThingRequestV1()
                    {
                        EngineName       = "CDMyVThings.TheVThings",
                        DeviceType       = "Memory Tag",
                        FriendlyName     = myClass.ClientName,
                        OwnerAddress     = MyBaseThing,
                        InstanceId       = Guid.NewGuid().ToString(),
                        CreateIfNotExist = true
                    };
                    tMemTag = TheThingRegistry.CreateOwnedThingAsync(tReq).Result;
                }

                var tOPCReq = new TheThingRegistry.MsgCreateThingRequestV1()
                {
                    EngineName       = "CDMyOPCUAClient.cdeOPCUaClient",
                    DeviceType       = "OPC-UA Remote Server",
                    FriendlyName     = myClass.ClientName,
                    Address          = myClass.OPCAddress,
                    OwnerAddress     = MyBaseThing,
                    InstanceId       = Guid.NewGuid().ToString(),
                    CreateIfNotExist = true
                };
                tOPCReq.Properties = new Dictionary <string, object>();
                //tOPCReq.Properties["ID"] = Guid.NewGuid().ToString();
                tOPCReq.Properties["AutoConnect"]     = myClass.AutoConnect;
                tOPCReq.Properties["SendOpcDataType"] = true;
                if (!myClass.DisableSecurity)
                {
                    tOPCReq.Properties["DisableSecurity"]            = true;
                    tOPCReq.Properties["AcceptUntrustedCertificate"] = true;
                    tOPCReq.Properties["DisableDomainCheck"]         = true;
                    tOPCReq.Properties["AcceptInvalidCertificate"]   = true;
                    tOPCReq.Properties["Anonymous"] = true;
                }
                if (tMemTag != null)
                {
                    tOPCReq.Properties["TagHostThingForSubscribeAll"] = tMemTag.cdeMID;
                }
                var tOPCServer = TheThingRegistry.CreateOwnedThingAsync(tOPCReq).Result;
                try
                {
                    if (tOPCServer != null && myClass.Prop2Tag && myClass.AutoConnect)
                    {
                        var response = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAConnect, MsgOPCUAConnectResponse>(MyBaseThing, tOPCServer, new MsgOPCUAConnect {
                            LogEssentialOnly = true, WaitUntilConnected = true
                        }).Result;
                        if (response != null && string.IsNullOrEmpty(response.Error))
                        {
                            var tBrowseResponse = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUABrowse, MsgOPCUABrowseResponse>(MyBaseThing, tOPCServer, new MsgOPCUABrowse()).Result;
                            if (string.IsNullOrEmpty(tBrowseResponse.Error))
                            {
                                TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", $"OPC UA Client browse error: {tBrowseResponse.Error}"));
                                return;
                            }
                            else
                            {
                                List <MsgOPCUACreateTags.TagInfo> tTagList = tBrowseResponse.Tags;
                                if (tTagList != null && tTagList.Count > 0)
                                {
                                    var tres = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUACreateTags, MsgOPCUACreateTagsResponse>(MyBaseThing, tOPCServer, new MsgOPCUACreateTags {
                                        Tags = tTagList, BulkApply = true
                                    }).Result;
                                    if (tres != null && string.IsNullOrEmpty(tres.Error))
                                    {
                                        TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "OPC UA Client Created and memory tag ready"));
                                    }
                                }
                            }
                        }
                    }
                    TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "OPC UA Client Created and ready"));
                }
                catch (Exception)
                {
                    TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "Something went wrong! Check the OPC and Memory Tag settings"));
                }
                tTargetButton.SetUXProperty(pClientInfo.NodeID, $"OnClick=TTS:{tOPCServer.GetBaseThing().cdeMID}");
                TheCommonUtils.SleepOneEye(2000, 100);
            });

            var tMyForm2 = flds["Form"] as TheFormInfo;

            var tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 0, 1, 2, null /*"Name and Address"*/);

            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleEnded, 1, 1, 2, 0, "Connection Name", "ClientName", new TheNMIBaseControl {
                Explainer = "1. Enter name for the new OPC connection.",
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleEnded, 1, 2, 2, 0, "OPC Server Address", "OPCAddress", new TheNMIBaseControl {
                Explainer = "1. Enter address of the OPC server.",
            });

            tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 1, 2, 3, null /* "Settings"*/);
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 1, 2, 0, "OPC Server requires Security", "DisableSecurity", new nmiCtrlSingleCheck {
                Explainer = "Check if the OPC Server requires security"
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 2, 2, 0, "Create a Memory Tag", "CreateMemoryTag", new nmiCtrlSingleCheck {
                TileWidth = 3, Explainer = "Check to create a Memory Tag and check to subscribes all Tags into it"
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 3, 2, 0, "All Tags in Memory Tag", "Prop2Tag", new nmiCtrlSingleCheck {
                TileWidth = 3
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 4, 2, 0, "Auto Connect to Server", "AutoConnect", new nmiCtrlSingleCheck {
                TileWidth = 3, Explainer = "Don't select this if your server requires security settings"
            });

            tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 2, 3, 0, null /*"Final Settings"*/);
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 3, 2, 0, 0, null, null, new nmiCtrlSmartLabel {
                Text = "Once you click finish, the Wizard will create the items you requested. It will notify you with a toast when its done", TileHeight = 5, TileWidth = 7, NoTE = true
            });
            //HELP SECTION final step help section

            TheNMIEngine.AddWizardProcessPage(MyBaseThing, tMyForm2, 4);
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 4, 1, 0, 0, null, null, new nmiCtrlSmartLabel {
                NoTE = true, TileWidth = 7, Text = "Creating the new instance..please wait", TileHeight = 2
            });

            TheNMIEngine.AddWizardFinishPage(MyBaseThing, tMyForm2, 5);
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 5, 1, 0, 0, null, null, new nmiCtrlSmartLabel {
                NoTE = true, TileWidth = 7, Text = "Done...what do you want to do next?", TileHeight = 2
            });

            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileGroup, 5, 2, 0, 0, null, null, new nmiCtrlTileGroup {
                TileWidth = 1, TileHeight = 2, TileFactorX = 2
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileButton, 5, 3, 2, 0, "Go to Dashboard", null, new nmiCtrlTileButton {
                NoTE = true, TileHeight = 2, TileWidth = 3, OnClick = $"TTS:{mMyDashboard.cdeMID}", ClassName = "cdeTransitButton"
            });
            TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileGroup, 5, 4, 0, 0, null, null, new nmiCtrlTileGroup {
                TileWidth = 1, TileHeight = 2
            });
            tTargetButton = TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileButton, 5, 5, 2, 0, "Go to New OPC Client", null, new nmiCtrlTileButton {
                NoTE = true, TileHeight = 2, TileWidth = 3, ClassName = "cdeTransitButton"
            });
        }
Exemple #12
0
        static void sinkReady()
        {
            Debug.WriteLine("Registering events for engine... ");

            TheCDEngines.MyContentEngine.RegisterEvent(eEngineEvents.IncomingMessage, sinkIncoming);
            if (TheCDEngines.MyNMIService != null)
            {
                TheCDEngines.MyNMIService.RegisterEvent(eEngineEvents.IncomingMessage, sinkIncoming);
                //TheCDEngines.MyContentEngine.RegisterEvent(eEngineEvents.ChannelConnected, sinkEstablished);
            }
            TheCommonUtils.cdeRunAsync("LoopDiDoop", true, (o) =>
            {
                TheThing tTimer    = null;
                TheThing GoogleDNS = null;
                TheThing ThingBar  = null;
                while (TheBaseAssets.MasterSwitch)
                {
                    TheCommonUtils.SleepOneEye(5000, 100);

                    if (ThingBar == null)
                    {
                        ThingBar = TheThingRegistry.GetThingByProperty("*", Guid.Empty, "FriendlyName", "ThingBar");
                        if (ThingBar != null)
                        {
                            TheThingRegistry.RegisterEventOfThing(ThingBar, eThingEvents.ValueChanged, (sender, para) =>
                            {
                                TSM tTSM2 = new TSM(eEngineName.ContentService, "UNITY:GAUGE", para.ToString());
                                TheCommCore.PublishCentral(tTSM2);
                            });
                        }
                    }
                    if (tTimer == null)
                    {
                        tTimer = TheThingRegistry.GetThingByProperty("*", Guid.Empty, "DeviceType", "Timer");
                        if (tTimer != null)
                        {
                            TheThingRegistry.RegisterEventOfThing(tTimer, eThingEvents.ValueChanged, (sender, para) =>
                            {
                                TSM tTSM2 = new TSM(eEngineName.ContentService, "UNITY:TIMER", para.ToString());
                                TheCommCore.PublishCentral(tTSM2);
                            });
                        }
                    }
                    if (GoogleDNS == null)
                    {
                        GoogleDNS = TheThingRegistry.GetThingByProperty("*", Guid.Empty, "FriendlyName", "Google DNS");
                        if (GoogleDNS != null)
                        {
                            TheThingRegistry.RegisterEventOfThing(GoogleDNS, eThingEvents.PropertyChanged, (sender, para) =>
                            {
                                cdeP tP = para as cdeP;
                                if (tP != null && tP.Name == "RoundTripTime")
                                {
                                    TSM tTSM2 = new TSM(eEngineName.ContentService, "UNITY:HEART", para.ToString());
                                    TheCommCore.PublishCentral(tTSM2);
                                }
                            });
                        }
                    }
                    if (GoogleDNS != null && tTimer != null && ThingBar != null)
                    {
                        break;
                    }
                }
            });
        }