6

I'm still learning a lot about how FBP and NoFlo works from a process perspective, so while I can hack something together that does the job, I'm unsure whether I'm introduce problems somewhere else.

In this case, I'm creating a component that waits for an input on each of its 2 ports before sending data to the out port. Why? I need data from both inputs to construct the output packet (group name and input packet).

I've managed to achieve this using 2 approaches and I'd like to know which approach is better, or at least the up/downsides to each approach.

The component I'm talking about here is vizicities/Group:

enter image description here

Approach 1: Queuing packets from input1 internally until the input2 has received a packet

var noflo = require("noflo");

exports.getComponent = function() {
  var AddGroup = new noflo.Component();
  AddGroup.description = "This component adds a group to the data packets";

  var packets = [];
  var groupName = "";

  // Register ports and event handlers
  AddGroup.inPorts.add("in", { datatype: "all" }, function(event, payload) {
    switch (event) {
      case "begingroup":
        AddGroup.outPorts.out.beginGroup(payload);
        break;
      case "endgroup":
        AddGroup.outPorts.out.endGroup();
        break;
      case "data":
        // Queue packet
        packets.push(payload);
        break;
      case "disconnect":
        // Only send output if group has been set
        if (groupName) {
          for (var i = 0; i < packets.length; i++) {
            AddGroup.outPorts.out.beginGroup(groupName);
            AddGroup.outPorts.out.send(packets);
            AddGroup.outPorts.out.endGroup();
          }

          // Disconnect output port when input port disconnects
          AddGroup.outPorts.out.disconnect();
        }
        break;
    }
  });

  AddGroup.inPorts.add("group", { datatype: "string" }, function(event, payload) {
    switch (event) {
      case "begingroup":
        break;
      case "endgroup":
        break;
      case "data":
        groupName = payload;
        break;
      case "disconnect":
        // TODO: Does this dupe anything with the same logic on the in port?
        // Only send output if group has been set
        if (groupName) {
          for (var i = 0; i < packets.length; i++) {
            AddGroup.outPorts.out.beginGroup(groupName);
            AddGroup.outPorts.out.send(packets);
            AddGroup.outPorts.out.endGroup();
          }

          // Disconnect output port when input port disconnects
          AddGroup.outPorts.out.disconnect();
        }
        break;
    }
  });

  AddGroup.outPorts.add("out", { datatype: "all" });

  return AddGroup; // Return new instance
};

Approach 2: Using the WirePattern helper

var noflo = require("noflo");

exports.getComponent = function() {
  var AddGroup = new noflo.Component();
  AddGroup.description = "This component adds a group to the data packets";

  var config = {
    in: ["in", "group"],
    out: "out"
  };

  AddGroup.inPorts = new noflo.InPorts({
    in: {
      datatype: "string",
      required: true
    },
    group: {
      datatype: "string",
      required: true
    }
  });

  AddGroup.outPorts = new noflo.OutPorts({
    out: {
      datatype: "all"
    }
  });

  noflo.helpers.WirePattern(AddGroup, config, function(data, groups, outPort) {
    outPort.beginGroup(data.group);
    outPort.send(data.in);
    outPort.endGroup();
  });

  // Return new instance
  return AddGroup;
};

Both approaches seem to work, though clearly there must be a reason for using one over the other. Can someone clarify this for me?

Robin Hawkes
  • 688
  • 8
  • 24

1 Answers1

3

WirePattern is the recommended way in modern NoFlo, as it provides you with additional control on packet synchronization when needed. You can fire when all the required inputs get data, or you can require a strict group (or even packet payload) matches.

A lot of common NoFlo components are still waiting for WirePattern-ization, but for anything new, and even more so for anything asynchronous it is the recommended way.

bergie
  • 930
  • 7
  • 8
  • Thanks Henri, that clears things up! The WirePattern version is much cleaner too so I preferred that approach. I'm currently understanding the difference between in-ports and params but it's all working at least. – Robin Hawkes Jan 28 '15 at 13:11
  • Parameter ports are used for configuring a component. If you set them to `required`, they need to be provided once before your WirePattern will fire, but after that the values are retained in `c.params.`. Optional parameter ports don't block WirePattern execution, and so may or may not have values depending how your graph is built. – bergie Jan 28 '15 at 21:09