예제 #1
0
        private static BValue Select(string category, string path, BValue localeRoot)
        {
            var section = localeRoot[category];

            if (section is null)
            {
                return(null);
            }

            var current = 0;

            while (true)
            {
                var len = path.IndexOf('.', current);

                string key;

                if (len < 0)
                {
                    //dot in path not found, final key
                    key = path.Substring(current);
                    return(section[key]);
                }
                key     = path.Substring(current, len);
                section = section[key];
                if (section is null)
                {
                    return(null);
                }
                current = len + 1;
            }
        }
        public void TestConvertWithDifferentArraySources()
        {
            var collection = new TestConverterCollection <AValue, BValue>(new PathFormatterCollection(), configurator =>
            {
                configurator.If(a => a.Condition)
                .Target(b => b.BOuterArray.Each().BInnerArray.Each().FirstValue)
                .Set(a => a.AOuterArray.Current().AFirstAFirstInnerArray.Current().Value);
                configurator.If(a => !a.Condition)
                .Target(b => b.BOuterArray.Each().BInnerArray.Each().FirstValue)
                .Set(a => a.AOuterArray.Current().ASecondASecondInnerArray.Current().Value);
            });
            var converter = collection.GetConverter(MutatorsContext.Empty);
            var from      = new AValue
            {
                AOuterArray = new[]
                {
                    new AOuterValue
                    {
                        AFirstAFirstInnerArray = new[]
                        {
                            new AFirstInnerValue {
                                Value = "123"
                            }
                        },
                        ASecondASecondInnerArray = new[]
                        {
                            new ASecondInnerValue {
                                Value = "321"
                            }
                        },
                    }
                },
                Condition = true,
            };

            Following.Code(() => converter(from))
            .Should().Throw <InvalidOperationException>()
            .Which.Message.Should().MatchRegex(@"^Method T Current\[T\].* cannot be invoked$");

            return;

#pragma warning disable 162
            var expected = new BValue
            {
                BOuterArray = new[]
                {
                    new BOuterValue
                    {
                        BInnerArray = new[]
                        {
                            new BInnerValue {
                                FirstValue = "123"
                            },
                        },
                    },
                },
            };
            converter(from).Should().BeEquivalentTo(expected);
#pragma warning restore 162
        }
예제 #3
0
            private bool UpdateRightsForUsersUponChangeOnSharing(List <string> _RelevantIdList, Tuple <string, List <string> >[] _RightsRegex, Controller_Rights_Internal.EChangeUserRightsForModelType _Action, Action <string> _ErrorMessageAction = null)
            {
                var WaitFor       = new ManualResetEvent(false);
                var InternalError = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                var DoneStack     = new ConcurrentStack <bool>();

                for (var i = 0; i < _RelevantIdList.Count; i++)
                {
                    for (var j = 0; j < _RightsRegex.Length; j++)
                    {
                        DoneStack.Push(true);
                    }
                }

                foreach (var ChangeForUserId in _RelevantIdList)
                {
                    var CurrentUserID = ChangeForUserId;
                    foreach (var PathRegex in _RightsRegex)
                    {
                        var CurrentPathRegex = PathRegex;
                        BTaskWrapper.Run(() =>
                        {
                            if (!Controller_AtomicDBOperation.Get().GetClearanceForDBOperation(InnerProcessor, UserDBEntry.DBSERVICE_USERS_TABLE(), CurrentUserID, _ErrorMessageAction))
                            {
                                _ErrorMessageAction?.Invoke("PubSub_To_AuthService->UpdateRightsForUsersUponChangeOnSharing: Atomic operation control has failed for " + UserDBEntry.KEY_NAME_USER_ID + ": " + CurrentUserID);
                                InternalError.Set(true);
                                try { WaitFor.Set(); } catch (Exception) { }
                                return;
                            }
                            try
                            {
                                if (!Controller_Rights_Internal.Get().ChangeBaseUserRight(
                                        out bool _bInternalErrorOccured,
                                        true,/*important to set to true*/
                                        _Action,
                                        CurrentUserID,
                                        CurrentPathRegex.Item1.Replace("{shareeUserId}", ChangeForUserId, StringComparison.InvariantCulture),
                                        _ErrorMessageAction,
                                        CurrentPathRegex.Item2))
                                {
                                    if (_bInternalErrorOccured)
                                    {
                                        InternalError.Set(true);
                                        try { WaitFor.Set(); } catch (Exception) { }
                                        return;
                                    }
                                }
                            }
                            finally
                            {
                                Controller_AtomicDBOperation.Get().SetClearanceForDBOperationForOthers(InnerProcessor, UserDBEntry.DBSERVICE_USERS_TABLE(), CurrentUserID, _ErrorMessageAction);
                            }

                            DoneStack.TryPop(out bool _);
                            if (DoneStack.Count == 0)
                            {
                                try
                                {
                                    WaitFor.Set();
                                }
                                catch (Exception) { }
                            }
                        });
                    }
                }

                try
                {
                    if (_RelevantIdList.Count > 0)
                    {
                        WaitFor.WaitOne();
                    }
                    WaitFor.Close();
                }
                catch (Exception) { }

                //Retry if internal error occured
                return(InternalError.Get() == false);
            }
