private static Task<bool> Send(Bubble b, BubbleGroup group, bool resend)
        {
            return Task<bool>.Factory.StartNew(() =>
            {                   
                var vb = b as VisualBubble;
                if (vb != null)
                {
                    if (vb.Status == Bubble.BubbleStatus.Sent)
                    {
                        Utils.DebugPrint("Trying to send a bubble that is already sent! On " + vb.Service.Information.ServiceName);
                        return true;
                    }

                    Func<bool> restartServiceIfNeeded = () =>
                    {
                        if (!ServiceManager.IsRegistered(b.Service) ||
                            ServiceManager.IsRunning(b.Service) ||
                            ServiceManager.IsAborted(b.Service) )
                            return false;

                        Utils.DebugPrint(
                            "For f***s sakes. The scheduler isn't doing it's job properly, or " +
                            "you're sending a message to it at a weird time. Starting it up bra (" +
                            b.Service.Information.ServiceName + ").");
                        ServiceManager.AbortAndRestart(b.Service);
                        return true;
                    };

                    var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId;
                    if (vb.IdService == null && vb.IdService2 == null && visualBubbleServiceId != null)
                    {
                        visualBubbleServiceId.AddVisualBubbleIdServices(vb);
                    }

                    try
                    {
                        @group = Group(vb, resend, true);
                    }
                    catch (Exception ex)
                    {
                        Utils.DebugPrint("Problem in Send:GroupBubble from service " + 
                                                 vb.Service.Information.ServiceName + ": " + ex.Message);
                        return false;
                    }

                    if (@group == null)
                    {
                        Utils.DebugPrint("Could not find a suitable group for bubble " + vb.ID 
                                                 + " on " + vb.Service.Information.ServiceName); 
                        return false;
                    }

                    var shouldQueue = vb.Service.QueuedBubblesParameters == null || 
                                      !vb.Service.QueuedBubblesParameters.BubblesNotToQueue.Contains(vb.GetType());

                    try
                    {
                        if (shouldQueue && !resend && 
                            BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName, 
                                true, false))
                        {
                            BubbleQueueManager.JustQueue(group, vb);
                            restartServiceIfNeeded();
                            return false;
                        }

                        if (shouldQueue)
                        {
                            Monitor.Enter(vb.Service.SendBubbleLock);
                        }

                        using (var queued = new BubbleQueueManager.InsertBubble(group, vb, shouldQueue))
                        {
                            Action checkForQueued = () =>
                            {
                                if (!resend 
                                    && BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName, true, true))
                                {
                                    BubbleQueueManager.Send(new [] { vb.Service.Information.ServiceName });
                                }
                            };

                            try
                            {
                                FailBubbleIfPathDoesntExist(vb);
                                SendBubbleInternal(b);
                            }
                            catch (ServiceQueueBubbleException ex)
                            {
                                Utils.DebugPrint("Queuing visual bubble on service " + 
                                                         vb.Service.Information.ServiceName + ": " + ex.Message);

                                UpdateStatus(vb, Bubble.BubbleStatus.Waiting, @group);

                                if (!restartServiceIfNeeded())
                                {
                                    checkForQueued();
                                }

                                return false;
                            }
                            catch (Exception ex)
                            {
                                queued.CancelQueue();

                                Utils.DebugPrint("Visual bubble on " + 
                                                         vb.Service.Information.ServiceName + " failed to be sent: " +
                                                         ex);

                                UpdateStatus(vb, Bubble.BubbleStatus.Failed, @group);
                                BubbleGroupEvents.RaiseBubbleFailed(vb, @group);

                                if (!restartServiceIfNeeded())
                                {
                                    checkForQueued();
                                }
                                    
                                //FIXME: if the bubble fails to send, allow the queue manager to continue.
                                if (resend)
                                    return true;

                                return false;
                            }
                                
                            queued.CancelQueue();

                            lock (BubbleGroupManager.LastBubbleSentTimestamps)
                            {
                                BubbleGroupManager.LastBubbleSentTimestamps[group.ID] = Time.GetNowUnixTimestamp();
                            }

                            if (vb.Status == Bubble.BubbleStatus.Delivered)
                            {
                                Utils.DebugPrint(
                                    "************ Race condition. The server set the status to delivered/read before we could send it to sent. :')");
                                checkForQueued();
                                return true;
                            }

                            UpdateStatus(vb, Bubble.BubbleStatus.Sent, @group);

                            checkForQueued();
                            return true;
                        }
                    }
                    finally
                    {
                        if (shouldQueue)
                        {
                            Monitor.Exit(vb.Service.SendBubbleLock);
                        }
                    }
                }
                else
                {
                    var composeBubble = b as ComposeBubble;

                    if (composeBubble != null)
                    {
                        var bubbleToSend = composeBubble.BubbleToSend;
                        var visualBubbleServiceId = bubbleToSend.Service as IVisualBubbleServiceId;
                        if (bubbleToSend.IdService == null && bubbleToSend.IdService2 == null && 
                            visualBubbleServiceId != null)
                        {
                            visualBubbleServiceId.AddVisualBubbleIdServices(bubbleToSend);
                        }
                        @group.InsertByTime(bubbleToSend);
                        try
                        {
                            BubbleGroupEvents.RaiseBubbleInserted(bubbleToSend, @group);
                        }
                        catch
                        {
                            // do nothing
                        }
                    }

                    try
                    {
                        SendBubbleInternal(b);
                    }
                    catch (ServiceBubbleGroupAddressException ex)
                    {
                        if (!String.IsNullOrWhiteSpace(ex.Address))
                        {
                            if (composeBubble != null)
                            {
                                composeBubble.BubbleToSend.Address = ex.Address;
                                composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Sent;

                                var actualGroup = Group(composeBubble.BubbleToSend, resend, true);

                                ServiceEvents.RaiseComposeFinished(
                                    @group as ComposeBubbleGroup, actualGroup);

                                return true;
                            }
                        }

                        composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        return false;
                    }
                    catch (Exception ex)
                    {
                        Utils.DebugPrint("Failed to send bubble on service " + b.Service.Information.ServiceName);

                        if (composeBubble != null)
                        {
                            composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        }

                        return false;
                    }

                    if (composeBubble != null)
                    {
                        composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        return false;
                    }

                    return true;
                }
            });
        }
