/// <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)); }
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); }
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))); }
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); } }
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); }