예제 #4
0
 public void Add(BValue key, BValue value)
 {
     dictionary.Add(key, value);
 }
예제 #5
0
        /// <summary>
        ///
        /// <para>CustomSubscribe:</para>
        ///
        /// <para>Subscribes to given custom topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null && BUtility.CalculateStringMD5(_CustomTopic, out string TopicMD5, _ErrorMessageAction))
            {
                if (EnsureQueueExists(TopicMD5, out string QueueUrl, _ErrorMessageAction))
                {
                    var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                    var SubscriptionThread          = new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;

                        while (!SubscriptionCancellationVar.Get())
                        {
                            ReceiveMessageResponse Response;
                            try
                            {
                                using (var ReceiveMessageTask = SQSClient.ReceiveMessageAsync(QueueUrl))
                                {
                                    ReceiveMessageTask.Wait();
                                    Response = ReceiveMessageTask.Result;
                                }
                            }
                            catch (Exception e)
                            {
                                Response = null;
                                _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }

                            if (Response == null || Response.Messages == null || Response.Messages.Count == 0)
                            {
                                Thread.Sleep(1000);
                                continue;
                            }

                            var AckDictionary = new Dictionary <string, string>();

                            foreach (var MessageContainer in Response.Messages)
                            {
                                if (MessageContainer != null)
                                {
                                    if (!AckDictionary.ContainsKey(MessageContainer.MessageId))
                                    {
                                        AckDictionary.Add(MessageContainer.MessageId, MessageContainer.ReceiptHandle);
                                    }

                                    string Data = MessageContainer.Body;

                                    if (UniqueMessageDeliveryEnsurer != null)
                                    {
                                        UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                        if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(_CustomTopic, TimestampHash, _ErrorMessageAction))
                                        {
                                            _OnMessage?.Invoke(_CustomTopic, Data);
                                        }
                                    }
                                    else
                                    {
                                        _OnMessage?.Invoke(_CustomTopic, Data);
                                    }
                                }
                            }

                            var AckArray = new List <DeleteMessageBatchRequestEntry>();
                            foreach (var Current in AckDictionary)
                            {
                                AckArray.Add(new DeleteMessageBatchRequestEntry(Current.Key, Current.Value));
                            }

                            try
                            {
                                using (var DeleteMessageBatchTask = SQSClient.DeleteMessageBatchAsync(QueueUrl, AckArray))
                                {
                                    DeleteMessageBatchTask.Wait();
                                }
                            }
                            catch (Exception e)
                            {
                                _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }
                        }
                    });
                    SubscriptionThread.Start();

                    lock (SubscriberThreadsDictionaryLock)
                    {
                        SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                    }
                    return(true);
                }
            }
            return(false);
        }