Esempio n. 2
0
        private static Task <bool> Send(Bubble b, BubbleGroup group, bool resend)
        {
            return(Task <bool> .Factory.StartNew(() =>
            {
                var vb = b as VisualBubble;
                if (vb != null)
                {
                    if (vb.Status == Bubble.BubbleStatus.Sent)
                    {
                        Utils.DebugPrint("Trying to send a bubble that is already sent! On " + vb.Service.Information.ServiceName);
                        return true;
                    }

                    Func <bool> restartServiceIfNeeded = () =>
                    {
                        if (!ServiceManager.IsRegistered(b.Service) ||
                            ServiceManager.IsRunning(b.Service) ||
                            ServiceManager.IsAborted(b.Service))
                        {
                            return false;
                        }

                        Utils.DebugPrint(
                            "For f***s sakes. The scheduler isn't doing it's job properly, or " +
                            "you're sending a message to it at a weird time. Starting it up bra (" +
                            b.Service.Information.ServiceName + ").");
                        ServiceManager.AbortAndRestart(b.Service);
                        return true;
                    };

                    var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId;
                    if (vb.IdService == null && vb.IdService2 == null && visualBubbleServiceId != null)
                    {
                        visualBubbleServiceId.AddVisualBubbleIdServices(vb);
                    }

                    try
                    {
                        @group = Group(vb, resend, true);
                    }
                    catch (Exception ex)
                    {
                        Utils.DebugPrint("Problem in Send:GroupBubble from service " +
                                         vb.Service.Information.ServiceName + ": " + ex.Message);
                        return false;
                    }

                    if (@group == null)
                    {
                        Utils.DebugPrint("Could not find a suitable group for bubble " + vb.ID
                                         + " on " + vb.Service.Information.ServiceName);
                        return false;
                    }

                    var shouldQueue = vb.Service.QueuedBubblesParameters == null ||
                                      !vb.Service.QueuedBubblesParameters.BubblesNotToQueue.Contains(vb.GetType());

                    try
                    {
                        if (shouldQueue && !resend &&
                            BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName,
                                                                true, false))
                        {
                            BubbleQueueManager.JustQueue(group, vb);
                            restartServiceIfNeeded();
                            return false;
                        }

                        if (shouldQueue)
                        {
                            Monitor.Enter(vb.Service.SendBubbleLock);
                        }

                        using (var queued = new BubbleQueueManager.InsertBubble(group, vb, shouldQueue))
                        {
                            Action checkForQueued = () =>
                            {
                                if (!resend &&
                                    BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName, true, true))
                                {
                                    BubbleQueueManager.Send(new [] { vb.Service.Information.ServiceName });
                                }
                            };

                            try
                            {
                                FailBubbleIfPathDoesntExist(vb);
                                SendBubbleInternal(b);
                            }
                            catch (ServiceQueueBubbleException ex)
                            {
                                Utils.DebugPrint("Queuing visual bubble on service " +
                                                 vb.Service.Information.ServiceName + ": " + ex.Message);

                                UpdateStatus(vb, Bubble.BubbleStatus.Waiting, @group);

                                if (!restartServiceIfNeeded())
                                {
                                    checkForQueued();
                                }

                                return false;
                            }
                            catch (Exception ex)
                            {
                                queued.CancelQueue();

                                Utils.DebugPrint("Visual bubble on " +
                                                 vb.Service.Information.ServiceName + " failed to be sent: " +
                                                 ex);

                                UpdateStatus(vb, Bubble.BubbleStatus.Failed, @group);
                                BubbleGroupEvents.RaiseBubbleFailed(vb, @group);

                                if (!restartServiceIfNeeded())
                                {
                                    checkForQueued();
                                }

                                //FIXME: if the bubble fails to send, allow the queue manager to continue.
                                if (resend)
                                {
                                    return true;
                                }

                                return false;
                            }

                            queued.CancelQueue();

                            lock (BubbleGroupManager.LastBubbleSentTimestamps)
                            {
                                BubbleGroupManager.LastBubbleSentTimestamps[group.ID] = Time.GetNowUnixTimestamp();
                            }

                            if (vb.Status == Bubble.BubbleStatus.Delivered)
                            {
                                Utils.DebugPrint(
                                    "************ Race condition. The server set the status to delivered/read before we could send it to sent. :')");
                                checkForQueued();
                                return true;
                            }

                            UpdateStatus(vb, Bubble.BubbleStatus.Sent, @group);

                            checkForQueued();
                            return true;
                        }
                    }
                    finally
                    {
                        if (shouldQueue)
                        {
                            Monitor.Exit(vb.Service.SendBubbleLock);
                        }
                    }
                }
                else
                {
                    var composeBubble = b as ComposeBubble;

                    if (composeBubble != null)
                    {
                        var bubbleToSend = composeBubble.BubbleToSend;
                        var visualBubbleServiceId = bubbleToSend.Service as IVisualBubbleServiceId;
                        if (bubbleToSend.IdService == null && bubbleToSend.IdService2 == null &&
                            visualBubbleServiceId != null)
                        {
                            visualBubbleServiceId.AddVisualBubbleIdServices(bubbleToSend);
                        }
                        @group.InsertByTime(bubbleToSend);
                        try
                        {
                            BubbleGroupEvents.RaiseBubbleInserted(bubbleToSend, @group);
                        }
                        catch
                        {
                            // do nothing
                        }
                    }

                    try
                    {
                        SendBubbleInternal(b);
                    }
                    catch (ServiceBubbleGroupAddressException ex)
                    {
                        if (!String.IsNullOrWhiteSpace(ex.Address))
                        {
                            if (composeBubble != null)
                            {
                                composeBubble.BubbleToSend.Address = ex.Address;
                                composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Sent;

                                var actualGroup = Group(composeBubble.BubbleToSend, resend, true);

                                ServiceEvents.RaiseComposeFinished(
                                    @group as ComposeBubbleGroup, actualGroup);

                                return true;
                            }
                        }

                        composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        return false;
                    }
                    catch (Exception ex)
                    {
                        Utils.DebugPrint("Failed to send bubble on service " + b.Service.Information.ServiceName);

                        if (composeBubble != null)
                        {
                            composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        }

                        return false;
                    }

                    if (composeBubble != null)
                    {
                        composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed;
                        return false;
                    }

                    return true;
                }
            }));
        }