Example #1
0
File: Zyre.cs Project: NetMQ/Zyre
        /// <summary>
        /// Create a Zyre API that communicates with a node on the ZRE bus.
        /// </summary>
        /// <param name="name">The name of the node</param>
        /// <param name="useEvents">Set this to true to disable Receive() and instead subscribe to events for getting messages from peers. Default is true.</param>
        /// <param name="loggerDelegate">An action to take for logging when _verbose is true. Default is null.</param>
        public Zyre (string name, bool useEvents = true, Action<string> loggerDelegate = null)
        {
            _useEvents = useEvents;
            // Create front-to-back pipe pair for data traffic
            // outbox is passed to ZyreNode for sending Zyre message traffic back to _inbox
            PairSocket outbox;
            PairSocket.CreateSocketPair(out outbox, out _inbox);

            // Start node engine and wait for it to be ready
            // All node control is done through _actor

            _actor = ZyreNode.Create(outbox, loggerDelegate);

            if (useEvents)
            {
                _inboxPoller = new NetMQPoller();
                _inbox.ReceiveReady += InboxReceiveReady;
                _inboxPoller.RunAsync();
            }

            // Send name, if any, to node ending
            if (!string.IsNullOrEmpty(name))
            {
                _actor.SendMoreFrame("SET NAME").SendFrame(name);
            }
        }
Example #2
0
 /// <summary>
 ///     Subscribe to Nyx group
 /// </summary>
 /// <param name="topic"></param>
 /// <returns></returns>
 public void AddToGroup(string topic)
 {
     try
     {
         if (string.IsNullOrWhiteSpace(topic))
         {
             _logger.Warn("Topic is empty.");
             return;
         }
         if (_subscribersChannels.Contains(topic))
         {
             _logger.Warn($"Topic {topic} already registered.");
             return;
         }
         if (_subscribersChannels.Add(topic))
         {
             _actor?.SendMoreFrame("subscribe").SendFrame(topic);
         }
     }
     catch (Exception ex)
     {
         _logger.Error($"Error adding subscription {topic}.", ex);
     }
 }
Example #3
0
 public void Publish(NetMQMessage message)
 {
     // we can use actor like NetMQSocket
     _actor.SendMoreFrame(PublishMessageCommand).SendMultipartMessage(message);
 }
Example #4
0
 public void Subscribe(string topic)
 {
     _actor.SendMoreFrame(SubscribeCommand).SendFrame(topic);
 }
Example #5
0
 public void Publish(NetMQMessage message)
 {
     _actor.SendMoreFrame(PublishMessageCommand).SendMultipartMessage(message);
 }