예제 #6
0
        public void Run(Action <string> _ServerLogAction = null)
        {
            var bStartSucceed       = new BValue <bool>(false);
            var WaitForFirstSuccess = new ManualResetEvent(false);

            BTaskWrapper.Run(() =>
            {
                var WaitForException = new ManualResetEvent(false);
                int FailureCount     = 0;
                do
                {
                    try
                    {
                        lock (Listener)
                        {
                            Listener.Start();
                        }

                        bStartSucceed.Set(true);
                        try
                        {
                            WaitForFirstSuccess.Set();
                        }
                        catch (Exception) {}

                        FailureCount = 0;

                        try
                        {
                            WaitForException.WaitOne();
                            //Do not close WaitForException! Can be reused.
                        }
                        catch (Exception) { }
                    }
                    catch (Exception e)
                    {
                        _ServerLogAction?.Invoke("BWebService->Run->HttpListener->Start: " + e.Message + ", trace: " + e.Message);

                        try
                        {
                            WaitForException.Set();
                        }
                        catch (Exception) { }

                        Thread.Sleep(1000);
                    }
                } while (++FailureCount < 10);

                try
                {
                    WaitForFirstSuccess.Set(); //When exhausted
                }
                catch (Exception) { }
            });

            try
            {
                WaitForFirstSuccess.WaitOne();
                //Do not close WaitForFirstSuccess! Can be reused.
            }
            catch (Exception) {}

            if (!bStartSucceed.Get())
            {
                _ServerLogAction?.Invoke("BWebService->Run: HttpListener.Start() has failed.");
                return;
            }

            BTaskWrapper.Run(() =>
            {
                _ServerLogAction?.Invoke("BWebserver->Run: Server is running. Listening port " + ServerPort);

                while (Listener.IsListening)
                {
                    HttpListenerContext Context = null;

                    int FailureCount = 0;
                    bool bSuccess;
                    do
                    {
                        try
                        {
                            lock (Listener)
                            {
                                Context = Listener.GetContext();
                            }
                            bSuccess     = true;
                            FailureCount = 0;
                        }
                        catch (Exception e)
                        {
                            _ServerLogAction?.Invoke("BWebService->Run->HttpListener->GetContext: " + e.Message + ", trace: " + e.Message);
                            bSuccess = false;
                            Thread.Sleep(1000);
                        }
                    } while (!bSuccess && ++FailureCount < 10);

                    if (Context == null)
                    {
                        continue;
                    }

                    BTaskWrapper.Run(() =>
                    {
                        if (Context == null)
                        {
                            return;
                        }
                        try
                        {
                            Context.Response.AppendHeader("Access-Control-Allow-Origin", "*");

                            bool bIsWebhookRequest =
                                BWebUtilities.DoesContextContainHeader(out List <string> _, out string _, Context, "webhook-request-callback") &&
                                BWebUtilities.DoesContextContainHeader(out List <string> _, out string _, Context, "webhook-request-origin");

                            if (Context.Request.HttpMethod == "OPTIONS" && !bIsWebhookRequest)
                            {
                                Context.Response.AppendHeader("Access-Control-Allow-Headers", "*");
                                Context.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
                                Context.Response.AppendHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH");
                                Context.Response.AppendHeader("Access-Control-Max-Age", "-1");
                                Context.Response.StatusCode = BWebResponse.Status_OK_Code;
                            }
                            else
                            {
                                if (PrefixesToListen == null)
                                {
                                    _ServerLogAction?.Invoke("BWebserver->Run: PrefixesToListen is null.");
                                    WriteInternalError(Context.Response, "Code: WS-PTLN.");
                                    return;
                                }
                                if (!LookForListenersFromRequest(out BWebServiceBase _Callback, Context))
                                {
                                    if (Context.Request.RawUrl.EndsWith("/ping"))
                                    {
                                        WriteOK(Context.Response, "pong");
                                        return;
                                    }
                                    _ServerLogAction?.Invoke($"BWebserver->Run: Request is not being listened. Request: {Context.Request.RawUrl}");
                                    WriteNotFound(Context.Response, "Request is not being listened.");
                                    return;
                                }

                                var Response = _Callback.OnRequest(Context, _ServerLogAction);

                                Context.Response.StatusCode = Response.StatusCode;

                                foreach (var CurrentHeader in Response.Headers)
                                {
                                    foreach (var Value in CurrentHeader.Value)
                                    {
                                        if (CurrentHeader.Key.ToLower() != "access-control-allow-origin")
                                        {
                                            Context.Response.AppendHeader(CurrentHeader.Key, Value);
                                        }
                                    }
                                }

                                if (Response.ResponseContentType != null)
                                {
                                    Context.Response.ContentType = Response.ResponseContentType;
                                }

                                if (Response.ResponseContent.Type == EBStringOrStreamEnum.String)
                                {
                                    byte[] Buffer = Encoding.UTF8.GetBytes(Response.ResponseContent.String);
                                    if (Buffer != null)
                                    {
                                        Context.Response.ContentLength64 = Buffer.Length;
                                        if (Buffer.Length > 0)
                                        {
                                            Context.Response.OutputStream.Write(Buffer, 0, Buffer.Length);
                                        }
                                    }
                                    else
                                    {
                                        Context.Response.ContentLength64 = 0;
                                    }
                                }
                                else
                                {
                                    if (Response.ResponseContent.Stream != null && Response.ResponseContent.StreamLength > 0)
                                    {
                                        Context.Response.ContentLength64 = Response.ResponseContent.StreamLength;
                                        Response.ResponseContent.Stream.CopyTo(Context.Response.OutputStream);
                                    }
                                    else
                                    {
                                        _ServerLogAction?.Invoke("BWebserver->Error: Response is stream, but stream object is " + (Response.ResponseContent.Stream == null ? "null" : "valid") + " and content length is " + Response.ResponseContent.StreamLength);
                                        WriteInternalError(Context.Response, "Code: WS-STRMINV.");
                                        return;
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            try
                            {
                                WriteInternalError(Context.Response, "An unexpected internal error has occured: " + e.Message);
                            }
                            catch (Exception) { }

                            _ServerLogAction?.Invoke("Uncaught exception in the request handle: " + e.Message + ", trace: " + e.StackTrace);
                        }
                        finally
                        {
                            //Always close the stream
                            try { Context.Response.OutputStream.Close(); } catch (Exception) { }
                            try { Context.Response.OutputStream.Dispose(); } catch (Exception) { }
                            //try { Context.Response.Close(); } catch (Exception) { }
                        }
                    });
                }
            });
        }
예제 #7
0
            private bool GetUserListFromAzure(out List <UserPrincipal> _Users, string _TokenType, string _AccessToken, Action <string> _ErrorMessageAction)
            {
                _Users = null;

                using var Handler = new HttpClientHandler
                      {
                          SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
                          ServerCertificateCustomValidationCallback = (a, b, c, d) => true
                      };
                using var Client = new HttpClient(Handler);
                Client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", _TokenType + " " + _AccessToken);

                string ResponseString = "";

                try
                {
                    using var RequestTask = Client.GetAsync("https://graph.microsoft.com/v1.0/servicePrincipals/" + FetchUsersAppObjectID + "/appRoleAssignedTo");
                    RequestTask.Wait();

                    using var Response        = RequestTask.Result;
                    using var ResponseContent = Response.Content;

                    using var ReadResponseTask = ResponseContent.ReadAsStringAsync();
                    ReadResponseTask.Wait();

                    ResponseString = ReadResponseTask.Result;

                    if (!Response.IsSuccessStatusCode)
                    {
                        _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: " + ResponseString);
                        return(false);
                    }

                    var Parsed = JObject.Parse(ResponseString);

                    if (!Parsed.TryGetValue("value", out JToken Values) || Values.Type != JTokenType.Array)
                    {
                        _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString);
                        return(false);
                    }

                    var UsersResult = new List <UserPrincipal>();

                    var ValuesArray = Values as JArray;

                    var InternalFailure = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                    var WaitFor         = new ManualResetEvent(false);
                    var RemainedTasks   = new ConcurrentStack <bool>();
                    for (var i = 0; i < ValuesArray.Count; i++)
                    {
                        RemainedTasks.Push(true);
                    }

                    foreach (var Value in ValuesArray)
                    {
                        if (Value.Type != JTokenType.Object)
                        {
                            _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString);
                            return(false);
                        }
                        var ValueObject = (JObject)Value;

                        if (!ValueObject.TryGetValue("principalDisplayName", out JToken UserNameToken) || UserNameToken.Type != JTokenType.String ||
                            !ValueObject.TryGetValue("principalId", out JToken PrincipleIDToken) || PrincipleIDToken.Type != JTokenType.String)
                        {
                            _ErrorMessageAction?.Invoke("GetTokenForAzure->Error: Unexpected response: " + ResponseString);
                            return(false);
                        }

                        var UserName    = (string)UserNameToken;
                        var PrincipalId = (string)PrincipleIDToken;

                        BTaskWrapper.Run(() =>
                        {
                            if (!GetUserEmail(out string UserEmail, PrincipalId, _TokenType, _AccessToken, _ErrorMessageAction))
                            {
                                InternalFailure.Set(true);
                                WaitFor.Set();
                                return;
                            }

                            if (InternalFailure.Get())
                            {
                                return;
                            }

                            lock (UsersResult)
                            {
                                UsersResult.Add(new UserPrincipal()
                                {
                                    Name  = UserName,
                                    Email = UserEmail
                                });
                            }

                            RemainedTasks.TryPop(out bool _);
                            if (RemainedTasks.Count == 0)
                            {
                                WaitFor.Set();
                            }
                        });
                    }

                    if (ValuesArray.Count > 0)
                    {
                        try { WaitFor.WaitOne(); } catch (Exception) { }
                    }
                    try { WaitFor.Close(); } catch (Exception) { }

                    if (InternalFailure.Get())
                    {
                        _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Get user e-mail step has failed.");
                        return(false);
                    }

                    _Users = UsersResult;
                }
                catch (Exception e)
                {
                    if (e.InnerException != null && e.InnerException != e)
                    {
                        _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                    }
                    if (e is AggregateException)
                    {
                        foreach (var Inner in (e as AggregateException).InnerExceptions)
                        {
                            _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: Aggregate->Inner: " + Inner.Message + ", Trace: " + Inner.StackTrace);
                        }
                    }
                    _ErrorMessageAction?.Invoke("GetUserListFromAzure->Error: " + ResponseString + ", message: " + e.Message + ", trace: " + e.StackTrace);
                    return(false);
                }
                return(true);
            }
예제 #8
0
        /// <summary>
        ///
        /// <para>CustomSubscribe:</para>
        ///
        /// <para>Subscribes to given custom topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool CustomSubscribe(
            string _CustomTopic,
            Action <string, string> _OnMessage,
            Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null)
            {
                _CustomTopic = GetGoogleFriendlyTopicName(_CustomTopic);

                if (GetSubscriber(out SubscriberServiceApiClient APIClientVar, out SubscriptionName SubscriptionNameVar, _CustomTopic, _ErrorMessageAction))
                {
                    var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                    var SubscriptionThread          = new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;

                        while (!SubscriptionCancellationVar.Get())
                        {
                            PullResponse Response = null;
                            try
                            {
                                Response = APIClientVar.Pull(SubscriptionNameVar, true, 1000);
                            }
                            catch (Exception e)
                            {
                                if (e is RpcException && (e as RpcException).StatusCode == StatusCode.DeadlineExceeded)
                                {
                                    Thread.Sleep(1000);
                                    continue;
                                }

                                Response = null;

                                _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }

                            if (Response == null || Response.ReceivedMessages == null || !Response.ReceivedMessages.Any())
                            {
                                Thread.Sleep(1000);
                                continue;
                            }

                            var MessageContainers = Response.ReceivedMessages.ToArray();
                            if (MessageContainers != null && MessageContainers.Length > 0)
                            {
                                var AckArray = new List <string>();

                                foreach (var MessageContainer in MessageContainers)
                                {
                                    if (MessageContainer != null)
                                    {
                                        if (!AckArray.Contains(MessageContainer.AckId))
                                        {
                                            AckArray.Add(MessageContainer.AckId);
                                        }

                                        string Topic = GetTopicNameFromGoogleFriendlyName(_CustomTopic);
                                        string Data  = MessageContainer.Message.Data.ToStringUtf8();

                                        if (UniqueMessageDeliveryEnsurer != null)
                                        {
                                            UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                            if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction))
                                            {
                                                _OnMessage?.Invoke(Topic, Data);
                                            }
                                        }
                                        else
                                        {
                                            _OnMessage?.Invoke(Topic, Data);
                                        }
                                    }
                                }

                                try
                                {
                                    APIClientVar.Acknowledge(SubscriptionNameVar, AckArray);
                                }
                                catch (Exception e)
                                {
                                    if (e is RpcException && (e as RpcException).Status.StatusCode == StatusCode.InvalidArgument)
                                    {
                                        //That is fine, probably due to previous subscriptions
                                    }
                                    else
                                    {
                                        _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                        if (e.InnerException != null && e.InnerException != e)
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                        }
                                    }
                                }
                            }
                        }
                    });
                    SubscriptionThread.Start();

                    lock (SubscriberThreadsDictionaryLock)
                    {
                        SubscriberThreadsDictionary.Add(SubscriptionNameVar, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                    }
                    return(true);
                }
            }
            return(false);
        }
