/// <summary> /// Construct new ZyrePeer object /// </summary> /// <param name="container">The dictionary of peers</param> /// <param name="guid">The identity for this peer</param> /// <param name="loggerDelegate">An action to take for logging when _verbose is true. Default is null.</param> /// <returns></returns> internal static ZyrePeer NewPeer(Dictionary <Guid, ZyrePeer> container, Guid guid, Action <string> loggerDelegate = null) { var peer = new ZyrePeer(guid, loggerDelegate); container[guid] = peer; // overwrite any existing entry for same uuid return(peer); }
/// <summary> /// Delete peer for a given endpoint /// </summary> /// <param name="peer"></param> /// <param name="endpoint"></param> private void PurgePeer(ZyrePeer peer, string endpoint) { if (peer.Endpoint == endpoint) { peer.Disconnect(); } }
/// <summary> /// We do this once a second: /// - if peer has gone quiet, send TCP ping and emit EVASIVE event /// - if peer has disappeared, expire it /// </summary> /// <param name="peer">the peer to ping</param> /// <returns>true if this peer should be removed</returns> private bool PingPeer(ZyrePeer peer) { if (!_isRunning) { // We have been stopped. We know longer can communicate to peers. return(true); } if (DateTime.Now >= peer.ExpiredAt) { return(true); } if (DateTime.Now >= peer.EvasiveAt) { // If peer is being evasive, force a TCP ping. // ZeroMQTODO: do this only once for a peer in this state; // it would be nicer to use a proper state machine // for peer management. _loggerDelegate?.Invoke($"Peer seems dead/slow: name={peer.Name} endpoint={peer.Endpoint}"); ZreMsg.SendPing(_outbox, 0); // Inform the calling application this peer is being evasive _outbox.SendMoreFrame("EVASIVE"); _outbox.SendMoreFrame(peer.Uuid.ToByteArray()); _outbox.SendFrame(peer.Name); } return(false); }
/// <summary> /// Join peer to group /// </summary> /// <param name="peer">The peer that is joining this group</param> /// <param name="groupName">The name of the group to join</param> /// <returns>the group joined</returns> private void JoinPeerGroup(ZyrePeer peer, string groupName) { var group = RequirePeerGroup(groupName); group.Join(peer); // Now tell the caller about the peer joined group _outbox.SendMoreFrame("JOIN").SendMoreFrame(peer.Uuid.ToByteArray()).SendMoreFrame(peer.Name).SendFrame(groupName); _loggerDelegate?.Invoke($"JOIN name={peer.Name} group={groupName}"); }
/// <summary> /// Have peer leave group /// </summary> /// <param name="peer"></param> /// <param name="groupName"></param> /// <returns></returns> private void LeavePeerGroup(ZyrePeer peer, string groupName) { var group = RequirePeerGroup(groupName); group.Leave(peer); // Now tell the caller about the peer left group _outbox.SendMoreFrame("LEAVE").SendMoreFrame(peer.Uuid.ToByteArray()).SendMoreFrame(peer.Name).SendFrame(groupName); _loggerDelegate?.Invoke($"LEAVE name={peer.Name} group={groupName}"); }
/// <summary> /// Remove a peer from our data structures /// </summary> /// <param name="peer"></param> private void RemovePeer(ZyrePeer peer) { // Tell the calling application the peer has gone _outbox.SendMoreFrame("EXIT").SendMoreFrame(peer.Uuid.ToByteArray()).SendFrame(peer.Name); _loggerDelegate?.Invoke($"EXIT name={peer.Name} endpoint={peer.Endpoint}"); // Remove peer from any groups we've got it in foreach (var peerGroup in _peerGroups.Values) { RemovePeerFromGroup(peerGroup, peer); } _peers.Remove(peer.Uuid); peer.Destroy(); }
/// <summary> /// Find or create peer via its UUID /// </summary> /// <param name="uuid">the identity of peer</param> /// <param name="endpoint">the endpoint to which we will connect the new peer</param> /// <returns>A peer (existing, or new one connected to endpoint)</returns> private ZyrePeer RequirePeer(Guid uuid, string endpoint) { Debug.Assert(!string.IsNullOrEmpty(endpoint)); ZyrePeer peer; if (_peers.TryGetValue(uuid, out peer)) { if (!_reportedKnownPeersTmp.Contains(peer)) { //var callingMethod1 = MethodNameLevelAbove(); //_loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() called by {callingMethod1} returning already-known peer={peer}"); _loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() returning already-known peer={peer}"); _reportedKnownPeersTmp.Add(peer); } return(peer); } // Purge any previous peer on same endpoint foreach (var existingPeer in _peers.Values) { PurgePeer(existingPeer, endpoint); } //var callingMethod2 = MethodNameLevelAbove(); //_loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() called by {callingMethod2} creating new peer with uuidShort={uuid.ToShortString6()}"); _loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() creating new peer with uuidShort={uuid.ToShortString6()}"); peer = ZyrePeer.NewPeer(_peers, uuid, _loggerDelegate); peer.Origin = _name; peer.Connect(_uuid, endpoint); // Handshake discovery by sending HELLO as first message var helloMessage = new ZreMsg { Id = ZreMsg.MessageId.Hello, Hello = { Endpoint = _endpoint, Groups = _ownGroups.Keys.ToList(), Status = _status, Name = _name, Headers = _headers } }; //_loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() called by {callingMethod2} created new peer={peer}. Sending Hello message..."); _loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(RequirePeer)}() created new peer={peer}. Sending Hello message..."); peer.Send(helloMessage); return(peer); }
/// <summary> /// We do this once a second: /// - if peer has gone quiet, send TCP ping and emit EVASIVE event /// - if peer has disappeared, expire it /// </summary> /// <param name="peer">the peer to ping</param> /// <returns>true if this peer should be removed</returns> private bool PingPeer(ZyrePeer peer) { if (!_isRunning) { // We have been stopped. We know longer can communicate to peers. return true; } if (DateTime.Now >= peer.ExpiredAt) { return true; } if (DateTime.Now >= peer.EvasiveAt) { // If peer is being evasive, force a TCP ping. // ZeroMQTODO: do this only once for a peer in this state; // it would be nicer to use a proper state machine // for peer management. _loggerDelegate?.Invoke($"Peer seems dead/slow: name={peer.Name} endpoint={peer.Endpoint}"); ZreMsg.SendPing(_outbox, 0); // Inform the calling application this peer is being evasive _outbox.SendMoreFrame("EVASIVE"); _outbox.SendMoreFrame(peer.Uuid.ToByteArray()); _outbox.SendFrame(peer.Name); } return false; }
/// <summary> /// Remove peer from group, if it's a member /// </summary> /// <param name="group"></param> /// <param name="peer"></param> private void RemovePeerFromGroup(ZyreGroup group, ZyrePeer peer) { group.Leave(peer); }
/// <summary> /// Add peer to group /// Ignore duplicate joins /// </summary> /// <param name="peer"></param> internal void Join(ZyrePeer peer) { _peers[peer.Uuid] = peer; peer.IncrementStatus(); }
/// <summary> /// Remove peer from group /// </summary> /// <param name="peer"></param> internal void Leave(ZyrePeer peer) { _peers.Remove(peer.Uuid); peer.IncrementStatus(); }
// /// <summary> // /// Return a string showing the class name and method of method calling the method calling this method, used for reporting errors // /// </summary> // /// <returns>the name of the calling method</returns> // private static string MethodNameLevelAbove() // { // var stackTrace = new System.Diagnostics.StackTrace(new Exception(), false); // var stackFrame = stackTrace.GetFrames()[2]; // var mb = stackFrame.GetMethod(); // return mb.ReflectedType.Name + ":" + mb.Name + "()"; // } /// <summary> /// Remove peer from group, if it's a member /// </summary> /// <param name="group"></param> /// <param name="peer"></param> private void RemovePeerFromGroup(ZyreGroup group, ZyrePeer peer) { group.Leave(peer); }
/// <summary> /// Construct new ZyrePeer object /// </summary> /// <param name="container">The dictionary of peers</param> /// <param name="guid">The identity for this peer</param> /// <param name="loggerDelegate">An action to take for logging when _verbose is true. Default is null.</param> /// <returns></returns> internal static ZyrePeer NewPeer(Dictionary<Guid, ZyrePeer> container, Guid guid, Action<string> loggerDelegate = null) { var peer = new ZyrePeer(guid, loggerDelegate); container[guid] = peer; // overwrite any existing entry for same uuid return peer; }