Example #6
0
        /// <summary>
        ///     Default connect
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool Connect(string ipAddress = "", int port = 4015)
        {
            if (!IsStarted)
            {
                _logger.Error("Connection failed. Server not running.");
                if (_autostart)
                {
                    _logger.Info("AutoStart is on. Server starting.");
                    if (!Start().Select(x => true).Amb(Observable.Return(false).Delay(TimeSpan.FromSeconds(5))).Wait())
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }
            try
            {
                if (_isConnected && _lastHubIp == ipAddress)
                {
                    _logger.Trace("Connection to {0} is active, not reconnecting.", ipAddress);
                    return(true);
                }

                if (string.IsNullOrWhiteSpace(ipAddress))
                {
                    ipAddress = "127.0.0.1";
                }

                Heartbeat.Instance.Disconnected();
                _connectionDisposable?.Dispose();

                // Stop previous actor is any.
                try
                {
                    _actor?.SendFrame(NetMQActor.EndShimMessage);
                    //_actor?.Dispose();
                }
                catch (Exception ex)
                {
                    _logger.Error("NetMQ error.", ex);
                }
                _actor = null;
                // Store port and hub address
                _port      = port;
                _lastHubIp = ipAddress;

                Heartbeat.Instance.Setup(_lastHubIp, _port);
                // Create a new actor to handle the comunications from hub.
                _actor = NetMQActor.Create(BorgShimHandler.Create(_nyxMessageSubject, ipAddress, port));
                Heartbeat.Instance.Connected();

                CreateServerSocket();
                _config.Set("borg", "hubIp", _lastHubIp);

                // Global channel
                AddToGroup("global");
                // Custom channels
                SubscribersChannels.ForEach(c => _actor.SendMoreFrame("subscribe").SendFrame(c));
                _actor.SendMoreFrame("subscribe").SendFrame(NodeId);
                _isConnected          = true;
                _connectionDisposable = Disposable.Create(() => _isConnected = false);
                NyxMessage.Create(BasicHubAction.NyxId, BasicHubAction.Register, NodeId).Set("nodeID", NodeId).SendMessage(this);
            }
            catch (Exception ex)
            {
                _logger.Error("Error connecting...", ex);
                return(false);
            }
            return(true);
        }
Example #7
0
 /// <summary>
 /// Set Name (the public name of this node)
 /// </summary>
 /// <param name="name">the name to set</param>
 public void SetName(string name)
 {
     _actor.SendMoreFrame("SET NAME").SendFrame(name);
 }
Example #8
0
        /// <summary>
        /// Here we handle messages coming from other peers
        /// </summary>
        private void ReceivePeer()
        {
            Guid uuid;
            var  msg = ZreMsg.ReceiveNew(_inbox, out uuid);

            if (msg == null)
            {
                // Ignore a bad message (header or message signature doesn't meet http://rfc.zeromq.org/spec:36)
                _loggerDelegate?.Invoke("Ignoring a bad message (header or message signature doesn't meet http://rfc.zeromq.org/spec:36).");
                return;
            }
            if (uuid == _uuid)
            {
                var text = $"({_name}) Our own message should not be coming back to us! {_uuid}";
                _loggerDelegate?.Invoke(text);
                throw new InvalidOperationException(text);
            }
            _loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(ReceivePeer)}() received message={msg}");
            Debug.Assert(uuid != _uuid, $"({_name}) Our own message should not be coming back to us! uuid={_uuid}");
            ZyrePeer peer;

            if (!_peers.TryGetValue(uuid, out peer))
            {
                _loggerDelegate?.Invoke($"Peer {uuid.ToShortString6()} is unknown.");
            }
            if (msg.Id == ZreMsg.MessageId.Hello)
            {
                // On HELLO we may create the peer if it's unknown
                // On other commands the peer must already exist
                if (peer != null)
                {
                    // Remove fake peers
                    if (peer.Ready)
                    {
                        _loggerDelegate?.Invoke("Removing fake peer={peer} because we received another HELLO from the same uuid.");
                        RemovePeer(peer);
                        Debug.Assert(!_peers.ContainsKey(uuid));
                    }
                    else if (peer.Endpoint == _endpoint)
                    {
                        // We ignore HELLO, if peer has same endpoint as current node
                        _loggerDelegate?.Invoke("Ignoring HELLO for peer that has same endpoint as current node.");
                        return;
                    }
                }
                peer = RequirePeer(uuid, msg.Hello.Endpoint);
                //_loggerDelegate?.Invoke($"TMP Did {nameof(RequirePeer)}");
                peer.Ready = true;
            }
            if (peer == null)
            {
                _loggerDelegate?.Invoke("Ignoring null peer");
                return;
            }
            if (!peer.Ready)
            {
                // Ignore command if peer isn't ready
                _loggerDelegate?.Invoke($"Ignoring peer that isn't ready: {peer}");
                return;
            }
            if (peer.MessagesLost(msg))
            {
                _loggerDelegate?.Invoke($"MessagesLost! {nameof(ZyreNode)}.{nameof(ReceivePeer)}() ignoring message={msg} and removing peer={peer} ");
                RemovePeer(peer);
                return;
            }

            // Now process each command
            _loggerDelegate?.Invoke($"{nameof(ZyreNode)}.{nameof(ReceivePeer)}() is now ready to process this {msg.Id} command.");
            switch (msg.Id)
            {
            case ZreMsg.MessageId.Hello:
                // Store properties from HELLO command into peer
                var helloMessage = msg.Hello;
                peer.Name    = helloMessage.Name;
                peer.Headers = helloMessage.Headers;

                // Tell the caller about the peer
                var headersBuffer = Serialization.BinarySerialize(peer.Headers);
                _outbox.SendMoreFrame("ENTER").SendMoreFrame(peer.Uuid.ToByteArray()).SendMoreFrame(peer.Name).SendMoreFrame(headersBuffer).SendFrame(helloMessage.Endpoint);
                _loggerDelegate?.Invoke($"ENTER name={peer.Name} endpoint={peer.Endpoint}");

                // Join peer to listed groups
                foreach (var groupName in helloMessage.Groups)
                {
                    JoinPeerGroup(peer, groupName);
                }

                // Now take peer's status from HELLO, after joining groups
                peer.Status = helloMessage.Status;
                _loggerDelegate?.Invoke($"Hello message has been processed for peer: {peer}");
                break;

            case ZreMsg.MessageId.Whisper:
                // Pass up to caller API as WHISPER event
                _outbox.SendMoreFrame("WHISPER").SendMoreFrame(uuid.ToByteArray()).SendMoreFrame(peer.Name).SendMultipartMessage(msg.Whisper.Content);
                break;

            case ZreMsg.MessageId.Shout:
                // Pass up to caller API as SHOUT event
                _outbox.SendMoreFrame("SHOUT").SendMoreFrame(uuid.ToByteArray()).SendMoreFrame(peer.Name).SendMoreFrame(msg.Shout.Group).SendMultipartMessage(msg.Shout.Content);
                break;

            case ZreMsg.MessageId.Join:
                JoinPeerGroup(peer, msg.Join.Group);
                Debug.Assert(msg.Join.Status == peer.Status);
                break;

            case ZreMsg.MessageId.Leave:
                LeavePeerGroup(peer, msg.Leave.Group);
                Debug.Assert(msg.Leave.Status == peer.Status);
                break;

            case ZreMsg.MessageId.Ping:
                // Respond to a PING request with PING-OK, always
                _actor.SendMoreFrame("PING-OK").SendFrame(uuid.ToByteArray());
                // Notify Zyre application PING came in
                _outbox.SendMoreFrame("PING").SendMoreFrame(uuid.ToByteArray()).SendFrame(peer.Name);
                break;

            case ZreMsg.MessageId.PingOk:
                // Good, the peer is alive, we will reset our timers
                // with the peer.Refresh(); call below.
                _outbox.SendMoreFrame("PING-OK").SendMoreFrame(uuid.ToByteArray()).SendFrame(peer.Name);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // Activity from peer resets peer timers
            peer.Refresh();
            //_loggerDelegate?.Invoke($"TMP Leaving {nameof(ReceivePeer)}");
        }
Example #9
0
        public Zyre (string name)
        {
            // Create front-to-back pipe pair for data traffic
            // outbox is passed to ZreNode for sending Zyre message traffic back to _inbox
            PairSocket outbox;
            PairSocket.CreateSocketPair(out outbox, out _inbox);

            // Start node engine and wait for it to be ready
            // All node control is done through _actor
            _actor = ZreNode.Create(outbox);

            // Send name, if any, to node ending
            if (!string.IsNullOrEmpty(name))
            {
                _actor.SendMoreFrame("SET NAME").SendFrame(name);
            }
        }