예제 #9
0
        public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 &&
                _OnMessage != null)
            {
                _CustomTopic = GetAzureFriendlyTopicName(_CustomTopic);

                if (EnsureTopicExists(_CustomTopic, out ITopicClient _TopicClient, _ErrorMessageAction))
                {
                    if (EnsureSubscriptionExists(_CustomTopic, _TopicClient, out Microsoft.Azure.ServiceBus.ISubscriptionClient _SubscriptionClient, _ErrorMessageAction))
                    {
                        var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                        var SubscriptionThread          = new Thread(() =>
                        {
                            Thread.CurrentThread.IsBackground = true;
                            try
                            {
                                // Define exception receiver handler
                                Func <ExceptionReceivedEventArgs, Task> ExceptionReceiverHandler = (ExceptionReceivedEventArgs _EventArgs) =>
                                {
                                    _ErrorMessageAction?.Invoke($"BPubSubServiceAzure->CustomSubscribe->ExceptionReceiverHandler: {_EventArgs.Exception.Message}, Action: {_EventArgs.ExceptionReceivedContext.Action}, EntityPath: {_EventArgs.ExceptionReceivedContext.EntityPath}, Endpoint: {_EventArgs.ExceptionReceivedContext.Endpoint}, ClientId: {_EventArgs.ExceptionReceivedContext.ClientId}, Trace: {_EventArgs.Exception.StackTrace}");

                                    RemoveSubscriberThread(_CustomTopic);
                                    if (!_SubscriptionClient.IsClosedOrClosing)
                                    {
                                        using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                        {
                                            CloseSubscriptionTask.Wait();
                                        }
                                    }

                                    return(Task.CompletedTask);
                                };

                                // Configure the message handler options in terms of exception handling, number of concurrent messages to deliver, etc.
                                var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceiverHandler)
                                {
                                    // Maximum number of concurrent calls to the callback ProcessMessagesAsync(), set to 1 for simplicity.
                                    // Set it according to how many messages the application wants to process in parallel.
                                    MaxConcurrentCalls = 1,

                                    // Indicates whether the message pump should automatically complete the messages after returning from user callback.
                                    // False below indicates the complete operation is handled by the user callback as in ProcessMessagesAsync().
                                    AutoComplete = false
                                };

                                // Register the function that processes messages.
                                _SubscriptionClient.RegisterMessageHandler(async(Message MessageContainer, CancellationToken token) =>
                                {
                                    if (MessageContainer != null)
                                    {
                                        string Topic = GetTopicNameFromAzureFriendlyName(_CustomTopic);
                                        string Data  = Encoding.UTF8.GetString(MessageContainer.Body);

                                        if (MessageContainer.Label != null &&
                                            MessageContainer.Label.Equals(_CustomTopic))
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [Internal] pub/sub message.");
                                        }
                                        else
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [StorageAccount] pub/sub message.");
                                        }

                                        if (UniqueMessageDeliveryEnsurer != null)
                                        {
                                            UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                            if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction))
                                            {
                                                _OnMessage?.Invoke(Topic, Data);
                                                RemoveSubscriberThread(_CustomTopic);
                                                if (!_SubscriptionClient.IsClosedOrClosing)
                                                {
                                                    await _SubscriptionClient.CloseAsync();
                                                }
                                            }
                                        }
                                        else
                                        {
                                            _OnMessage?.Invoke(Topic, Data);
                                        }

                                        await _SubscriptionClient.CompleteAsync(MessageContainer.SystemProperties.LockToken);

                                        if (_SubscribeSingleMessage)
                                        {
                                            RemoveSubscriberThread(_CustomTopic);
                                            if (!_SubscriptionClient.IsClosedOrClosing)
                                            {
                                                await _SubscriptionClient.CloseAsync();
                                            }
                                        }
                                    }
                                }, messageHandlerOptions);
                            }
                            catch (Exception e)
                            {
                                _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe->InnerException: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }

                                RemoveSubscriberThread(_CustomTopic);
                                if (!_SubscriptionClient.IsClosedOrClosing)
                                {
                                    using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                    {
                                        CloseSubscriptionTask.Wait();
                                    }
                                }
                            }

                            while (!SubscriptionCancellationVar.Get())
                            {
                                //Wait until delete
                                Thread.Sleep(500);
                            }

                            if (!_SubscriptionClient.IsClosedOrClosing)
                            {
                                using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                {
                                    CloseSubscriptionTask.Wait();
                                }
                            }
                        });
                        SubscriptionThread.Start();

                        lock (SubscriberThreadsDictionaryLock)
                        {
                            SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                        }
                        return(true);
                    }
                }
            }
            return(false);
        }