Ejemplo n.º 1
0
        internal static void SetResponseBuffer(TheRequestData pRequestData, TheChannelInfo pChannelInfo, bool pSendPulse, string NopTopic, Guid owner, string pRefreshToken)
        {
            if (string.IsNullOrEmpty(NopTopic))
            {
                TheQueuedSender tQ = null;
                if (pChannelInfo != null && pChannelInfo.cdeMID != Guid.Empty)    //Send to Device First
                {
                    tQ = TheQueuedSenderRegistry.GetSenderByGuid(pChannelInfo.cdeMID);
                }
                if (tQ != null)
                {
                    if (pRequestData.WebSocket != null)
                    {
                        if (tQ.GetQueLength() == 0)
                        {
                            tQ.SendPickupMessage();
                        }
                        return;
                    }
                    tQ.GetNextBackChannelBuffer(pRequestData);
                }
            }
            if (string.IsNullOrEmpty(NopTopic) && pRequestData.WebSocket != null)
            {
                return;                                                                   //NEW:3.084  && !pSendPulse removed          NEW:V3B3:2014-7-22 removed && pRequestData.ResponseBuffer != null
            }
            if (pRequestData.ResponseBuffer == null && pChannelInfo != null && (pSendPulse || (pChannelInfo.cdeMID != Guid.Empty || TheQueuedSenderRegistry.IsNodeIdInSenderList(pChannelInfo.cdeMID))))
            {
                TheDeviceMessage tDev = new TheDeviceMessage {
                    CNT = 0
                };
                //tDev.MET = 0;
                if (!string.IsNullOrEmpty(NopTopic))
                {
                    tDev.MSG = new TSM();   //Can be set without ORG and SID
                    if (owner != Guid.Empty)
                    {
                        tDev.MSG.OWN = owner.ToString();
                    }
                    if (NopTopic == "CDE_WSINIT")
                    {
                        NopTopic = TheCommCore.SetConnectingBufferStr(pChannelInfo, null);
                    }
                }
                if (pChannelInfo.SenderType != cdeSenderType.CDE_JAVAJASON) //4.209: No longer sending SID to Browser;
                {
                    if (TheBaseAssets.MyServiceHostInfo.EnableFastSecurity)
                    {
                        tDev.SID = pRequestData.SessionState.SScopeID;  //SECURITY: All responses will have same Scrambled ScopeID - but ok because this is init telegram or HB
                    }
                    else
                    {
                        tDev.SID = TheBaseAssets.MyScopeManager.GetScrambledScopeID(pRequestData.SessionState.SScopeID, false); //GRSI: high frequency
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(pRefreshToken))
                    {
                        tDev.SID = pRefreshToken;
                    }
                }
                tDev.FID = pRequestData.SessionState.GetNextSerial().ToString();
                if (TheCommonUtils.IsDeviceSenderType(pChannelInfo.SenderType)) //IDST-OK: Must create RSA for Devices
                {
                    TheCommonUtils.CreateRSAKeys(pRequestData.SessionState);
                    tDev.RSA = pRequestData.SessionState.RSAPublic;
                }
                tDev.NPA = TheBaseAssets.MyScopeManager.GetISBPath(TheBaseAssets.MyServiceHostInfo.RootDir, pChannelInfo.SenderType, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType, pRequestData.SessionState.FID, pRequestData.SessionState.cdeMID, pRequestData.WebSocket != null);
                tDev.CNT = pSendPulse ? 1 : 0;
                tDev.TOP = NopTopic;
                tDev.DID = pChannelInfo.SenderType == cdeSenderType.CDE_JAVAJASON ? pChannelInfo.cdeMID.ToString() : TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString();

                //There will be only one Message here - single poke or Mini Command or NOP Pickup
                List <TheDeviceMessage> tDevList = new List <TheDeviceMessage> {
                    tDev
                };
                if (pChannelInfo.SenderType == cdeSenderType.CDE_JAVAJASON || TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.SenderType == cdeSenderType.CDE_MINI || pChannelInfo.SenderType == cdeSenderType.CDE_MINI || pRequestData.WebSocket != null)
                {
                    pRequestData.ResponseBuffer   = TheCommonUtils.CUTF8String2Array(TheCommonUtils.SerializeObjectToJSONString(tDevList));
                    pRequestData.ResponseMimeType = "application/json";
                }
                else
                {
                    pRequestData.ResponseBuffer   = TheCommonUtils.cdeCompressString(TheCommonUtils.SerializeObjectToJSONString(tDevList));
                    pRequestData.ResponseMimeType = "application/x-gzip";
                }
            }
            if (pRequestData.ResponseBuffer == null && pChannelInfo != null && pChannelInfo.cdeMID != Guid.Empty)
            {
                TheBaseAssets.MySYSLOG.WriteToLog(290, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM("CoreComm", $"Nothing to Send Back to {pChannelInfo?.ToMLString()}", eMsgLevel.l7_HostDebugMessage));
            }
        }
Ejemplo n.º 2
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();
            }
        }