Esempio n. 1
0
        protected async Task CheckPendingMessages(string endPointID)
        {
            ASSERT(!string.IsNullOrWhiteSpace(endPointID), $"Missing parameter '{nameof(endPointID)}");

            // Is this endpoint registered against me ?
            lock ( Locker )
            {
                if (!RegisteredEndpoints.ContainsKey(endPointID))
                {
                    // No -> No need to continue
                    return;
                }
            }

            var messages = await RestoreMessages(endPointID);

            if (messages == null)
            {
                // No messages available for this endpoint
                return;
            }

            IEndPoint endPoint;

            lock ( Locker )
            {
                endPoint = RegisteredEndpoints.TryGet(endPointID);
                if (endPoint == null)
                {
                    // endPoint was unregistered in the mean-time (nb: should not happen often ...)
                    goto PUSH_MESSAGES_BACK;
                }
                else if (endPoint.IsOneShot)
                {
                    // Unregister this endpoint before sending the messages
                    var rc = RegisteredEndpoints.Remove(endPointID);
                    ASSERT(rc, $"Could not unregister endpoint '{endPointID}'");
                    goto SEND_MESSAGES;
                }
                else                  // not one-shot
                {
                    goto SEND_MESSAGES;
                }
            }
                        #pragma warning disable 0162
            FAIL("Unreachable code reached ...");
                        #pragma warning restore 0162

SEND_MESSAGES:
            ASSERT(endPoint != null, $"Logic error: '{nameof(endPoint)}' is supposed to be set here");
            await endPoint.ReceiveMessages(messages);

            return;

PUSH_MESSAGES_BACK:
            // The messages could not be delivered => Put them back in the queue
            await ReceiveMessages(messages);

            return;
        }
Esempio n. 2
0
        public async Task RegisterEndpoint(IEndPoint endPoint)
        {
            ASSERT((endPoint != null) && (!string.IsNullOrWhiteSpace(endPoint.ID)), $"Missing or invalid parameter '{nameof(endPoint)}'");

            Action checkExisting = () =>
            {
                var existing = RegisteredEndpoints.TryGet(endPoint.ID);                            // nb: read-only => no need for "lock{}"
                if (existing == null)
                {
                    // OK
                    return;
                }
                // Not OK
                throw new EndpointAlreadyRegistered($"The endpoint '{endPoint.ID}' has already been registered", existing);
            };

            checkExisting();

            if (endPoint.IsOneShot)
            {
                // Check pending messages
                var messages = await RestoreMessages(endPoint.ID);

                if (messages != null)
                {
                    ASSERT(messages.Count > 0, $"'{nameof(messages)}' is not supposed to be empty here");
                    await endPoint.ReceiveMessages(messages);

                    // nb: one-shot -> No need to register this endpoint ...
                }
                else                  // There's no pending messages
                {
                    // Register endpoint
                    lock ( Locker )
                    {
                        checkExisting();
                        RegisteredEndpoints.Add(endPoint.ID, endPoint);
                    }

                    // Re-check pending messages (in case they've been added in the mean-time ...)
                    await CheckPendingMessages(endPoint.ID);
                }
            }
            else              // not endPoint.IsOneShot
            {
                // Register endpoint
                lock ( Locker )
                {
                    checkExisting();
                    RegisteredEndpoints.Add(endPoint.ID, endPoint);
                }

                // Re-check pending messages (in case they've been added in the mean-time ...)
                await CheckPendingMessages(endPoint.ID);
            }
        }
Esempio n. 3
0
        public Task UnRegisterEndpoint(string id)
        {
            ASSERT(!string.IsNullOrWhiteSpace(id), $"Missing parameter '{nameof(id)}");

            lock ( Locker )
            {
                var rc = RegisteredEndpoints.Remove(id);
                ASSERT(rc, $"Could not unregister endpoint '{id}'");                    // nb: can happen in case of race condition, but should be very rare
            }

            return(Task.FromResult(0));
        }
Esempio n. 4
0
        public async Task ReceiveMessages(IEnumerable <TMessage> messages)
        {
            ASSERT(messages != null, $"Missing parameter '{nameof(messages)}'");
            ASSERT(messages.Where(v => string.IsNullOrWhiteSpace(v.TryGetString(MessageKeys.KeyReceiverID))).Count() == 0, $"There are messages without '{MessageKeys.KeyReceiverID}' defined");

            var messagesToSave = (new{ EndPointID = (string)null, Messages = (List <TMessage>)null }).NewAnonymousList();
            var messagesToSend = (new{ EndPoint = (IEndPoint)null, Messages = (List <TMessage>)null }).NewAnonymousList();

            var byEndPointIDs = messages.GroupBy(v => v.TryGetString(MessageKeys.KeyReceiverID)).ToDictionary(v => v.Key, v => v.ToList());

            lock ( Locker )
            {
                foreach (var pair in byEndPointIDs)
                {
                    var endPointID = pair.Key;
                    var msgs       = pair.Value;

                    var endPoint = RegisteredEndpoints.TryGet(endPointID);
                    if (endPoint == null)
                    {
                        // These messages are for an endpoint that is not managed by me => Save them to Redis
                        messagesToSave.Add(new{ EndPointID = endPointID, Messages = msgs });
                    }
                    else if (endPoint.IsOneShot)
                    {
                        // These messages are for an endpoint that is managed by me but needs to be unregistered when it receives messages
                        var rc = RegisteredEndpoints.Remove(endPointID);
                        ASSERT(rc, $"Could not unregister endpoint '{endPointID}'");

                        messagesToSend.Add(new{ EndPoint = endPoint, Messages = msgs });
                    }
                    else
                    {
                        // These messages are for an endpoint that is managed by me
                        messagesToSend.Add(new{ EndPoint = endPoint, Messages = msgs });
                    }
                }
            }

            var exception = (System.Exception)null;              // The first exception encountered if any

            foreach (var item in messagesToSend)
            {
                var notAwaited = Task.Run(async() =>                   // nb: Run asynchroneously
                {
                    try { await item.EndPoint.ReceiveMessages(item.Messages); }
                    catch (System.Exception ex) { exception = (exception ?? ex); }
                });
            }

            foreach (var item in messagesToSave)
            {
                try { await SaveMessages(item.EndPointID, item.Messages); }
                catch (System.Exception ex) { exception = (exception ?? ex); }
            }

            if (exception != null)
            {
                // An exception has been encountered => Rethrow the first one received
                throw new ApplicationException($"An error occurred while receiving a message ({exception.GetType().FullName}): {exception.Message}", innerException: exception);
            }
        }