private void ProcessMessageActions(INyxMessage msg) { try { var action = msg.Action; var borgPlugins = _plugman.GetActions <IBorgAction>(p => p.SupportedActions.Contains(action)).ToList(); if (borgPlugins.Count == 0) { return; } var sw = Stopwatch.StartNew(); _logger.Trace("Plugins with action {0}: {1} in {2}", msg.Action, borgPlugins.Count(), _plugman.GetActions <IBorgAction>().Count()); void forAction(IBorgAction borgPlug) { try { _logger.Debug("Running action {0} for message {1} on processor {2}", msg.Action, msg, borgPlug.GetType().Name); borgPlug.ProcessMessage(msg.AsReadOnly()); } catch (Exception ex) { _logger.Error($"Error running action on {borgPlug.GetType().Name}", ex); } } borgPlugins.ForEach(forAction); _logger.Trace("Message actions took {0}ms", sw.ElapsedMilliseconds); sw.Stop(); } catch (Exception ex) { _logger.Error("Error processing actions.", ex); } }
/// <summary> /// Broadcast message to the given channel(s) /// </summary> /// <param name="msg"></param> public void BroadcastMessage(INyxMessage msg) { if (!_isStarted || _hubActor == null) { _logger.Warn("Hub is not started."); return; } _logger.Debug("Broadcasting message to channel {0}...", StringExtensions.Trimmer(msg.Target)); ((NyxMessage)msg).Direction = MessageDirection.Out; var error = string.Empty; try { var filterFound = _plugman.GetFilters(f => f.Direction.HasFlag(MessageDirection.Out) && f.CanFilter(this)).FirstOrDefault(filter => !filter.AllowMessage(msg, this, out error)); if (filterFound != null) { _logger.Warn("Message not sent. Was filtered by {0}. {1}", filterFound.GetType().Name, error); return; } } catch (Exception ex) { _logger.Error("Error filtering message.", ex); } _hubActor.SendMoreFrame("broadcast").SendMoreFrame(msg.Target).SendFrame(msg.ToDefault()); _outMessageStatus.OnNext(msg.AsReadOnly().SuccessfullSent(this)); }
public override bool ProcessMessage(INyxMessage msg) { if (_hub == null) { return(true); } switch (msg.Action) { case Register: _logger.Info("Registered node {0}", StringExtensions.Trimmer(msg.Source)); _hub.BroadcastMessage(new NyxMessage { Target = msg.Source, Action = Callback, Source = NyxId }.Set("event", "registered") ); break; case Ping: _logger.Info("Node {0} pinged.", StringExtensions.Trimmer(msg.Source)); msg.Reply(Pong).BroadcastMessage(_hub); break; default: return(false); } return(true); }
/// <summary> /// Prepares nodes info /// </summary> /// <param name="message"></param> /// <param name="sender"></param> private void PrepareNodeInfo(INyxMessage message, INyxNode sender) { NodeInfo nodeInfo; try { nodeInfo = NodeInfo.BuildInfo((INyxBorg)sender); } catch (Exception ex) { _logger.Error("Error building node info.", ex); return; } var plugs = _pluginManager.GetExtensions().Where(e => e.GetType().IsAssignableTo <IExtendNodeInfo>()).Cast <IExtendNodeInfo>(); var sw = Stopwatch.StartNew(); Action <IExtendNodeInfo> act = p => { sw.Restart(); try { p.AddExtraData(nodeInfo); } catch (Exception ex) { _logger.Error($"Error adding extra info from type {p?.GetType().FullName}.", ex); } _logger.Trace("{0} took {1}ms to add node info.", p.GetType().FullName, sw.ElapsedMilliseconds); }; sw.Stop(); plugs.ForEach(act); message.Set(NodeManagerInfo, nodeInfo); }
/// <summary> /// Allows all messages to pass, just add new info to them, or removes so they don't get into the borgs by mistake. /// </summary> /// <param name="message"></param> /// <param name="sender"></param> /// <param name="error"></param> /// <returns></returns> public bool AllowMessage(INyxMessage message, INyxNode sender, out string error) { lock (FilterLock) { error = string.Empty; if (sender is INyxBorg) { if (message.Direction == MessageDirection.Out) { PrepareNodeInfo(message, sender); } return(true); } var msg = message.AsReadOnly(); // We use a queue _tasker.QueueTask(() => { try { RunNodeCollector(msg); } catch (Exception ex) { _logger.Error("Error processing node info.", ex); } }); } return(true); }
/// <summary> /// Converts a NyxMessage to Json and then to a NetMQMessage /// </summary> /// <param name="msg">Nyx message</param> /// <returns>Converted NetMQMessage</returns> public static NetMQMessage ToJsonMessage(this INyxMessage msg) { var zmsg = new NetMQMessage(); zmsg.Push(msg.ToJson()); return(zmsg); }
/// <summary> /// Converts a NyxMessage to the default type and then to a NetMQMessage. /// This should be plugable... for future proof /// </summary> /// <param name="msg">Nyx message</param> /// <returns>Converted NetMQMessage</returns> public static NetMQMessage ToNetMQMessage(this INyxMessage msg) { // TODO: Add plugin support or atleast configuration support, so we can var zmsg = new NetMQMessage(); zmsg.Push(msg.ToDefault()); return(zmsg); }
/// <summary> /// Converts <see cref="INyxMessage"/> into a <see cref="ReadOnlyNyxMessage"/> if it isn't read only yet./> /// <remarks>Note that this doesn't create a new message every call, only if needed.</remarks> /// </summary> /// <param name="msg">Read only <see cref="INyxMessage"/>.</param> /// <returns></returns> public static INyxMessage AsReadOnly([NotNull] this INyxMessage msg) { if (msg is ReadOnlyNyxMessage) { return(msg); } return(new ReadOnlyNyxMessage(msg)); }
public MessageStatus(INyxNode sender, INyxMessage msg, MessageCondition condition, string description, bool hubReply) { Sender = sender; Message = msg; Status = condition; IsHubReply = hubReply; Description = description; }
public bool TransferFiles(INyxMessage message, INyxBorg sender) { if (message.Has("fileTransfer")) { return(true); } _taskQueue.QueueTask(() => AsyncLoadToMessage(message, sender)); return(false); }
public bool ExtractFiles(INyxMessage message, INyxBorg nyxBorg) { if (message.Has("fileExtract")) { return(true); } _taskQueue.QueueTask(() => AsyncExtractFiles(message, nyxBorg)); return(false); }
/// <summary> /// Queues a message for sending to the hub for distribution. /// </summary> /// <param name="msg">Nyx message to send.</param> /// <param name="skip">Doesn't queue the message if no connection to the hub.</param> /// <returns>An observable for checking when the message is delivered to the Hub.</returns> public IObservable <MessageStatus> SendMessage(INyxMessage msg, bool skip = false) { if (msg == null) { return(Observable.Return(new MessageStatus(this, NyxMessage.EmptyOut, MessageCondition.Failed, "Null message"))); } if (string.IsNullOrWhiteSpace(msg.Source)) { msg.Source = NodeId; } if (string.IsNullOrWhiteSpace(msg.Target)) { _logger.Error("Message validation failed, missing Target."); return(Observable.Return(new MessageStatus(this, msg, MessageCondition.Failed, "Message validation failed, missing Target."))); } // Processes internal messages like they were external messages. if (msg is InternalNyxMessage) { return(Observable.Start(() => ProcessExternalMessages(msg))); } if ((!_isConnected && !_queueOnDisconnected) || (!_hubOnline && skip) || (!_isConnected && skip)) { _logger.Debug("Message missed. Not connected to any hub, or hub offline."); return(Observable.Return(new MessageStatus(this, msg, MessageCondition.Failed, "Not connected to any hub."))); } if (_messageLoopCancelation.IsCancellationRequested) { _logger.Error("Message missed. Not connected to any hub, or hub offline."); return(Observable.Return(new MessageStatus(this, msg, MessageCondition.Failed, "Borg is going down."))); } ((NyxMessage)msg).Direction = MessageDirection.Out; var observable = Observable.Create <MessageStatus>(observer => { return(OutMessageStream.Where(m => m?.Message.Id == msg.Id).Subscribe(n => { observer.OnNext(n); switch (n.Status) { case MessageCondition.Failed: case MessageCondition.Filtered: case MessageCondition.Sent: observer.OnCompleted(); break; } })); }); lock (MessageQueueSync) _messageQueue.Enqueue(new MessageHelper { Message = msg }); _messageSendResetEvent.Set(); return(observable); }
/// <summary> /// Creates a reply message, by switching the target and source and maitaining the previous data bag. /// Also adds info from the previous message. /// <remarks>All file data is not transfered.</remarks> /// </summary> /// <param name="msg">Source message</param> /// <param name="action">Message action</param> /// <returns></returns> public static INyxMessage ReplyWithData(this INyxMessage msg, string action) { var reply = new NyxMessage(msg.Source, action, msg.Target).Set(CoreParamsOriginalMessageId, msg.ShortId()); foreach (var element in msg.Elements) { reply.Set(element.Key, element.Value); } return(reply); }
public ReadOnlyNyxMessage(INyxMessage message) { Id = message.Id; _target = message.Target; _source = message.Source; _action = message.Action; Direction = message.Direction; Elements = new ReadOnlyDictionary <string, object>((IDictionary <string, object>)message.Elements); Files = new ReadOnlyCollection <IFile>(message.Files); }
private MessageStatus ProcessExternalMessages(INyxMessage msg) { if (FilterMessage(msg)) { return(msg.Filtered(this, "Filtered.")); } if (msg.Direction == MessageDirection.In) { ProcessMessageActions(msg.AsReadOnly()); } _messageReceived.OnNext(msg.SuccessfullReceived(this)); return(msg.SuccessfullSent(this)); }
/// <summary> /// Send the info to the requester <see cref="INyxBorg" />. /// </summary> /// <param name="sourceMessage">Source message</param> /// <param name="target">Target for receiveing the updates</param> /// <param name="added">Nodes added.</param> /// <param name="removed">Nodes removed.</param> private void SendNodesInfo([CanBeNull] INyxMessage sourceMessage, [CanBeNull] string target, [NotNull] IEnumerable <NodeInfo> added, [NotNull] IEnumerable <NodeInfo> removed, bool cleanup = false) { _logger.Debug("Pushing node updates to {0}", target); var msg = string.IsNullOrWhiteSpace(target) ? sourceMessage.Reply(NodesInfoReport) : new NyxMessage(target, NodesInfoReport, "Nyx"); msg.Set(NodeManagerAdded, added.ToArray()); msg.Set(NodeManagerRemoved, removed.ToArray()); msg.Set(NodeManagerCleanup, cleanup); _hub.BroadcastMessage(msg); }
/// <summary> /// Converts a INyxMessage into a internal message. /// This is used to communicate inside borg, it nevers leaves the borg. /// Internal messages are processed by the message filters and message processors, like they were received. /// </summary> /// <param name="msg"></param> /// <returns></returns> public static INyxMessage AsInternal([NotNull] this INyxMessage msg) { if (msg is InternalNyxMessage) { return(msg); } var nmsg = msg as NyxMessage; return(nmsg == null ? null : new InternalNyxMessage(nmsg) { Direction = MessageDirection.In }); }
/// <summary> /// Process messages on borg or host conform the case. /// </summary> /// <param name="message">Message to process.</param> /// <returns></returns> public bool ProcessMessage(INyxMessage message) { // We lock here so we can process this without caring too much. lock (ProcessLock) { if (_hub != null) { _messageReceivedHub.OnNext(message); switch (message.Action) { case NodesInfo: SendNodesInfo(message, new List <NodeInfo>(_nodesInfo), new List <NodeInfo>(), true); return(true); case NodesUpdateSubscribe: SendNodesInfo(message, new List <NodeInfo>(_nodesInfo), new List <NodeInfo>(), true); lock (UpdaterLock) { if (!_pushUpdates.Contains(message.Source)) { _pushUpdates.Add(message.Source); } } break; case NodesPing: // This is just so we update the info of the node, no action required. break; } return(true); } if (_borg == null) { return(true); } switch (message.Action) { case NodesInfoReport: BuildReportFromMessage(message); break; } _messageReceivedBorg.OnNext(message); } return(true); }
private bool FilterMessage(INyxMessage msg) { var abort = false; try { var error = string.Empty; var filters = _plugman.GetFilters(f => f.Direction.HasFlag(msg.Direction) && f.CanFilter(this)).ToList(); if (!filters.Any()) { return(true); } var sw = Stopwatch.StartNew(); var filterFound = filters.FirstOrDefault(filter => msg != null && !filter.AllowMessage(msg, this, out error)); if (filterFound != null) { if (error != string.Empty) { _logger.Warn("Message {0} was filtered by {1}. {2}", msg, filterFound.GetType().Name, error); } var messageStatus = msg.Filtered(this, $"Message was filtered by {filterFound.GetType().Name}."); if (!(msg is InternalNyxMessage) && msg.Direction == MessageDirection.In) { _messageReceived.OnNext(messageStatus); } if (!(msg is InternalNyxMessage) && msg.Direction == MessageDirection.Out) { _messageReplyReceived.OnNext(msg.Filtered(this, error)); } abort = true; } _logger.Trace("Message filter took {0}ms", sw.ElapsedMilliseconds); } catch (Exception ex) { _logger.Error("Error processing filter.", ex); } return(abort); }
private void BuildReportFromMessage(INyxMessage message) { lock (NodesLock) { var added = message.Get <IEnumerable <NodeInfo> >(NodeManagerAdded); var removed = message.Get <IEnumerable <NodeInfo> >(NodeManagerRemoved); var cleanup = message.Get <bool>(NodeManagerCleanup); // Cache all nodes info on borg. if (cleanup) { _nodesInfo.Clear(); removed = new List <NodeInfo>(_nodesInfo); } else { _nodesInfo.RemoveAll(p => removed.Any(r => p?.NodeId == r.NodeId)); } var addedNodes = added as IList <NodeInfo> ?? added.ToList(); if (added != null) { _nodesInfo.RemoveAll(n => addedNodes.Any(o => o.NodeId == n.NodeId)); _nodesInfo.AddRange(addedNodes); } UpdateGroupInfo(); // Internal broadcast the info to the message bus, so ui can get the updates. var managerMessage = new NodesChanges { Added = addedNodes, Removed = removed, All = new List <NodeInfo>(_nodesInfo) }; _nodesSubject.OnNext(managerMessage); _groupSubject.OnNext(_groups.Clone()); } }
/// <summary> /// Override this for handling the SubSocket receive /// </summary> /// <param name="msg"></param> private void ReceivedMessage(INyxMessage msg) { var data = string.Empty; try { _logger.Trace("Received message..."); _logger.Trace("Message source: {0}", msg.Source); if (FilterMessage(msg)) { return; } // Run message processing in another thread var readOnly = msg.AsReadOnly(); void processMessages() => ProcessMessageActions(readOnly); if (_multithread) { _tasker.QueueTask(processMessages); } else { processMessages(); } // Notify _messageReceived.OnNext(msg.SuccessfullReceived(this)); } catch (Exception ex) { _logger.Error($"Exception caught in message {data}.", ex); } }
public MessageStatus(INyxNode sender, INyxMessage msg, MessageCondition condition, bool hubReply) : this(sender, msg, condition, string.Empty, hubReply) { }
public MessageStatus(INyxNode sender, INyxMessage msg, MessageCondition condition, string description) : this(sender, msg, condition, description, false) { }
public static IObservable <INyxMessage> IsReplyTo(this IObservable <INyxMessage> observable, INyxMessage message) { return(observable.Where(m => m?.IsReplyTo(message) ?? false)); }
/// <summary> /// Timeouts the message and returns a Failed message status. /// </summary> /// <param name="observable"></param> /// <param name="timeoutSeconds"></param> /// <param name="msg"></param> /// <returns></returns> public static IObservable <MessageStatus> TimeoutMessage(this IObservable <MessageStatus> observable, double timeoutSeconds, INyxMessage msg) { return(observable .Amb(Observable.Return(msg.Timeout(null, "Timeout waiting for message.")).Delay(TimeSpan.FromSeconds(timeoutSeconds * 2)))); }
public bool SeedFiles(INyxMessage message, INyxHub nyxHub) { // Do nothing just pass the file return(true); }
/// <summary> /// Always create a new <see cref="ReadOnlyNyxMessage"/> from a <see cref="INyxMessage"/>./> /// </summary> /// <param name="msg">Read only <see cref="INyxMessage"/>.</param> /// <returns></returns> public static INyxMessage ToReadOnly(this INyxMessage msg) { return(new ReadOnlyNyxMessage(msg)); }
public static INyxMessage FromDefault(this INyxMessage msg, string message) { return(msg.FromJson(message)); }
/// <summary> /// Converts a NyxMessage to json format /// </summary> /// <param name="msg"></param> /// <returns></returns> public static string ToJson(this INyxMessage msg) { return(JsonConvert.SerializeObject(msg)); }
public static string ToDefault(this INyxMessage msg) { return(msg.ToJson()); }