Example #1
0
        /// <summary>
        /// Ensures the message of type <typeparamref name="TMessage"/> and matching predicate <paramref name="predicate"/> is received.<br/>
        /// If one or more matching messages were already received by listener, the latest matching message is returned immediately.<br/>
        /// If no matching messages were received yet, the method listens for upcoming messages and returns when matching one arrives, timeout occurs or <paramref name="cancellationToken"/> is cancelled.<br/>
        /// </summary>
        /// <typeparam name="TMessage">Type of message to receive.</typeparam>
        /// <param name="predicate">Predicate that message have to match to be returned.</param>
        /// <param name="timeout">Timeout for how long the method should await for matching message to arrive. If <c>null</c>, a default value of 10s will be used.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <returns>Latest matching message</returns>
        /// <exception cref="TimeoutException">Thrown when timeout occurs and no matching message was received.</exception>
        /// <exception cref="MessagePredicateEvaluationException">Thrown when provided predicate failed evaluation on received message.</exception>
        public async Task <TMessage> EnsureReceived <TMessage>(Func <TMessage, bool> predicate, TimeSpan?timeout = null, CancellationToken cancellationToken = default)
        {
            bool PredicateFn(TMessage m) => IsValidMessage(m, predicate);

            using var waiter = new MessageWaiter <TMessage>(this, PredicateFn);
            using var cts    = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _listenerDisposedTokenSource.Token);
            return(await waiter.WaitAsync(timeout ?? DefaultTimeout, cts.Token));
        }
Example #2
0
        private void OnSGameConnected(NetPeer peer)
        {
            var newNodeInfoWaiter = new MessageWaiter <SShared.Messages.NodeConfig>(_busMaster, peer).Wait;

            newNodeInfoWaiter.Wait();
            var newNodeInfo = newNodeInfoWaiter.Result;

            var newNode = _routingTable.AddSGameNode(peer, newNodeInfo.BusAddress, newNodeInfo.BusPort, newNodeInfo.ApiUrl);

            Console.Error.WriteLine(">>> SGame node {0} (API: {1}) connected at {2} <<<", peer.EndPoint, newNode.ApiUrl, newNode.Path());

            // IMPORTANT: Send the whole network topology (as of now) to the new node (so that it can build a routing table for itself)
            foreach (var treeNode in _routingTable.RootNode.Traverse().Cast <ArbiterTreeNode>())
            {
                if (treeNode.Peer == peer)
                {
                    continue;
                }

                var otherNodeConfig = new SShared.Messages.NodeConfig()
                {
                    BusAddress = treeNode.BusAddress,
                    BusPort    = treeNode.BusPort,
                    Bounds     = treeNode.Bounds,
                    Path       = treeNode.Path(),
                    ApiUrl     = treeNode.ApiUrl,
                };
                _busMaster.SendMessage(otherNodeConfig, peer, DeliveryMethod.ReliableOrdered);
            }

            // IMPORTANT: Broadcast that the new node is online and where it is (incl. the new node itself to tell it its path)
            var newNodeConfig = new SShared.Messages.NodeConfig()
            {
                BusAddress = newNode.BusAddress,
                BusPort    = newNode.BusPort,
                Bounds     = newNode.Bounds,
                Path       = newNode.Path(),
                ApiUrl     = newNode.ApiUrl,
            };

            _busMaster.BroadcastMessage(newNodeConfig, DeliveryMethod.ReliableOrdered);
        }
Example #3
0
        public virtual Task <IMessageWaiter> GetAsync(IEnumerable <Type> messageTypes, Func <IMessage, bool> filter)
        {
            IEnumerable <Type> messageTypesArray = messageTypes as Type[] ?? messageTypes.ToArray();

            // Create one waiter for message type
            var messageWaitersGroup = new List <MessageWaiter>();

            foreach (Type messageType in messageTypesArray)
            {
                ConcurrentDictionary <IInternalMessageWaiter, bool> eventWaiter = _messageWaiters.GetOrAdd(messageType, o => new ConcurrentDictionary <IInternalMessageWaiter, bool>());

                var messageWaiter = new MessageWaiter(messageType, filter);
                eventWaiter.TryAdd(messageWaiter, true);

                // Keep track of the group
                messageWaitersGroup.Add(messageWaiter);
            }

            return(Task.FromResult <IMessageWaiter>(new MessageWaiterGroup(this, messageTypesArray, messageWaitersGroup)));
        }
