Ejemplo n.º 1
0
        /// <summary>
        /// Sends the asynchronous.
        /// </summary>
        /// <param name="rockMessage">The rock message.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public async Task <SendMessageResult> SendAsync(RockMessage rockMessage, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            var sendMessageResult = new SendMessageResult();

            var smsMessage = rockMessage as RockSMSMessage;

            if (smsMessage != null)
            {
                // Validate From Number
                if (smsMessage.FromNumber == null)
                {
                    sendMessageResult.Errors.Add("A From Number was not provided.");
                    return(sendMessageResult);
                }

                string accountSid = GetAttributeValue(TwilioAttributeKey.Sid);
                string authToken  = GetAttributeValue(TwilioAttributeKey.AuthToken);
                TwilioClient.Init(accountSid, authToken);

                // Common Merge Field
                var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, rockMessage.CurrentPerson);
                foreach (var mergeField in rockMessage.AdditionalMergeFields)
                {
                    mergeFields.AddOrReplace(mergeField.Key, mergeField.Value);
                }

                int?throttlingWaitTimeMS = null;
                if (this.IsLongCodePhoneNumber(smsMessage.FromNumber.Value))
                {
                    throttlingWaitTimeMS = this.GetAttributeValue(TwilioAttributeKey.LongCodeThrottling).AsIntegerOrNull();
                }

                List <Uri> attachmentMediaUrls = GetAttachmentMediaUrls(rockMessage.Attachments.AsQueryable());

                if (throttlingWaitTimeMS.HasValue)
                {
                    foreach (var recipient in rockMessage.GetRecipients())
                    {
                        var result = await SendToRecipientAsync(recipient, mergeFields, smsMessage, attachmentMediaUrls, mediumEntityTypeId, mediumAttributes).ConfigureAwait(false);

                        sendMessageResult.Errors.AddRange(result.Errors);
                        sendMessageResult.Errors.AddRange(result.Warnings);
                        sendMessageResult.MessagesSent += result.MessagesSent;

                        await Task.Delay(throttlingWaitTimeMS.Value).ConfigureAwait(false);
                    }
                }
                else
                {
                    var sendingTask = new List <Task <SendMessageResult> >();

                    using (var mutex = new SemaphoreSlim(MaxParallelization))
                    {
                        foreach (var recipient in rockMessage.GetRecipients())
                        {
                            var startMutexWait = System.Diagnostics.Stopwatch.StartNew();
                            await mutex.WaitAsync().ConfigureAwait(false);

                            sendingTask.Add(ThrottleHelper.ThrottledExecute(() => SendToRecipientAsync(recipient, mergeFields, smsMessage, attachmentMediaUrls, mediumEntityTypeId, mediumAttributes), mutex));
                        }

                        /*
                         * Now that we have fired off all of the task, we need to wait for them to complete, get their results,
                         * and then process that result. Once all of the task have been completed we can continue.
                         */
                        while (sendingTask.Count > 0)
                        {
                            var completedTask = await Task.WhenAny(sendingTask).ConfigureAwait(false);

                            sendingTask.Remove(completedTask);

                            var result = await completedTask.ConfigureAwait(false);

                            sendMessageResult.Errors.AddRange(result.Errors);
                            sendMessageResult.Errors.AddRange(result.Warnings);
                            sendMessageResult.MessagesSent += result.MessagesSent;
                        }
                    }
                }
            }

            return(sendMessageResult);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Sends the asynchronous.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public async Task SendAsync(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            var    fromPhone = string.Empty;
            var    unprocessedRecipientCount = 0;
            var    mergeFields               = new Dictionary <string, object>();
            Person currentPerson             = null;
            var    attachmentMediaUrls       = new List <Uri>();
            var    personEntityTypeId        = 0;
            var    communicationCategoryId   = 0;
            var    communicationEntityTypeId = 0;

            using (var rockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(rockContext).Get(communication.Id);

                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(rockContext).Queryable();
                    unprocessedRecipientCount = qryRecipients
                                                .Where(r =>
                                                       r.CommunicationId == communication.Id &&
                                                       r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                       r.MediumEntityTypeId.HasValue &&
                                                       r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                                .Count();
                }

                if (unprocessedRecipientCount == 0)
                {
                    return;
                }

                fromPhone = communication.SMSFromDefinedValue?.Value;
                if (string.IsNullOrWhiteSpace(fromPhone))
                {
                    // just in case we got this far without a From Number, throw an exception
                    throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString());
                }

                currentPerson = communication.CreatedByPersonAlias?.Person;
                mergeFields   = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                personEntityTypeId        = EntityTypeCache.Get <Person>().Id;
                communicationEntityTypeId = EntityTypeCache.Get <Model.Communication>().Id;
                communicationCategoryId   = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext).Id;
                var smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS);

                if (smsAttachmentsBinaryFileIdList.Any())
                {
                    attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(rockContext).GetByIds(smsAttachmentsBinaryFileIdList));
                }
            }

            int?throttlingWaitTimeMS = null;

            if (this.IsLongCodePhoneNumber(fromPhone))
            {
                throttlingWaitTimeMS = GetAttributeValue(TwilioAttributeKey.LongCodeThrottling).AsIntegerOrNull();
            }

            var    globalAttributes = GlobalAttributesCache.Get();
            string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot");
            var    callbackUrl      = publicAppRoot + "Webhooks/Twilio.ashx";

            var accountSid = GetAttributeValue(TwilioAttributeKey.Sid);
            var authToken  = GetAttributeValue(TwilioAttributeKey.AuthToken);

            TwilioClient.Init(accountSid, authToken);

            if (throttlingWaitTimeMS.HasValue)
            {
                // If throttlingWaitTime has a value we need to send all text synchronously so that the throttle is respected.
                var recipientFound = true;
                while (recipientFound)
                {
                    // make a new rockContext per recipient
                    var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication);

                    // This means we are done, break the loop
                    if (recipient == null)
                    {
                        recipientFound = false;
                        continue;
                    }

                    await SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient).ConfigureAwait(false);

                    await Task.Delay(throttlingWaitTimeMS.Value).ConfigureAwait(false);
                }
            }
            else
            {
                var sendingTask        = new List <Task>(unprocessedRecipientCount);
                var asyncTransport     = this as IAsyncTransport;
                var maxParallelization = asyncTransport?.MaxParallelization ?? 10;

                using (var mutex = new SemaphoreSlim(maxParallelization))
                {
                    var recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication);

                        // This means we are done, break the loop
                        if (recipient == null)
                        {
                            recipientFound = false;
                            continue;
                        }

                        await mutex.WaitAsync().ConfigureAwait(false);

                        sendingTask.Add(ThrottleHelper.ThrottledExecute(() => SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient), mutex));
                    }

                    /*
                     * Now that we have fired off all of the task, we need to wait for them to complete.
                     * Once all of the task have been completed we can continue.
                     */
                    while (sendingTask.Count > 0)
                    {
                        var completedTask = await Task.WhenAny(sendingTask).ConfigureAwait(false);

                        sendingTask.Remove(completedTask);
                    }
                }
            }
        }