Example #4
0
        public override Messages.Struck ScanShootLocal(Messages.ScanShoot msg)
        {
            bool affected = MathUtils.DoesQuadIntersectCircleSector(this.Bounds, msg);

            if (affected)
            {
                Bus.SendMessage(msg, NodePeer);

                var             struckTask = new MessageWaiter <Messages.Struck>(Bus, NodePeer, (struck) => struck.Originator == msg.Originator).Wait;
                Messages.Struck results    = new Messages.Struck();
                if (Task.WaitAll(new Task[] { struckTask }, REPLYTIMEOUT))
                {
                    results.OriginatorAreaGain += struckTask.Result.OriginatorAreaGain;
                    results.ShipsInfo.AddRange(struckTask.Result.ShipsInfo);
                }
                return(results);
            }
            else
            {
                return(null);
            }
        }
Example #5
0
        public async Task <bool> RemoveSGameNode(NetPeer peer)
        {
            if (RootNode == null)
            {
                return(false);
            }

            var disconnectedNode = RootNode.Traverse().Cast <ArbiterTreeNode>().Where((node) => node.Peer == peer).FirstOrDefault();

            if (disconnectedNode == null)
            {
                return(false);
            }

            ArbiterTreeNode substituteNode;

            if (disconnectedNode.Parent == null)
            {
                ArbiterTreeNode childToPromote = (ArbiterTreeNode)disconnectedNode.FirstChild();
                if (childToPromote == null)
                {
                    substituteNode = null;
                    RootNode       = null;
                }
                else
                {
                    substituteNode = childToPromote;
                }
            }
            else
            {
                ArbiterTreeNode leafToPromote = (ArbiterTreeNode)disconnectedNode.RandomLeafNode();
                if (leafToPromote == null)
                {
                    // No leaf means `disconnectedNode` had no childtren, so we just send the ships to the parent
                    substituteNode = (ArbiterTreeNode)disconnectedNode.Parent;
                }
                else
                {
                    substituteNode = leafToPromote;
                }
            }

            if (substituteNode != null)
            {
                Console.Error.WriteLine("Moving ships that were in {0} to {1}", disconnectedNode.Path(), substituteNode.Path());
            }
            else
            {
                Console.Error.WriteLine("There is no node to promote to root!");
            }

            // New substitute node retains his children but also gets the new ones
            // We assume the disconnected node persisted its ships to Elastic before dying;
            // if it has, the connect REST calls below will transfer the ships to the substitute!
            foreach (var token in _nodeByShipToken.Keys.ToList())
            {
                if (_nodeByShipToken[token] == disconnectedNode)
                {
                    if (substituteNode != null)
                    {
                        var connectWaiter = new MessageWaiter <Messages.ShipConnected>(BusMaster, substituteNode.Peer).Wait;
                        BusMaster.SendMessage(new Messages.ShipConnected()
                        {
                            Token = token
                        }, substituteNode.Peer);
                        await connectWaiter;
                    }
                    _nodeByShipToken[token] = substituteNode;
                }
            }

            if (substituteNode != null)
            {
                if (substituteNode.Parent != null)
                {
                    substituteNode.Parent.SetChild(substituteNode.Quadrant, null);
                }

                if (disconnectedNode.Parent != null)
                {
                    disconnectedNode.Parent.SetChild(disconnectedNode.Quadrant, substituteNode);
                }
                else
                {
                    substituteNode.MakeRoot(new Quad(0.0, 0.0, UniverseSize));
                    RootNode = substituteNode;
                }

                BusMaster.BroadcastMessage(new Messages.NodeOffline()
                {
                    Path   = disconnectedNode.Path(),
                    ApiUrl = disconnectedNode.ApiUrl,
                }, DeliveryMethod.ReliableOrdered);

                BusMaster.BroadcastMessage(new Messages.NodeConfig()
                {
                    BusAddress = substituteNode.BusAddress,
                    BusPort    = substituteNode.BusPort,
                    Bounds     = substituteNode.Bounds,
                    Path       = substituteNode.Path(),
                    ApiUrl     = substituteNode.ApiUrl,
                }, DeliveryMethod.ReliableOrdered);
            }

            return(true);
        }